本文详细讲解如何使用原生JavaScript调用设备摄像头并实现拍照功能。通过navigator.mediaDevices获取媒体权限,将视频流绑定至video元素实时显示,并利用Canvas的drawImage方法截取当前画面生成图片。文章提供了完整代码示例及HTTPS协议等关键注意事项,帮助开发者灵活实现自定义拍照组件。
1. 需求分析
本文将探讨一个实用且有趣的技术话题:如何利用原生JavaScript实现拍照功能。
部分开发者可能会质疑:既然有现成的解决方案,为何还要耗费精力使用原生JS?直接使用第三方库不是更高效吗?
确实,使用第三方库能显著提升开发效率。因此,在实际项目中,我们通常会优先考虑成熟的第三方JS摄像库,例如CameraJS、WebcamJS或getUserMediaJS等,以快速实现拍照需求。
然而,了解其底层实现原理同样重要。掌握原生JS实现方式不仅能提升代码灵活性,还可能在未来特定场景下发挥关键作用。
接下来,我们将深入解析其实现原理,过程其实并不复杂。

首先明确,在哪些项目场景中会用到拍照功能?
回答:拍照功能广泛应用于多种项目类型,以下是常见的需求场景:
社交媒体应用:社交媒体平台通常要求用户拍摄照片并上传,用于分享生活、发布动态或更新个人头像。电子商务应用:在电商应用中,商家或用户可利用拍照功能拍摄商品图片,上传至商品详情页或用于售后凭证提交。扫描和识别:该功能可用于文档、二维码、条形码或身份证的扫描与识别。例如,通过拍照自动提取身份证信息,简化录入流程。相机应用和照片编辑:专业相机应用依赖拍照功能捕捉图像,并结合滤镜、裁剪、旋转等编辑工具提供丰富的图像处理体验。实时图像处理:结合图像处理算法,拍照功能可实现实时滤镜效果、人脸识别及美颜处理等高级功能。身份验证和安全:部分应用利用拍照进行身份验证或安全认证,如通过拍摄面部照片进行人脸识别登录或解锁设备。文档管理和归档:在文档管理中,拍照可将纸质文件转化为电子格式,便于保存、检索和分类归档。
2. 功能实现
明确需求后,我们开始原生JS实现拍照功能,整个过程分为3步进行。文末提供了完整代码及关键注意事项供参考。
2.1 获取媒体设备访问权限
首先检查设备是否具备媒体设备,可通过调用 navigator.mediaDevices.
enumerateDevices() 方法。
const navigator = window.navigator.mediaDevices;
const devices = await navigator.enumerateDevices();
if (devices) { ... }
接着使用 navigator.mediaDevices.getUserMedia() 方法请求用户授权,允许访问摄像头和麦克风。该接口将返回一个包含音视频数据的媒体流对象。
const stream = await navigator.getUserMedia({
audio: false, // 不需要音频
video: {
width: 300,
height: 300,
// facingMode: { exact: "environment" }, //强制后置摄像头
facingMode: "user", //前置摄像头
},
});


2.2 显示视频流
将获取到的媒体流绑定至HTML中的 <video> 元素,即可在页面上实时显示摄像头捕捉的画面。
if (!videoRef.value) return;
videoRef.value.srcObject = stream;
videoRef.value.play();

2.3 拍照截图
通过捕获 <video> 元素的当前帧画面,即可实现拍照。具体做法是使用 <canvas> 元素的drawImage()方法绘制视频画面,并将其转换为图像数据。
// 设置canvas画布
const canvas = document.createElement("canvas");
canvas.width = videoRef.value.videoWidth;
canvas.height = videoRef.value.videoHeight;
// 获取canvas上下文对象
const ctx = canvas.getContext("2d");
// 截图操作
ctx?.drawImage(videoRef.value, 0, 0, canvas.width, canvas.height);
最后,根据项目具体需求,将获取到的图像数据用于后续的操作,例如在页面显示或上传至服务器存储。
2.4 全部代码
以下是拍照功能实现的全部代码,每行代码均已添加详细注释,复制后可直接运行:
<template>
<div ref="wrapperRefRef">
<video ref="videoRef" />
<el-button type="primary" @click="handleShoot">拍摄</el-button>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
const wrapperRef = ref();
const videoRef = ref();
// 检验设备
const checkCamera = async () => {
// 先检验当前设备是否有摄像设备
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", //前置摄像头
},
});
console.log(stream);
// 用video元素渲染流数据
if (!videoRef.value) return;
videoRef.value.srcObject = stream;
videoRef.value.play();
}
}
// 点击拍照
const handleShoot = () => {
if (!videoRef.value || !wrapperRef.value) return;
// 设置canvas画布
const canvas = document.createElement("canvas");
canvas.width = videoRef.value.videoWidth;
canvas.height = videoRef.value.videoHeight;
// 获取canvas上下文对象
const ctx = canvas.getContext("2d");
// 截图操作
ctx?.drawImage(videoRef.value, 0, 0, canvas.width, canvas.height);
// 展示截图
wrapperRef.value.appendChild(canvas);
}
onMounted(() => {
checkCamera();
});
</script>
2.5 一些注意事项
window.navigator.mediaDevices 中的 mediaDevices 属性用于标识浏览器是否支持媒体设备访问,如摄像头和麦克风。
在某些设备上,该属性可能正常存在,而在其他设备上不存在。
这通常取决于多个因素,包括浏览器的支持程度、用户权限设置以及网页的协议环境。若发现某设备中该属性缺失,可能是上述因素之一导致。
在测试Demo时,我曾遇到网页通过非HTTPS协议分享的情况,导致浏览器限制媒体访问权限,排查耗时较长。
希望读者能避免此类问题,节省调试时间。
结语
以上为使用原生JS实现拍照功能的完整教程,如需了解更多JS相关技术,请关注本站其他文章。