使用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> <!-- <button type="primary">拍照</button> --> <div @touchstart="gtouchstart()" @touchmove="gtouchmove()" @touchend="showDeleteButton()" class="lick"> <p class="li"></p> </div> <!-- <button style="margin-right: 10px;">切换摄像头</button> --> <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> <!-- <p>{{ content }}</p> --> </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>