文章目录
前言
接到一个需求,设计整体实现pc端 OA系统上下班面部识别打卡的功能,智能识别面部肯定是后端进行对比是不是本人,前端需要实现拉取摄像头,进行拍照,并保存照片,传给后端,进行智能分析,返回参数
window.navigator
JavaScript Window Navigator是JavaScript中一个常用的浏览器对象模型,它提供了许多属性和方法,用于访问用户浏览器的信息。
window.navigator 对象在编写时可不使用 window 这个前缀
- Navigator属性
<div id="example"></div><script>// appCodeName 该属性返回浏览器的代码名称。在大多数浏览器中,它的值都是“Mozilla”,因为它们使用了Mozilla浏览器的代码。 txt ="<p>浏览器代号: "+ navigator.appCodeName +"</p>";// 该属性返回浏览器的名称。它的值可能是"Microsoft Internet Explorer"、"Netscape"、"Chrome"等。 txt+="<p>浏览器名称: "+ navigator.appName +"</p>";// 该属性返回浏览器的版本信息。 txt+="<p>浏览器版本: "+ navigator.appVersion +"</p>";// language 属性返回浏览器语言: txt+="<p>浏览器语言: "+ navigator.language +"</p>";// onLine 属性返回 true,假如浏览器在线: txt+="<p>浏览器是否在线: "+ navigator.onLine +"</p>";// 该属性返回一个布尔值,表示浏览器是否启用cookie。 txt+="<p>启用Cookies: "+ navigator.cookieEnabled +"</p>";// 该属性返回运行浏览器的操作系统平台,例如Windows、Mac OS X、Linux等。 txt+="<p>硬件平台: "+ navigator.platform +"</p>";// 该属性返回包含浏览器版本和操作系统信息的用户代理字符串。 txt+="<p>用户代理: "+ navigator.userAgent +"</p>"; txt+="<p>用户代理语言: "+ navigator.systemLanguage +"</p>"; document.getElementById("example").innerHTML=txt;</script>
- Navigator 对象方法 > javaEnabled返回一个布尔值,该值指示浏览器是否支持并启用了 Java。如果是,则返回 true,否则返回 false。
- 实际运用 a)浏览器版本检测 > 在开发网站时,我们需要确保网站能够在各种浏览器上正确地运行。由于不同的浏览器版本在处理JavaScript代码方面存在差异,因此我们需要能够检测浏览器版本并根据浏览器版本来编写JavaScript代码。可以使用Navigator对象中的属性来检测浏览器版本,例如 userAgent 属性和 appVersion 属性。
if(navigator.userAgent.indexOf("MSIE")!=-1){// 如果是IE浏览器,执行相应的操作}elseif(navigator.userAgent.indexOf("Firefox")!=-1){// 如果是Firefox浏览器,执行相应的操作}elseif(navigator.userAgent.indexOf("Chrome")!=-1){// 如果是Chrome浏览器,执行相应的操作}elseif(navigator.userAgent.indexOf("Opera")!=-1){// 如果是Opera浏览器,执行相应的操作}elseif(navigator.userAgent.indexOf("Safari")!=-1){// 如果是Safari浏览器,执行相应的操作}
b)浏览器版本检测 > 在编写JavaScript代码时,我们可能需要使用一些浏览器特定的API。但是不同的浏览器支持的API可能不同,因此我们需要进行浏览器能力检测,以确保我们的代码能够在各种浏览器上正确地运行。可以使用Navigator对象中的属性来检测浏览器的能力,例如 cookieEnabled 属性和 geolocation 属性。if(navigator.cookieEnabled){// 如果浏览器支持cookie,执行相应的操作}if("geolocation" in navigator){// 如果浏览器支持地理位置信息,执行相应的操作}
c)获取浏览器位置信息 > Navigator对象中的geolocation属性可以获取用户的地理位置信息,这在实现一些地理位置相关的功能时非常有用。以下是一个获取用户位置信息的示例:// 注在谷歌浏览器会被拦截会报错延迟 index.html:42 Error code: 3; message: Timeout expired// 代码在edge浏览器中执行navigator.geolocation.getCurrentPosition(function(position){ var latitude = position.coords.latitude; var longitude = position.coords.longitude;// 根据经纬度显示用户当前位置 console.log(latitude)// 39.135874 console.log(longitude)// 117.18322},function(error){ console.error("Error code: "+ error.code +"; message: "+ error.message);},{ timeout:1000,// 超时时间为10秒 maximumAge:60000,// 最大缓存时间为1分钟 enableHighAccuracy: true // 开启高精度模式});
navigator.mediaDevices
接口提供访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等。它可以使你取得任何硬件资源的媒体数据。
let camera = window.navigator.mediaDevices;
console.log(camera,'cameracameracameracamera');
navigator.mediaDevices 详细的使用方法以及API可以去看官方文档
window.navigator.mediaDevices.getUserMedia() 打开系统上的相机或屏幕共享和/或麦克风。会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器等等),也可能是其他轨道类型。
获取摄像头
navigator.mediaDevices.getUserMedia()官方文档
- 先判断当前浏览器是否有摄像设备并给与权限,我们先调取 enumerateDevices 函数来查看当前媒体设备是否存在。它的返回值是一个 promise 类型,我们直接用 async 和 await 来简化一下
let camera = window.navigator.mediaDevices;let devices = await camera.enumerateDevices();console.log(devices,'devices');
从上图可以看出,我的电脑有6个音频设备和一个视频设备,那么我们就可以放下进行下一步了。 - 设置视频图像显示的位置
<div id="camera"><video ref="videoEL"></video></div>
- 获取视频流并在相应的位置展示并播放
let cameraMedia = window.navigator.mediaDevices; let devices = await cameraMedia.enumerateDevices();if(!!devices){ let camera = await cameraMedia.getUserMedia({ audio: false,// 不需要音频 video:{ width:300, height:300,// facingMode: { exact: 'environment' },// 设置后置摄像头 pc端不需要设置// facingMode: { exact: 'uder' }, // 设置前置摄像头},});if(!videoEL.value)return; videoEL.value.srcObject = camera; videoEL.value.play();}
截取当前画面(canvas)
- 打开 Performance 标签卡,记录一下打开掘金首页的过程,可以看到浏览器的整个渲染过程其实也是一帧一帧拼接到一起,才完成了整个页面的渲染。
- 当我按下按钮的时候,想办法将 video 标签当前的画面保存下来。需要用canvas
- 首先创建一个空白的 canvas 元素,元素的宽高设置为和 video 标签一致。
- canvas 的 getContext 方法,接受一个字符串 “2d” 作为参数,它会把这个画布的上下文返回
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);// 将 canvas 投到页面上
源码
项目是基于 Vue-Vben-Admin搭建的
<template><BasicModal
v-bind="$attrs"
@register="registerModel":title="拍照":maskClosable="false"
@ok="handleSubmit":keyboard="true"><div id="camera"><div ref="wrapper"><video ref="videoEL"></video><!--<a-button type="primary" @click="handlShoot">拍照</a-button>--></div></div></BasicModal></template><script lang="ts">
import { defineComponent, ref, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage';
import { ActionEnum, VALIDATE_API } from '/@/enums/commonEnum';
export defaultdefineComponent({
name:'编辑积分商品',
components:{ BasicModal, BasicForm },
emits:['success','register'],setup(_,{ emit }){const{ t }=useI18n();const type = ref<ActionEnum>(ActionEnum.ADD);const{ createMessage }=useMessage();
let videoEL = ref<HTMLVideoElement>();const wrapper = ref<HTMLDivElement>();const[registerModel,{ setModalProps: setProps, closeModal: close }]=useModalInner(async(data)=>{setProps({ confirmLoading: false });
type.value = data?.type || ActionEnum.ADD;handleCamera();});
async function handleCamera(){
let cameraMedia = window.navigator.mediaDevices;
let devices = await cameraMedia.enumerateDevices();if(!!devices){
let camera = await cameraMedia.getUserMedia({
audio: false,// 不需要音频
video:{
width:300,
height:300,// facingMode: { exact: 'environment' },// 设置后置摄像头 pc端不需要设置// facingMode: { exact: 'uder' }, // 设置前置摄像头},});if(!videoEL.value)return;
videoEL.value.srcObject = camera;
videoEL.value.play();}}
async function handleSubmit(){
try {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);} finally {setProps({ confirmLoading: false });}}return{ type, videoEL, wrapper, t, registerModel, handleSubmit };},});</script>
小结
实现拍照的整体思路其实很简单,仅仅需要了解到视频其实也是一帧一帧画面构成的,而 canvas 恰好有捕捉当前帧的能力。
版权归原作者 程楠楠&M 所有, 如有侵权,请联系我们删除。