vue使用navigator.mediaDevices.getUserMedia调用相机功能

简介: vue使用navigator.mediaDevices.getUserMedia调用相机功能



 

前言:

本文将介绍Vue中如何使用navigator.mediaDevices.getUserMedia调用相机功能,实现拍照使用实例,需要的朋友可以参考一下。

注意:

Vue 调用本地摄像头实现拍照功能,由于调用摄像头有使用权限,只能在本地运行,线上需用 https 域名才可以使用。


API:

Navigator.mediaDevices.getUserMedia()是一种用于访问流媒体设备(如摄像机或麦克风)的API,它是Navigator.mediaDevices API的一部分。它允许网页访问摄像头和/或麦克风,并捕获实时流视频/音频。

此API采用异步方式,通过返回一个Promise来提供访问流媒体设备的权限。如果用户允许,API将返回一个MediaStream对象,该对象可以进一步用于捕获视频和音频。

具体使用方法:MediaDevices.getUserMedia() - Web API 接口参考 | MDN (mozilla.org)


API简单示例:

以下是一个使用Vue.js调用相机功能的示例:

<template>
  <div>
    <video ref="video" autoplay></video>
    <button @click="startCamera">启动相机</button>
    <button @click="stopCamera">关闭相机</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      cameraStream: null,
    };
  },
  methods: {
    async startCamera() {
      try {
        const stream = await navigator.mediaDevices.getUserMedia({
          audio: false,
          video: true,
        });
        this.cameraStream = stream;
        this.$refs.video.srcObject = stream;
      } catch (error) {
        console.error(error);
      }
    },
    stopCamera() {
      if (this.cameraStream) {
        this.cameraStream.getTracks()[0].stop();
        this.cameraStream = null;
      }
    },
  },
};
</script>

在上面的代码中,我们首先在模板中添加一个视频元素,该元素被引用为“video”。我们还添加了两个按钮来启动和关闭相机。

在数据属性中,我们定义了一个名为cameraStream的变量,用于存储从相机捕获的视频流。

在startCamera方法中,我们首先使用await关键字调用navigator.mediaDevices.getUserMedia()方法,传递一个选项对象,其中audio属性设置为false,因为我们不需要捕获音频,video属性设置为true,因为我们需要捕获视频。

如果用户允许访问相机,方法将返回一个MediaStream对象,我们将其存储在cameraStream变量中并将其作为“video”元素的源对象。

在stopCamera方法中,我们首先检查cameraStream是否存在,如果存在,则使用getTracks()[0].stop()方法停止从相机捕获的视频流,并将cameraStream设置为null。


拍照功能

完整示例:

<template>
  <div id="body">
    <div class="body">
      <div class="camera">
        <video ref="video"></video>
        <canvas
          style="display: none"
          id="canvasCamera"
          ref="canvasDom"
        ></canvas>
      </div>
      <div class="img_body">
        <div class="img_content">
          <div class="image" v-for="(item, index) in image" :key="index">
            <img :src="item" alt="" />
          </div>
        </div>
      </div>
      <div>
        <button @click="open">打开相机</button>
        <button @click="takePhoto">拍照</button>
        <button @click="CloseCamera">关闭相机</button>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
const video = ref(null);
const canvasDom = ref(null);
const router = useRouter();
const mediaStreamTrack = ref({});
const video_stream = ref("");
const imgSrc = ref("");
const image = ref([]);
const front = ref(true);
onMounted(() => {
  getCamera();
});
// 打开相机
const open = () => {
  getCamera();
};
const getCamera = () => {
  if (navigator.mediaDevices) {
    navigator.mediaDevices
      .getUserMedia({ video: true })
      .then((stream) => {
        // 摄像头开启成功
        video.value.srcObject = stream;
        video.value.play();
      })
      .catch((err) => {
        console.log(err);
      });
  }
};
// 拍照 绘制图片
const takePhoto = () => {
  // 设置画布大小与摄像大小一致
  canvasDom.value.width = video.value.videoWidth;
  canvasDom.value.height = video.value.videoHeight;
  // 执行画的操作
  canvasDom.value.getContext("2d").drawImage(video.value, 0, 0);
  // 将结果转换为可展示的格式
  imgSrc.value = canvasDom.value.toDataURL("image/webp");
  console.log(imgSrc.value);
  image.value.push(imgSrc.value);
};
// 关闭摄像头
const CloseCamera = () => {
  console.log("关闭摄像头");
  video.value.srcObject.getTracks()[0].stop();
};
</script>
<style scoped>
#body {
  width: 100%;
  display: flex;
  justify-content: center;
}
button {
  width: 60px;
  height: 25px;
  background-color: rgb(86, 250, 174);
  margin: 5px;
  border-radius: 5px;
}
.camera {
  margin-top: 10px;
}
.camera video {
  border-radius: 5px;
}
.img_body {
  width: 100%;
}
.img_content {
  width: 100%;
  display: flex;
}
.image {
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.image img {
  width: 80px;
  height: 80px;
  border-radius: 5px;
}
</style>

navigator.mediaDevices.getUserMedia切换手机前后摄像头:

前置摄像头:

navigator.mediaDevices
      .getUserMedia({ video: true })
      .then((stream) => {
        // 摄像头开启成功
        video.value.srcObject = stream;
        video.value.play();
      })
      .catch((err) => {
        console.log(err);
      });

后置摄像头:

navigator.mediaDevices
      .getUserMedia({
        audio: true,
        video: { facingMode: { exact: "environment" } },
      })
      .then((stream) => {
        // 摄像头开启成功
        video.value.srcObject = stream;
        video.value.play();
      })
      .catch((err) => {
        console.log(err);
      });

实现效果:

目录
相关文章
|
5天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
5天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
5天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
5天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
4天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
6天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
4天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
6天前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
11天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发
|
11天前
|
存储 JavaScript
Vue 状态管理工具vuex
Vue 状态管理工具vuex