当前位置: 首页 > news >正文

vue实现调用手机拍照、录像功能

目录

前言

准备工作

在这个示例中,我们将使用Vue.js框架来实现我们的目标。如果你还不熟悉Vue.js,推荐先学习一下Vue.js的基础知识。

接下来,我们需要创建一个基于Vue.js的项目。你可以使用Vue CLI来创建一个全新的Vue项目:# 安装Vue CLI

# 创建一个全新的Vue项目

实现拍照功能

首先,我们将实现拍照功能。我们需要一个按钮来触发这个功能,所以让我们来创建一个简单的按钮。在App.vue文件中添加以下代码:

现在我们已经有了一个按钮,我们需要在点击按钮时触发拍照功能。让我们来填写TODO的部分。

首先,我们需要判断当前设备是否支持Media Capture API。我们可以通过以下代码来检查:

接下来,我们需要请求访问设备的摄像头。我们可以使用navigator.mediaDevices.getUserMedia()方法来请求访问设备的摄像头:

getUserMedia()方法返回一个Promise对象,该对象的resolve回调函数将返回一个MediaStream对象,该对象包含来自设备摄像头的视频流。如果访问摄像头失败,则Promise对象的reject回调函数将被触发。

我们需要将视频流绑定到一个video元素上,以便用户可以预览实时视频。让我们来添加一个video元素:

接下来我们需要将MediaStream对象绑定到video元素上。我们可以使用URL.createObjectURL()方法将MediaStream对象转换为URL,然后将该URL分配给video元素的src属性:

接下来,让我们添加一个拍照按钮。在App.vue文件中添加以下代码:

在takePhoto()方法中,我们需要从video元素中捕获当前帧,并将其绘制到canvas元素中。我们可以使用canvas元素的getContext()方法来获取上下文,并将video元素的当前帧绘制到canvas中:

最后,我们可以将base64编码的字符串转换为Blob对象,并将其上传到服务器:

至此,我们已经完成了拍照功能的实现。现在,让我们来看一下效果图:

实现录像功能

接下来,我们将实现录像功能。与拍照功能相似,我们也需要一个按钮来触发录像功能。在App.vue文件中添加以下代码:

我们定义了三个方法:toggleRecording()用于切换录像状态,isSupported()用于检查当前设备是否支持Media Capture API和MediaRecorder API,startRecording()用于开始录像,stopRecording()用于停止录像。在startRecording()方法中,我们创建了一个MediaRecorder对象,并添加了dataavailable和stop事件监听器。在dataavailable事件中,我们将获取到的数据块保存到chunks数组中。在stop事件中,我们将chunks数组中的数据块转换为Blob对象,并使用URL.createObjectURL()方法将其转换为URL。最后,我们创建了一个a元素,用于下载录制的视频。

总结


前言

在当前移动互联网高速发展的时代,手机已经成为人们生活中必不可少的设备。随着手机硬件和软件的不断升级,一些原本只存在于专业设备上的功能也被慢慢地引入到手机中,比如拍照和录像功能。在这篇文章中,我将介绍如何在Vue中使用HTML5的Media Capture API实现调用手机相机和录像功能。

准备工作

首先,让我们看一下Media Capture API是什么。Media Capture API是HTML5提供的一组API,用于从设备的摄像头和麦克风中获取数据,包括拍照和录像功能。我们在使用Media Capture API之前,需要了解一些基本的Web前端技术,比如HTML、CSS和JavaScript。

在这个示例中,我们将使用Vue.js框架来实现我们的目标。如果你还不熟悉Vue.js,推荐先学习一下Vue.js的基础知识。

接下来,我们需要创建一个基于Vue.js的项目。你可以使用Vue CLI来创建一个全新的Vue项目:
# 安装Vue CLI

npm install -g @vue/cli

# 创建一个全新的Vue项目

vue create my-project

这将创建一个全新的Vue项目,并安装所有必要的依赖项。

实现拍照功能

首先,我们将实现拍照功能。我们需要一个按钮来触发这个功能,所以让我们来创建一个简单的按钮。在App.vue文件中添加以下代码:

