这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
1. 背景
一般业务也很少接触摄像头,有也是现成的工具库扫个二维码。难得用一次,记录下踩坑。
2.调用摄像头的方法
2.1. input
- <input type="file" accept="image/*" capture="camera">
- <input type="file" accept="video/*" capture="camcorder">
- <input type="file" accept="audio/*" capture="microphone">
这个就不用多说了,缺点就是没办法自定义界面,它是调用的系统原生相机界面。
2.2. mediaDevices
由于我需要自定义界面,就像下面这样:

所以我选择了这个方案,这个api使用起来其实很简单:
- <!-- 创建一个video标签用来播放摄像头的视屏流 -->
- <video id="video" autoplay="autoplay" muted width="200px" height="200px"></video>
- <button onclick="getMedia()">开启摄像头</button>
- async getMedia() {
- // 获取设备媒体的设置,通常就video和audio
- const constraints = {
- // video配置,具体配置可以看看mdn
- video: {
- height: 200,
- wdith: 200,
- },
- // 关闭音频
- audio: false
- };
- this.video = document.getElementById("video");
- // 使用getUserMedia获取媒体流
- // 媒体流赋值给srcObject
- this.video.srcObject = await window.navigator.mediaDevices.getUserMedia(constraints);
- // 直接播放就行了
- this.video.play();
- }

可以看到这个效果。
- // 截图拍照
- takePhoto() {
- const video = document.getElementById("video");
- // 借助canvas绘制视频的一帧
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext('2d');
- ctx.drawImage(this.video, 0, 0, 300, 300);
- },
- // 停止
- stopMedia() {
- // 获取媒体流
- const stream = this.video.srcObject;
- const tracks = stream.getTracks();
- // 停止所有轨道
- tracks.forEach(function (track) {
- track.stop();
- })
- this.video.srcObject = null;
- }
3.坑
如果你复制我的代码,在localhost上肯定能运行,但是你想在手机上试试的时候就会发现很多问题。
3.1. 需要https
由于浏览器的安全设置,除了localhost和https连接,你都没办法获取到navigator.mediaDevices,打印出来是undefined。如果要在手机上测试,你要么用内网穿透代理一个https,要么部署在https域名的服务器上测试。
3.2. 设置前后摄像头
默认是使用user设备,也就是前摄像头,想要使用后摄像头也是有配置的,
- async getMedia() {
- // ...
- let constraints = {
- video: {
- height: 200,
- wdith: 200,
- // environment设备就是后置
- facingMode: { exact: "environment" },
- },
- audio: false
- };
- // ...
- }
3.3. 设置显示区域大小
我的需求是铺满整个设备,所以我想当然的直接把video样式宽高设置成容器大小:
- #video {
- width: 100%;
- height: 100%;
- }
-
-
- async getMedia() {
- // ....
- // 将宽高设置成容器大小
- const pageSize = document.querySelector('.page').getBoundingClientRect()
- let constraints = {
- video: {
- height: pageSize.height,
- width: pageSize.width,
- facingMode: { exact: "environment" },
- },
- audio: false
- };
- //....
- }

发现这个视频横着而且没有铺满屏幕。
通过输出video的信息可以看到,设备返回的视频流宽高是反的:

所以配置换一下就行了:
- let constraints = {
- video: {
- height: pageSize.width,
- width: pageSize.height,
- },
- };

