使用vue制作出来相机的功能:照相、录视频
废话不多说,直接上代码!
布局:
- <template>
- <div>
- <video ref="video" autoplay>video>
- <canvas ref="canvas" width="64" height="48">canvas>
- <div class="footer">
- <div class="font"><b>{{ content }}b>div>
- <div class="but">
- <input type="file" id="file">
- <label for="file"><img src="../assets/img.png" alt="">label>
-
- <div @touchstart="gtouchstart()" @touchmove="gtouchmove()" @touchend="showDeleteButton()" class="lick">
- <p class="li">p>
- div>
-
- <img @click='changeDevice' src="../assets/look.png" alt="">
- div>
- div>
- <div>
- <button @click="getCamera" style="margin-right: 10px;">开启摄像头button>
- <button @click="closeCamera">关闭摄像头button>
- div>
- <a id="downLoadLink" style="display: none;">a>
-
- div>
- template>
CSS样式:
- <style scoped>
- video {
- width: 100%;
- height: 60vh;
- background-color: black;
- }
-
- #file {
- display: none;
- }
-
- .font {
- width: 100%;
- text-align: center;
- font-size: 15px;
- color: #667E6E;
- margin-bottom: 20px;
- }
-
- .footer {
- width: 90%;
- height: 23vh;
- margin-left: 5%;
- position: fixed;
- bottom: 0;
- z-index: 10;
- background-color: white;
- }
-
- .but {
- display: flex;
- justify-content: space-around;
- }
-
- .lick {
- width: 70px;
- height: 70px;
- line-height: 70px;
- border-radius: 50%;
- background-color: #E6E6E6;
- /* text-align: center; */
- }
-
- .li {
- width: 30px;
- height: 30px;
- line-height: 30px;
- background-color: #B7B7B7;
- border-radius: 50%;
- margin: 20px 0 0 20px;
- }
-
- input {
- width: 50px;
- }
-
- img {
- width: 40px;
- height: 40px;
- margin-top: 15px;
- }
- style>
脚本:
- <script>
- export default {
- data() {
- return {
- videoArr: [],//所有的摄像头,也可以加入音频设备
- modelSel: '',//当前使用的摄像头
- myInterval: null,
- mediaStreamTrack: {}, // 退出时关闭摄像头
- video_stream: '', // 视频stream
- recordedBlobs: [], // 视频音频 blobs
- isRecord: false, // 视频是否正在录制
- content: '按住拍摄,点击拍照'
- }
- },
- created() {
- this.changeDevice();
- },
- mounted() {
- this.getCamera();
- },
- methods: {
- getCamera() {
- // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
- if (navigator.mediaDevices === undefined) {
- navigator.mediaDevices = {};
- }
- navigator.mediaDevices
- .getUserMedia({
- video: true,
- })
- .then((stream) => {
- // 摄像头开启成功
- this.mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[0];
- this.video_stream = stream;
- this.$refs.video.srcObject = stream;
- this.$refs.video.play();
- })
- .catch(err => {
- console.log(err);
- });
- },
- //长按事件(起始) 返回按钮--------------------------------------------------------------------------------------------
- gtouchstart() {
- var self = this;
- this.timeOutEvent = setTimeout(function () {
- self.longPress();
- }, 500); //这里设置定时器,定义长按500毫秒触发长按事件
- return false;
- },
- //手释放,如果在500毫秒内就释放,则取消长按事件,此时可以执行onclick应该执行的事件
- showDeleteButton() {
- clearTimeout(this.timeOutEvent); //清除定时器
- if (this.timeOutEvent != 0) { //这里写要执行的内容(如onclick事件)点击未长按
- this.returns = true
- setTimeout(() => {
- this.uploadImg()
- }, 100);
- } else { //长按后松开要执行的内容
- this.returns = false
- this.stop()
- this.content = '按住拍摄,点击拍照'
- }
- return false;
- },
- //如果手指有移动,则取消所有事件,此时说明用户只是要移动而不是长按
- gtouchmove() {
- clearTimeout(this.timeOutEvent); //清除定时器
- this.timeOutEvent = 0;
- console.log("移动");
- },
- //真正长按后应该执行的内容
- longPress() { //执行长按要执行的内容,如弹出菜单
- this.timeOutEvent = 0;
- this.returns = true
- this.record();
- this.content = '视频录制中'
- console.log("长按");
- },
- // 拍照--------------------------------------------------------------------------------------------------------------------
- uploadImg() {
- let ctx = this.$refs['canvas'].getContext('2d');
- ctx.drawImage(this.$refs['video'], 0, 0, 64, 48);
- // let imgBase64 = this.$refs['canvas'].toDataURL('image/jpeg', 0.7);
- console.log(this.$refs['canvas']);
- },
- closeCamera() {
- if (!this.$refs['video'].srcObject) return;
- let stream = this.$refs['video'].srcObject;
- let tracks = stream.getTracks();
- tracks.forEach(track => {
- track.stop();
- });
- this.$refs['video'].srcObject = null;
- },
- changeDevice() {
- navigator.mediaDevices.enumerateDevices().then((devices) => {
- this.videoArr = [];
- devices.forEach((device) => {
- //音频是audioautput 摄像头videoinput
- if (device.kind == 'videoinput') {
- this.videoArr.push({
- 'label': device.label,
- 'id': device.deviceId
- })
- }
- });
- })
- },
- setCurrentDevice(val) {
- const videoConstraints = {};
- if (val === '') {
- videoConstraints.facingMode = 'environment';
- } else {
- videoConstraints.deviceId = { exact: val };
- }
- var constraints = {
- video: videoConstraints,
- };
- this.getUserMedia(constraints);
- },
- getUserMedia(constraints, success, error) {
- if (navigator.mediaDevices.getUserMedia) {
- //最新的标准API
- navigator.mediaDevices.getUserMedia(constraints).then(success => {
- // 摄像头开启成功
- this.$refs['video'].srcObject = success
- // 实时拍照效果
- this.$refs['video'].play()
- }).catch(error);
-
- } else if (navigator.webkitGetUserMedia) {
- //webkit核心浏览器
- navigator.webkitGetUserMedia(constraints, success, error)
- } else if (navigator.mozGetUserMedia) {
- //firfox浏览器
- navigator.mozGetUserMedia(constraints, success, error);
- } else if (navigator.getUserMedia) {
- //旧版API
- navigator.getUserMedia(constraints, success, error);
- }
- },
- // 视频录制----------------------------------------------------------------------------------------------------------------------
- record() {
- console.log('record');
- this.isRecord = !this.isRecord;
- let mediaRecorder;
- let options;
- this.recordedBlobs = [];
- if (typeof MediaRecorder.isTypeSupported === 'function') {
- // 根据浏览器来设置编码参数
- if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
- options = {
- MimeType: 'video/webm;codecs=h264',
- };
- } else if (MediaRecorder.isTypeSupported('video/webm;codecs=h264')) {
- options = {
- MimeType: 'video/webm;codecs=h264',
- };
- } else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
- options = {
- MimeType: 'video/webm;codecs=vp8',
- };
- }
- mediaRecorder = new MediaRecorder(this.video_stream, options);
- } else {
- // console.log('isTypeSupported is not supported, using default codecs for browser');
- console.log('当前不支持isTypeSupported,使用浏览器的默认编解码器');
- mediaRecorder = new MediaRecorder(this.video_stream);
- }
- mediaRecorder.start();
- // 视频录制监听事件
- mediaRecorder.ondataavailable = e => {
- console.log(e);
- // 录制的视频数据有效
- if (e.data && e.data.size > 0) {
- this.recordedBlobs.push(e.data);
- }
- };
- // 停止录像后增加下载视频功能,将视频流转为mp4格式
- mediaRecorder.onstop = () => {
- const blob = new Blob(this.recordedBlobs, { type: 'video/mp4' });
- this.recordedBlobs = [];
- // 将视频链接转换完可以用于在浏览器上预览的本地视频
- const videoUrl = window.URL.createObjectURL(blob);
- // 设置下载链接
- document.getElementById('downLoadLink').href = videoUrl;
- // 设置下载mp4格式视频
- document.getElementById('downLoadLink').download = 'media.mp4';
- document.getElementById('downLoadLink').innerHTML = 'DownLoad video file';
- // 生成随机数字
- const rand = Math.floor((Math.random() * 1000000));
- // 生成视频名
- const name = `video${rand}.mp4`;
-
- // setAttribute() 方法添加指定的属性,并为其赋指定的值
- document.getElementById('downLoadLink').setAttribute('download', name);
- document.getElementById('downLoadLink').setAttribute('name', name);
-
- // 0.5s后自动下载视频
- setTimeout(() => {
- document.getElementById('downLoadLink').click();
- }, 500);
- };
- },
- // 停止录制----------------------------------------------------------------------------------------------------------------------
- stop() {
- this.isRecord = !this.isRecord;
- if (!this.$refs.video.srcObject) return;
- const stream = this.$refs.video.srcObject;
- const tracks = stream.getTracks();
- // 关闭摄像头和音频
- tracks.forEach(track => {
- track.stop();
- });
- },
- }
- }
- script>