<template><div><button @click="takePhoto">Take Photo</button></div>
</template><script>
export default {methods: {takePhoto() {// TODO}}
}
</script>

现在我们已经有了一个按钮,我们需要在点击按钮时触发拍照功能。让我们来填写TODO的部分。

首先,我们需要判断当前设备是否支持Media Capture API。我们可以通过以下代码来检查:

if (!("mediaDevices" in navigator) || !("getUserMedia" in navigator.mediaDevices)) {alert("Media Capture API is not supported");return;
}

如果不支持Media Capture API,则会弹出一个警告框,并退出函数。

接下来,我们需要请求访问设备的摄像头。我们可以使用navigator.mediaDevices.getUserMedia()方法来请求访问设备的摄像头:

navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {// TODO}).catch(error => {alert(`Failed to access camera: ${error}`);});

getUserMedia()方法返回一个Promise对象,该对象的resolve回调函数将返回一个MediaStream对象,该对象包含来自设备摄像头的视频流。如果访问摄像头失败,则Promise对象的reject回调函数将被触发。

我们需要将视频流绑定到一个video元素上,以便用户可以预览实时视频。让我们来添加一个video元素:

<template><div><button @click="takePhoto">Take Photo</button><video ref="video" autoplay></video></div>
</template>

接下来我们需要将MediaStream对象绑定到video元素上。我们可以使用URL.createObjectURL()方法将MediaStream对象转换为URL,然后将该URL分配给video元素的src属性:

this.$refs.video.src = URL.createObjectURL(stream);

现在,如果一切都正确,应该可以在video元素中看到来自设备摄像头的实时视频流了。

接下来,让我们添加一个拍照按钮。在App.vue文件中添加以下代码:

<template><div><button @click="takePhoto">Take Photo</button><video ref="video" autoplay></video><canvas ref="canvas" style="display: none;"></canvas></div>
</template>

我们添加了一个canvas元素,用于在其中绘制当前视频帧。由于我们不需要在屏幕上显示canvas元素,所以将其样式设置为"display: none;"。

在takePhoto()方法中,我们需要从video元素中捕获当前帧,并将其绘制到canvas元素中。我们可以使用canvas元素的getContext()方法来获取上下文,并将video元素的当前帧绘制到canvas中:

const video = this.$refs.video;
const canvas = this.$refs.canvas;
const context = canvas.getContext("2d");canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
context.drawImage(video, 0, 0, canvas.width, canvas.height);

现在,我们已经将当前视频帧绘制到了canvas中。我们可以使用canvas元素的toDataURL()方法将canvas中的数据转换为base64编码的字符串:

const dataUrl = canvas.toDataURL("image/png");

最后,我们可以将base64编码的字符串转换为Blob对象,并将其上传到服务器:

fetch("/api/upload", {method: "POST",body: dataUrlToBlob(dataUrl)
}).then(() => {alert("Photo uploaded successfully!");
}).catch(error => {alert(`Failed to upload photo: ${error}`);
});

如何将base64编码的字符串转换为Blob对象?我们可以使用以下函数:

function dataUrlToBlob(dataUrl) {const [header, data] = dataUrl.split(",");const [, type] = header.match(/^data:(.*?);base64$/);const decodedData = atob(data);const buffer = new ArrayBuffer(decodedData.length);const view = new Uint8Array(buffer);for (let i = 0; i < decodedData.length; i++) {view[i] = decodedData.charCodeAt(i);}return new Blob([view], { type });
}

这个函数将base64编码的字符串拆分为数据头和数据体,然后将数据体解码为原始数据。接着,将原始数据写入一个ArrayBuffer中,最后通过Blob构造函数将ArrayBuffer转换为Blob对象。

至此,我们已经完成了拍照功能的实现。现在,让我们来看一下效果图:

![拍照功能效果图](https://i.imgur.com/dpPqAuL.png)

实现录像功能

接下来,我们将实现录像功能。与拍照功能相似,我们也需要一个按钮来触发录像功能。在App.vue文件中添加以下代码:

<template><div><button @click="toggleRecording">{{ recording ? "Stop" : "Start" }} Recording</button><video ref="video" autoplay></video></div>
</template><script>
export default {data() {return {recording: false,mediaRecorder: null,chunks: []};},methods: {toggleRecording() {if (!this.isSupported()) {alert("Media Capture API is not supported");return;}if (this.recording) {this.stopRecording();} else {this.startRecording();}},isSupported() {return "mediaDevices" in navigator && "getUserMedia" in navigator.mediaDevices && "MediaRecorder" in window;},startRecording() {const video = this.$refs.video;this.mediaRecorder = new MediaRecorder(video.srcObject);this.mediaRecorder.addEventListener("dataavailable", event => {this.chunks.push(event.data);});this.mediaRecorder.addEventListener("stop", () => {const blob = new Blob(this.chunks, { type: "video/webm" });const url = URL.createObjectURL(blob);const link = document.createElement("a");link.href = url;link.download = "video.webm";link.click();URL.revokeObjectURL(url);this.recording = false;this.chunks = [];});this.mediaRecorder.start();this.recording = true;},stopRecording() {this.mediaRecorder.stop();}}
}
</script>

在这个示例中,我们使用了一个data()函数来定义Vue的状态,包括录像状态、MediaRecorder对象和数据块等。我们添加了一个按钮,用于启动和停止录像,并使用了一个video元素,用于预览实时视频。

我们定义了三个方法:toggleRecording()用于切换录像状态,isSupported()用于检查当前设备是否支持Media Capture API和MediaRecorder API,startRecording()用于开始录像,stopRecording()用于停止录像。在startRecording()方法中,我们创建了一个MediaRecorder对象,并添加了dataavailable和stop事件监听器。在dataavailable事件中,我们将获取到的数据块保存到chunks数组中。在stop事件中,我们将chunks数组中的数据块转换为Blob对象,并使用URL.createObjectURL()方法将其转换为URL。最后,我们创建了一个a元素,用于下载录制的视频。

我们还需要在模板中添加样式来隐藏video元素:

<style>
video {display: none;
}
</style>

至此,我们已经完成了录像功能的实现。现在,让我们来看一下效果图:

![录像功能效果图](https://i.imgur.com/PcYYnDs.png)

总结

在本文中,我们介绍了如何在Vue中使用HTML5的Media Capture API实现调用手机相机和录像功能。我们实现了拍照和录像功能,并对两个功能进行了详细的讲解。需要注意的是,Media Capture API并不是所有浏览器都支持的,所以在使用Media Capture API时,需要进行兼容性检查。

相关文章:

vue实现调用手机拍照、录像功能

目录 前言 准备工作 在这个示例中&#xff0c;我们将使用Vue.js框架来实现我们的目标。如果你还不熟悉Vue.js&#xff0c;推荐先学习一下Vue.js的基础知识。 接下来&#xff0c;我们需要创建一个基于Vue.js的项目。你可以使用Vue CLI来创建一个全新的Vue项目&#xff1a;# 安…...

WPF播放视频

在WPF中&#xff0c;你可以使用MediaElement来播放本地视频。下面是一个简单的例子&#xff1a; <Window x:Class"WPFVideoPlayer.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsof…...

交换机如何配置BGP协议

环境&#xff1a; 华为交换机 华三交换机 问题描述&#xff1a; 交换机如何配置BGP协议 解决方案&#xff1a; 华三交换机上配置案例 1.配置BGP协议&#xff0c;可以按照以下步骤进行&#xff1a; 登录交换机&#xff1a;使用SSH、Telnet或控制台等方式登录到华三交换…...

精通Nginx(14)-配置HTTPS

HTTPS是在 HTTP 协议的基础上使用 TLS/SSL 加密,其主要目标是提高数据传输的安全性。从HTTP2.0开始,HTTPS已经是网站的标准协议,很多开放平台非HTTPS不能访问。Nginx为HTTPS提供了强大的支持,且对应用服务器是完全透明的。 目录 SSL/TLS基础 发展历史 TLS握手过程 加密…...

封装一个简单的table组件

子组件 <template> <el-table :data"tableData" :headers"tableHeaders" style"width: 100%"> <el-table-column v-for"header in tableHeaders" :key"header.prop" :label"header.label" :pro…...

Avalonia UI框架介绍

Avalonia UI是一个跨平台的UI框架&#xff0c;它允许开发者使用XAML和C#语言创建可在多个平台上运行的应用程序&#xff0c;包括Windows、Linux、macOS等。Avalonia UI与WPF非常相似&#xff0c;但是它是开源的&#xff0c;并且更加灵活。 下面是一个简单的Avalonia UI应用程序…...

【入门篇】1.3 redis客户端之 jedis 高级使用示例

文章目录 0.前言1. 发布和订阅消息2. 事务操作3. 管道操作4. jedis 支持哨兵模式5. jedis 支持集群模式5. 参考链接 0.前言 Jedis是Redis的Java客户端&#xff0c;它支持所有的Redis原生命令&#xff0c;使用方便&#xff0c;且可以与Java项目无缝集成。 该库的最新版本支持Re…...

使用CXF调用WSDL(二)

简介 本篇文章主要解决了上篇文章中遗留的对象嵌套问题&#xff0c;要想全面解析无限极的对象嵌套需要使用递归去解决 上文链接&#xff1a; 使用CXF调用WSDL&#xff08;一&#xff09; 上文回顾 上文使用了单方法“ call() ”解决了List和基本类型&#xff08;含String&…...

list.toArray

直接去看原文 原文链接:List的toArray()方法_list.toarray-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- toArray()介绍 toArray()方法是List接口中提供的方法&#xff…...

2013年11月10日 Go生态洞察:Go语言四周年回顾

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…...

Ubuntu上使用SSH连接到CentOS系统

确保CentOS系统上的SSH服务器已安装并正在运行&#xff1a; 在CentOS上&#xff0c;默认情况下&#xff0c;SSH服务器&#xff08;sshd&#xff09;应该已安装并正在运行。如果不确定&#xff0c;可以通过以下方式检查&#xff1a; sudo systemctl status sshd如果未安装&…...

【知识增强】A Survey of Knowledge-Enhanced Pre-trained LM 论文笔记

A Survey of Knowledge-Enhanced Pre-trained Language Models Linmei Hu, Zeyi Liu, Ziwang Zhao, Lei Hou, Liqiang Nie, Senior Member, IEEE and Juanzi Li 2023年8月的一篇关于知识增强预训练模型的文献综述 论文思维导图 思维导图网页上看不清的话&#xff0c;可以存…...

shell脚本之函数

快捷查看指令 ctrlf 进行搜索会直接定位到需要的知识点和命令讲解&#xff08;如有不正确的地方欢迎各位小伙伴在评论区提意见&#xff0c;博主会及时修改&#xff09; 函数 一&#xff0c;什么是函数 函数是一段功能代码,用来解决shell编程中冗余代码[重复且不连续出现的功能…...

订水商城实战教程10-宫格导航

上一篇我们介绍了跑马灯的功能&#xff0c;这一篇就进入到我们的主体部分开发。在订水商城业务中可以按照分类查询商品信息&#xff0c;这就涉及到数据源的拆分。 我们在数据源的设计中区分为主子表&#xff0c;主表呢存储唯一的记录&#xff0c;子表的记录可以重复&#xff0…...

【C++11】lambda表达式 | 包装器

文章目录 一、 lambda表达式lambda表达式的引入lambda表达式的语法lambda表达式与函数对象lambda表达式的捕捉列表 二、包装器function包装器bind包装器 一、 lambda表达式 lambda表达式的引入 在C98中&#xff0c;为了替代函数指针&#xff0c;C设计出了仿函数&#xff0c;也…...

网络安全准入技术之MAC VLAN

网络准入控制作为主要保障企业网络基础设施的安全的措施&#xff0c;特别是对于中大型企业来说&#xff0c;终端类型多样数量激增、终端管理任务重难度大、成本高。 在这样的一个大背景下&#xff0c;拥有更灵活的动态识别、认证、访问控制等成为了企业网络安全的最核心诉求之…...

MyBatis 操作数据库

文章目录 1. 什么是MyBatis&#xff1f;2. 入门MyBatis2.1 准备工作2.2.1 创建springboot项目2.2.2 数据准备 2.2 配置数据库连接2.3 写持久层代码2.4 单元测试2.4.1 web测试2.4.2 自动测试 1. 什么是MyBatis&#xff1f; MyBatis是一种持久层框架&#xff0c;用于简化JDBC的开…...

设计模式 -- 建造者模式(Builder Pattern)

这个模式以前也义Android-kotlin的场景下讲过 Android 用建造者模式模式写一个Dialog-CSDN博客 不过用的是 变种的建造者模式 建造者模式&#xff1a; 属于创建型模式 提供了一种创建对象的最佳方式&#xff0c; 使用多个简单的对象一步一步构建成一个复杂的对象 。 介绍 意图…...

如何下载 Apache + PHP + Mysql 集成安装环境并结合内网穿透工具实现公网访问内网服务

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. WampServer下载安装二. WampServer启动三. 安装cpolar内网穿透3.1 注册账号…...

一招告别百度广告烦恼,同时效率提高100倍的几个常用搜索技巧!

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐--…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

《信号与系统》第 6 章 信号与系统的时域和频域特性

目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...

python打卡第47天

昨天代码中注意力热图的部分顺移至今天 知识点回顾&#xff1a; 热力图 作业&#xff1a;对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图&#xff0c;展示模…...