废话不多说直接上代码(代码内有多行注释)
<template>
<div class="camera-box" style="width: 900px">
<el-row :gutter="20">
<el-col :span="12">
<div style="text-align: center; margin-bottom: 10px">摄像头</div>
<!-- 这里就是摄像头显示的画面 -->
<video id="video" width="400" height="300" v-show="videoState"></video>
<div class="iCenter">
<el-button type="primary" @click="videoState = !videoState">
开启摄像头
</el-button>
</div>
</el-col>
<el-col :span="12">
<div style="text-align: center; margin-bottom: 10px">拍摄效果</div>
<!-- 这里是点击拍照显示的图片画面 -->
<canvas id="canvas" width="400" height="300" style="display: block">
</canvas>
<el-button type="primary" @click="takePhone"> 拍照 </el-button>
<el-button type="primary" @click="takePhoneUpfile"> 保存 </el-button>
</el-col>
</el-row>
</div>
</template>
<script setup>
const blobFile = ref(null)
const canvas = ref(null)
const video = ref(null)
const videoState = ref(false)
const mediaStreamTrack = ref()
onMounted(() => {
// 摄像头
video.value = document.getElementById('video')
//画布
canvas.value = document.getElementById('canvas')
})
watch(videoState, (newValue, oldValue) => {
if (newValue) {
let video = document.querySelector('video')
// 兼容代码
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {}
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
var getUserMedia =
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia
if (!getUserMedia) {
return Promise.reject(
new Error('getUserMedia is not implemented in this browser')
)
}
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject)
})
}
}
let mediaOpts = {
audio: false,
video: true,
video: { facingMode: 'user' }, // 或者 "environment"
// video: { width: 1280, height: 720 }
// video: { facingMode: { exact: "environment" } }// 或者 "user"
}
navigator.mediaDevices
.getUserMedia(mediaOpts)
.then(function (stream) {
mediaStreamTrack.value = stream
video = document.querySelector('video')
if ('srcObject' in video) {
video.srcObject = stream
} else {
video.src =
(window.URL && window.URL.createObjectURL(stream)) || stream
}
video.play()
})
.catch(function (err) {
console.log(err)
})
}
})
// base64转file方式附上
const dataURLtoFile = (dataurl, filename) => {
var arr = dataurl.split(',')
var mime = arr[0].match(/:(.*?);/)[1]
var bstr = atob(arr[1])
var n = bstr.length
var u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, { type: mime })
}
const takePhone = () => {
//点击拍照截图画面
canvas.value.getContext('2d').drawImage(video.value, 0, 0, 400, 300)
let dataurl = canvas.value.toDataURL('image/jpeg')
blobFile.value = dataURLtoFile(dataurl, 'camera.jpg') // 储存响应的图片File
// tips 此时已经获取到了File类型的数据 可直接向后端传递数据
// 若需要formData类型的数据,需加上以下代码
// 创建虚拟表单保存file
let formData = new FormData()
formData.append('file', blobFile.value) //图片内容
// tips 此时已经获取到了fromData类型的数据
// console.log(formData.getAll('file'), 123) // 查看数据内容
// 剩下就是html处理
videoState.value = false // 关闭video
canvas.value.getContext('2d').clearRect(0, 0, 400, 300) //清除画布
// 关闭摄像头
mediaStreamTrack.value.getVideoTracks().forEach(function (track) {
track.stop()
})
}
// 点击保存
const takePhoneUpfile = () => {
// 发送api等等
}
</script>
问题1: getUserMedia is not implemented in this browser ( 谷歌的安全策略 )
在网页上输入下列指令:
chrome://flags/#unsafely-treat-insecure-origin-as-secure
出现如下画面:
红框1内输入访问摄像头的网址,红框2选择Enabled
问题2: DOMException: Could not start video source ( 无法启动视频源 )
tips: 若正常显示可忽略此项
给 video 配置 muted 属性 使其静音自动播放,与抖音网页版处理方式一致,代码如下:
<video id="video" width="400" height="300" v-show="videoState" muted ></video>