Vue中文社区

前端调取摄像头并实现拍照功能

前言

最近接到的一个需求十分有意思,设计整体实现了前端仿 微信扫一扫 的功能。整理了一下思路,做一个分享。

tips: 如果想要实现完整扫一扫的功能,你需要掌握一些前置知识,这次我们先讲如何实现拍照并且保存的功能。

一. window.navigator

  1. 你想调取手机的摄像头,首先你得先检验当前设备是否有摄像设备,window 身上自带了一个 navigator 属性,这个对象有一个叫做 mediaDevices 的属性是我们即将用到的。

  2. 于是我们就可以先设计一个叫做 checkCamera 的函数,用来在页面刚开始加载的时候执行。。
    Image

  3. 我们先看一下这个对象有哪些方法,你也许会看到下面的场景,会发现这个属性身上只有一个值为 null 的 ondevicechange 属性,不要怕,真正要用的方法其实在它的原型身上。 Image

  4. 让我们点开它的原型属性,注意下面这两个方法,这是我们本章节的主角。
    Image

  5. 我们到这一步只是需要判断当前设备是否有摄像头,我们先调取 enumerateDevices 函数来查看当前媒体设备是否存在。它的返回值是一个 promise 类型,我们直接用 async 和 await 来简化一下代码。 Image Image 从上图可以看出,我的电脑有两个音频设备和一个视频设备,那么我们就可以放下进行下一步了。

二. 获取摄像头

三. 截取当前画面

四. 源码

<script lang="ts" setup>import { ref, onMounted } from "vue";
const wrapper = ref<HTMLDivElement>();const videoEl = ref<HTMLVideoElement>();
async function checkCamera() { const navigator = window.navigator.mediaDevices; const devices = await navigator.enumerateDevices(); if (devices) { const stream = await navigator.getUserMedia({ audio: false, video: { width: 300, height: 300, // facingMode: { exact: "environment" }, //强制后置摄像头 facingMode: "user", //前置摄像头 }, }); if (!videoEl.value) return;
videoEl.value.srcObject = stream; videoEl.value.play(); }}
function shoot() { if (!videoEl.value || !wrapper.value) return; const canvas = document.createElement("canvas"); canvas.width = videoEl.value.videoWidth; canvas.height = videoEl.value.videoHeight; //拿到 canvas 上下文对象 const ctx = canvas.getContext("2d"); ctx?.drawImage(videoEl.value, 0, 0, canvas.width, canvas.height); wrapper.value.appendChild(canvas);}
onMounted(() => { checkCamera();});</script><template> <div ref="wrapper" class="w-full h-full bg-red flex flex-col items-center"> <video ref="videoEl" /> <div @click="shoot" class="w-100px leading-100px text-center bg-black text-30px" > 拍摄 </div> </div></template>

五. 总结

实现拍照的整体思路其实很简单,仅仅需要了解到视频其实也是一帧一帧画面构成的,而 canvas 恰好有捕捉当前帧的能力。

预告:在下一篇会讲解如何实现扫一扫的功能,需要用到插件,感兴趣的同学可以先预习一下功课。

作者:韩振方
链接:https://juejin.cn/post/7289662055183597603