vue3开启摄像头并进行拍照

2024-01-08 11:32:12

一、前言

Vue3 调用本地摄像头实现拍照功能,由于调用摄像头有使用权限,只能在本地运行,线上需用 https 域名才可以使用。主要是使用navigator.mediaDevices.getUserMedia这个API来实现。

二、文档

navigator.mediaDevices.getUserMediaMDN的官方文档点击【前往】。

向用户请求获得媒体输入的许可,返回一个MediaStream,我们可以使用MediaStreamvideo组件绑定输出摄像头拍摄的视频,也能记录麦克风的音频

三、实现

3.1、封装

封装组件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>

3.2、使用

/**
 * @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>

3.3、效果

四、最后

本人每篇文章都是一字一句码出来,希望对大家有所帮助,多提提意见。顺手来个三连击,点赞👍收藏💖关注?,一起加油?

文章来源:https://blog.csdn.net/u012804440/article/details/135439353
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。