使用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>