Vue3
调用本地摄像头实现拍照功能,由于调用摄像头有使用权限,只能在本地运行,线上需用 https
域名才可以使用。主要是使用navigator.mediaDevices.getUserMedia
这个API
来实现。
navigator.mediaDevices.getUserMedia
,MDN
的官方文档点击【前往】。
向用户请求获得媒体输入的许可,返回一个MediaStream
,我们可以使用MediaStream
与video
组件绑定输出摄像头拍摄的视频,也能记录麦克风的音频
封装组件take-photo.vue
/**
* @Description: 拍照
* @author 小马甲丫
* @date 2024-01-07 12:03:04
*/
<template>
<a-modal
:width="800"
:height="600"
title="读身份证"
@cancel="hideModal"
v-model:visible="visibleFlag"
>
<!-- 画笔控件 用来拍照 -->
<canvas style="display: none" ref="canvasDom"></canvas>
<!-- 播放器,用来播放拍摄的视频 -->
<video v-if="!imgurl" class="camera_video" ref="videoDom"></video>
<!-- 显示照片 -->
<img v-else :src="imgurl" />
<template #footer>
<a-space>
<a-button @click="hideModal">关闭</a-button>
<a-button type="primary" @click="takePhoto">{{ imgurl ? "重拍" : "拍照" }}</a-button>
</a-space>
</template>
</a-modal>
</template>
<script setup>
import { ref, nextTick } from "vue";
// canvas控件对象
const canvasDom = ref(null);
// video 控件对象
const videoDom = ref(null);
// 照片路径
const imgurl = ref(null);
const emits = defineEmits(['save']);
// ------------------ 显示,关闭 ------------------
// 显示
const visibleFlag = ref(false);
function showModal() {
imgurl.value = ''
visibleFlag.value = true;
openCamera();
}
// 关闭
function hideModal() {
visibleFlag.value = false;
}
const openCamera = () => {
// 检测浏览器是否支持mediaDevices
if (navigator.mediaDevices) {
navigator.mediaDevices
// 开启视频,关闭音频
.getUserMedia({audio: false, video: true})
.then((stream) => {
// 将视频流传入viedo控件
videoDom.value.srcObject = stream;
// 播放
videoDom.value.play();
})
.catch((err) => {
console.log(err);
});
} else {
window.alert("该浏览器不支持开启摄像头,请更换最新版浏览器");
}
};
// 拍照
const takePhoto = () => {
// 如果已经拍照了就重新启动摄像头
if (imgurl.value) {
imgurl.value = null;
openCamera()
return;
}
// 设置画布大小与摄像大小一致
canvasDom.value.width = videoDom.value.videoWidth;
canvasDom.value.height = videoDom.value.videoHeight;
// 执行画的操作
canvasDom.value.getContext("2d").drawImage(videoDom.value, 0, 0);
// 将结果转换为可展示的格式
imgurl.value = canvasDom.value.toDataURL("image/webp");
// 关闭摄像头
stop();
nextTick(() => {
emits('save', imgurl.value)
hideModal()
})
}
// 关闭摄像头
const stop = () => {
let stream = videoDom.value.srcObject;
if (!stream) return;
let tracks = stream.getTracks();
tracks.forEach((x) => {
x.stop();
});
};
// ----------------------- 以下是暴露的方法内容 ------------------------
defineExpose({
showModal,
hideModal
});
</script>
<style lang="less" scoped>
.camera_video {
width: 100%;
height: 100%;
border: 2px black solid;
}
</style>
/**
* @Description: 使用
* @author 小马甲丫
* @date 2023-12-20 08:07:47
*/
<template>
<div>
<img :src="photo" />
<a-button ghost type="primary" @click="readCard">拍照</a-button>
<TakePhoto ref="photoRef" @save="handlePhoto" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import TakePhoto from './take-photo.vue';
const photoRef = ref()
const photo = ref()
// 拍照
function readCard() {
photoRef.value.showModal()
}
// 拍照回调
function handlePhoto(img) {
photo.value = img
}
</script>
本人每篇文章都是一字一句码出来,希望对大家有所帮助,多提提意见。顺手来个三连击,点赞👍收藏💖关注?,一起加油?