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

前端h5录音

时隔差不多半个月, 现在才来写这编博客。由于某些原因,我一直没有写,请大家原谅。前段时间开发了一个小模块。模块的主要功能就是有一个录音的功能。也就是说,模仿微信发送语音的功能一样。不多说,直接来一段代码

//自定义长按事件,注意, directives是跟 data ,created() 同一级的,注意注意
directives: {longpress: {bind(el, binding, vnode) {let pressTimer = null;let maxPressTime = 60000; // 60秒 = 60000毫秒  let startCallback = binding.value.start || Vue.noop;let endCallback = binding.value.end || Vue.noop;function handlePress() {startCallback();pressTimer = setTimeout(() => {endCallback();clearTimeout(pressTimer);pressTimer = null;}, maxPressTime);}function handleRelease() {if (pressTimer) {clearTimeout(pressTimer);pressTimer = null;endCallback();}}// 确保这些函数在unbind中可用  el._handlePress = handlePress;el._handleRelease = handleRelease;// 添加事件监听器  el.addEventListener('mousedown', handlePress);el.addEventListener('touchstart', handlePress);el.addEventListener('mouseup', handleRelease);el.addEventListener('touchend', handleRelease);el.addEventListener('mouseleave', handleRelease);el.addEventListener('touchcancel', handleRelease);},unbind(el) {// 移除事件监听器  el.removeEventListener('mousedown', el._handlePress);el.removeEventListener('touchstart', el._handlePress);el.removeEventListener('mouseup', el._handleRelease);el.removeEventListener('touchend', el._handleRelease);el.removeEventListener('mouseleave', el._handleRelease);el.removeEventListener('touchcancel', el._handleRelease);// 清理自定义属性  el._handlePress = null;el._handleRelease = null;}}
},
data(){return {zheZhao:false,//录音时的遮罩层isMai:false,//初始化,是否支持录音luYinAttr: {isAn:false,s: 0,timer:null,audioArray:[],startTime: null,//录音开始时间endTime: null, //录音结束时间mediaRecorder: null,recording: false, //录音状态(用于录音记时)timeLength: 0,//录音时长recordedChunks: [],timer: null,longPressThreshold:800,},}
}
//初始化录音对象(记住,录音一定得在 https里面。当然,在本地开发 localhost 可以不需要,但上线一定得在https里面)
luYin() {//这儿先做判断,判断当前设备或当前网络是否支持录音,如果不支持,那下面的也就不用多说了。//console.log(navigator, 'navigator.mediaDevices')if (!('mediaDevices' in navigator)) {this.isMai = false;return false;}navigator.mediaDevices.getUserMedia({ audio: true }).then(this.luYinSuccess) //支持录音,继续执行下面的操作.catch(this.luYinErr) //不支持录音,没下文
},
luYinSuccess(stream) {const audioContext = new AudioContext();//const sourceNode = audioContext.createMediaStreamSource(stream); //没用上,先注释const mediaRecorder = new MediaRecorder(stream);const recordedChunks = [];this.luYinAttr.mediaRecorder = mediaRecorderthis.luYinAttr.recordedChunks = recordedChunksthis.isMai = true;
},
luYinErr(err) {this.isMai = false;//console.log('The following error occurred: ' + err);
},//startRecording ,  stopRecording是开始计时和结束计时(由于录音的时间不能太长,这儿我,限制为1分分钟的时长。所以,我得有一个录音计时,超过1分钟,录音取消)
//开始计时
startRecording() {console.log('开始计时')this.luYinAttr.isAn = true;this.zheZhao = true;this.luYinAttr.s = 0;this.luYinAttr.recording = true;this.luYinAttr.startTime = Date.now();this.luYinAttr.timer = setInterval(() => {this.luYinAttr.s = this.luYinAttr.s + 1;} , 500)
},
//结束录音计时
stopRecording() {this.luYinAttr.recording = false;const endTime = Date.now();const startTime = this.luYinAttr.startTimeconst recordDuration = (endTime - startTime) / 1000; // 计算录音时长(秒) if (recordDuration >= 60) {this.luYinAttr.timeLength = 60;//结束录音}this.luYinAttr.timeLength = recordDuration;/*const maxWidth = 300; // 设置图标的最大宽度  const indicatorWidth = Math.min(recordDuration * 20, maxWidth); // 根据录音时长计算图标宽度,假设每秒对应2个像素宽度  console.log(indicatorWidth, '时长')console.log('结束计时')*/
},startLongPress() {//console.log('长按开始');let that = this;clearTimeout(this.luYinAttr.timer);that.luYinAttr.timer = setTimeout(function () {// 执行长按操作  //console.log('长按操作开始');that.luYinAttr.mediaRecorder.start();//console.log(that.luYinAttr.mediaRecorder.state , 'qqggg');//startRecord.disabled = true;//stopRecord.disabled = false;that.startRecording();}, that.luYinAttr.longPressThreshold);// 在这里编写长按开始时的逻辑
},
endLongPress() {//长按结束事件let that = this;//console.log('取消')clearTimeout(that.luYinAttr.timer);that.luYinAttr.mediaRecorder.stop();that.stopRecording();that.luYinAttr.mediaRecorder.ondataavailable = async function (e) {console.log(e)if (e.data.size > 0) {const blobObj = e.data;let nowTime = new Date().getTime();let fileName = 'LY_' + nowTime + '.mp3';const file = new File([blobObj], fileName, { type: 'audio/mpeg' });//that.uplodAudio(file) //上传录音that.luYinAttr.isAn = false;that.zheZhao = false;clearInterval(that.luYinAttr.timer)} else {// no data to push  }};
},//试听录音(在苹果机上不支持)
listenAudio(obj, index) {let myTimer = null;this.play.listenStatus = this.play.listenStatus + 1;if (this.play.listenStatus > 1) {clearInterval(myTimer)return false;}if (!this.playActive.isLongPressing) {let that = this;let itemAudio = [(that.luYinAttr.recordedChunks)[index]]//console.log(itemAudio, 'itemAudio', obj)let len = JSON.parse(JSON.stringify(obj.timeLength));obj.timeLength = 0;myTimer = setInterval(() => {obj.timeLength = obj.timeLength + 1;if (obj.timeLength == len) {clearInterval(myTimer)this.play.listenStatus = 0;}} , 1000)const blob = new Blob(itemAudio, { 'type': 'audio/ogg; codecs=opus' });//const blob = new Blob(that.luYinAttr.recordedChunks, { 'type': 'audio/ogg; codecs=opus' });//console.log(blob, 'blob')const audioURL = window.URL.createObjectURL(blob);//console.log(audioURL, 'audioURL')const audio = new Audio(audioURL);//console.log(audio,'audio')audio.play().catch(err => {console.log('Failed to play sound:', err);});}
},
<template v-if="isMai == true"><div class="" style="background:#ffffff; padding:10px 16px;"><div class="list" style="text-align:center"><template v-for="(audioArrayItem , audioArrayIndex) in luYinAttr.audioArray"><el-tooltip placement="top" :manual="true" :value="audioArrayItem.tooltip"><div slot="content"><span @click="returnAudioArrayItem(audioArrayItem , audioArrayIndex)">移除</span></div><div style="margin-bottom:10px;"  @click.prevent="listenAudio(audioArrayItem , audioArrayIndex)"><div style="overflow:hidden"><div style="float:left"><p style="background: #3975C6; color: #ffffff; padding:0 8px; display:inline-block; border-radius:4px;"><span class="icon iconfont playIcon" style="display:inline-block; height:20px; font-size:14px; text-align:center;">&#xe618;</span><span style="position:relative; top:-5px; margin:0 5px;"><template v-for="(item , index) in audioArrayItem.timeLength"><span>,,</span></template></span><span>{{ audioArrayItem.timeLength }}'</span></p></div><div style="float:right"><van-button type="info" size="mini" @click.stop="returnAudioArrayItem(audioArrayItem , audioArrayIndex)">移除</van-button></div></div></div></el-tooltip></template></div><div class="byBtn" :class="luYinAttr.isAn == true ? 'myIsYesAn': 'myIsNoAn' " style="text-align: center; font-size:14px;" v-longpress="{ start: startLongPress, end: endLongPress }"><p class="icon iconfont" style="color: #3975C6; font-size: 24px;">&#xe7a6;</p><p>任务详情 - 按住说话</p></div></div>
</template>

相关文章:

前端h5录音

时隔差不多半个月&#xff0c; 现在才来写这编博客。由于某些原因&#xff0c;我一直没有写&#xff0c;请大家原谅。前段时间开发了一个小模块。模块的主要功能就是有一个录音的功能。也就是说&#xff0c;模仿微信发送语音的功能一样。不多说&#xff0c;直接来一段代码 //自…...

Android Studio 使用Flutter开发第一个Web页面(进行中)

附上Flutter官方文档 1、新建Flutter项目&#xff08;需要勾选web选项&#xff09; 新建项目构成为&#xff1a; 2、配置 Flutter 使用 path 策略 官方文档 在main.dart中&#xff0c;需要导入flutter_web_plugins/url_strategy.dart包&#xff0c;并在main(){}函数中usePath…...

Vue.js组件精讲 第2章 基础:Vue.js组件的三个API:prop、event、slot

如果您已经对 Vue.js 组件的基础用法了如指掌&#xff0c;可以跳过本小节&#xff0c;不过当做复习稍读一下也无妨。 组件的构成 一个再复杂的组件&#xff0c;都是由三部分组成的&#xff1a;prop、event、slot&#xff0c;它们构成了 Vue.js 组件的 API。如果你开发的是一个…...

npm install 报 ERESOLVE unable to resolve dependency tree 异常解决方法

问题 在安装项目依赖时&#xff0c;很大可能会遇到安装不成功的问题&#xff0c;其中有一个很大的原因&#xff0c;可能就是因为你的npm版本导致的。 1.npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree 2.ERESOLVE unable to resolve dependenc…...

RPC还是HTTP

RPC是一个远程调用的通讯协议 RPC要比HTTP快一些 1. HTTP体积大 原因是HTTP协议会带着一堆无用信息 HTTP由三部分组成 请求头 请求行 请求体 这三部分只有请求体是需要的 2. HTTP支持的序列化协议比较少 RPC支持更多轻量级的通讯协议 3. RPC协议支持定制...

Conda 常用命令总结

创建虚拟环境 conda create -n name python[your_version] 激活环境 conda activate name 退出环境 conda deactivate 查看虚拟环境 conda info --envs 删除虚拟环境 conda remove -n name --all 删除所有的安装包及cache(索引缓存、锁定文件、未使用过的包和tar包) …...

Spring MVC 文件上传和下载

文章目录 Spring MVC 中文件上传利用 commons-fileupload 文件上传使用 Servlet 3.1 内置的文件上传功能 Spring MVC 中文件下载 Spring MVC 中文件上传 为了能上传文件&#xff0c;必须将 from 表单的 method 设置为 POST&#xff0c;并将 enctype 设置为 multipart/form-data…...

WSL访问adb usb device

1.Windows上用PowerShell运行&#xff1a; winget install --interactive --exact dorssel.usbipd-win 2.在WSLUbuntu上终端运行&#xff1a; sudo apt install linux-tools-generic hwdata sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-too…...

CDF与PDF(描述随机变量的分布情况)

一、概念解释 CDF(Cumulative Distribution Function)和PDF(Probability Density Function)是概率论和统计学中常用的两个评价指标,用于描述随机变量的分布情况。 1. CDF(累积分布函数): - CDF是描述随机变量在某个取值及其之前所有可能取值的概率的函数。它表示了累…...

react项目中需要条形码功能,安装react-barcode使用时报错

react项目中需要条形码功能&#xff0c;用yarn add安装react-barcode后&#xff0c;在项目中使用import Barcode from ‘react-barcode’&#xff0c;页面中一直白屏&#xff0c;加载中 查看控制台报以下错误 load component failed Error: Module "./react-barcode"…...

ES6基础(JavaScript基础)

本文用于检验学习效果&#xff0c;忘记知识就去文末的链接复习 1. ECMAScript介绍 ECMAScript是一种由Ecma国际&#xff08;前身为欧洲计算机制造商协会&#xff0c;英文名称是European Computer Manufacturers Association&#xff09;通过ECMA-262标准化的脚本程序设计语言…...

[蓝桥杯] 纸张尺寸(C语言)

题目链接 蓝桥杯2022年第十三届省赛真题-纸张尺寸 - C语言网 题目理解 输入一行包含一个字符串表示纸张的名称&#xff0c;该名称一定是 A0、A1、A2、A3、A4、A5、A6、A7、A8、A9 之一&#xff0c;输出两行&#xff0c;每行包含一个整数&#xff0c;依次表示长边和短边的长度…...

AI推介-多模态视觉语言模型VLMs论文速览(arXiv方向):2024.04.05-2024.04.10

文章目录~ 1.BRAVE: Broadening the visual encoding of vision-language models2.ORacle: Large Vision-Language Models for Knowledge-Guided Holistic OR Domain Modeling3.MedRG: Medical Report Grounding with Multi-modal Large Language Model4.InternLM-XComposer2-4…...

【golang】动态生成微信小程序二维码实战下:golang 生成 小程序二维码图片 并通过s3协议上传到对象存储桶 | 腾讯云 cos

项目背景 在自研的系统&#xff0c;需要实现类似草料二维码的功能 将我们自己的小程序&#xff0c;通过代码生成相想要的小程序二维码 代码已经上传到 Github 需要的朋友可以自取 https://github.com/ctra-wang/wechat-mini-qrcode 一、生成Qrcode并提交到对象存储 通过源生A…...

kubeadm k8s 1.24之后版本安装,带cri-dockerd

最后编辑时间&#xff1a;2024/3/26 适用于1.24之后的版本 单节点配置 检查是否已经安装kubectl, kubelet, kubeadm直接输入命令确定&#xff0c;如果提示没有该指令则正确 kubectl kubelet kubeadm如果之前安装&#xff0c;首先reset&#xff0c;然后使用apt remove和snap r…...

13-pyspark的共享变量用法总结

目录 前言广播变量广播变量的作用 广播变量的使用方式 累加器累加器的作用累加器的优缺点累加器的使用方式 PySpark实战笔记系列第四篇 10-用PySpark建立第一个Spark RDD(PySpark实战笔记系列第一篇)11-pyspark的RDD的变换与动作算子总结(PySpark实战笔记系列第二篇))12-pysp…...

BI数据分析软件:行业趋势与功能特点剖析

随着数据量的爆炸性增长&#xff0c;企业对于数据的需求也日益迫切。BI数据分析软件作为帮助企业实现数据驱动决策的关键工具&#xff0c;在当前的商业环境中扮演着不可或缺的角色。本文将从行业趋势、功能特点以及适用场景等方面&#xff0c;深入剖析BI数据分析软件&#xff0…...

centos7上docker搭建vulhub靶场

1 vulhub靶场概述 VulHub是一个在线靶场平台&#xff0c;提供了丰富的漏洞环境供安全爱好者学习和实践。 该平台主要面向网络安全初学者和进阶者&#xff0c;通过模拟真实的漏洞环境&#xff0c;帮助用户深入了解漏洞的成因、利用方式以及防范措施。 此外&#xff0c;VulHub还…...

Flutter入门指南

文章目录 一、环境搭建二、基本概念三、创建一个简单的Flutter应用四、常用组件及代码示例五、总结推荐阅读 笔者项目中使用Flutter的模块并不多。虽然笔者还没有机会在项目中正式使用Flutter&#xff0c;但是也在学习Flutter的一些基本用法。本文就是一篇Flutter的入门介绍&am…...

keepalived脑裂问题

脑裂问题产生的原因 就是vip同时存在 master和backup 就叫做脑裂 比如说 backup 机器的防火墙没关&#xff0c;并且没有允许vrrp通过&#xff0c;backup 没有收到master的心跳数据&#xff0c;就会抢夺资源&#xff0c;发生脑裂问题测试 我们打开test3的防火墙&#xff0c;此…...

为什么你的MoveIt2 Python API总报错?ROS2环境变量与PYTHONPATH的隐藏陷阱

为什么你的MoveIt2 Python API总报错&#xff1f;ROS2环境变量与PYTHONPATH的隐藏陷阱 当你第一次在ROS2中尝试使用MoveIt2的Python API时&#xff0c;那种"ModuleNotFoundError: No module named moveit"的报错信息可能会让你抓狂。这不是因为你做错了什么&#xff…...

Elasticsearch-03-kNN算法

Elasticsearch-03-kNN算法详解 概述 Elasticsearch提供了强大的k近邻&#xff08;k-Nearest Neighbors, kNN&#xff09;搜索功能&#xff0c;支持两种实现方式&#xff1a;暴力搜索和近似搜索。本文档将详细介绍这两种kNN算法的原理、优缺点和适用场景。 1. 暴力搜索&#xff…...

Andi活码,最简单好用!

上链接&#xff1a; https://app.andi.cn/qr/ 试用过这么多群聊二维码的活码工具。 真正好用的是我推荐的这款Andi活码。 免登录、打开即用。单屏管理&#xff0c;超简单好用。 优威科技有限公司出品。 承诺永久免费长期支持。 稳定可靠好用&#xff01; 不信我来用一下…...

NaViL-9B图文问答教程:支持中英双语提问的跨语言理解能力实测

NaViL-9B图文问答教程&#xff1a;支持中英双语提问的跨语言理解能力实测 1. 认识NaViL-9B NaViL-9B是一款原生多模态大语言模型&#xff0c;由专业研究机构开发。它最吸引人的特点是能够同时理解文字和图片内容&#xff0c;并且支持中文和英文两种语言的提问。想象一下&…...

GetQzonehistory完整指南:三步实现QQ空间历史说说一键备份

GetQzonehistory完整指南&#xff1a;三步实现QQ空间历史说说一键备份 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory GetQzonehistory是一款专为QQ空间用户设计的智能数据备份工具&…...

Windows下MySQL 8.0数据库存储路径迁移实战:释放C盘空间

Windows下MySQL 8.0存储路径迁移全指南&#xff1a;彻底解放C盘空间 对于长期在本地开发环境中使用MySQL的开发者来说&#xff0c;系统盘空间被数据库文件逐渐蚕食是常见痛点。默认安装的MySQL 8.0会将数据目录存放在C盘的隐蔽位置&#xff0c;随着业务数据增长&#xff0c;不仅…...

告别改板焦虑!手把手教你用Ansys SIwave 2022R2搞定PCB信号完整性仿真(附S参数导出Pspice全流程)

告别改板焦虑&#xff01;Ansys SIwave 2022R2信号完整性仿真实战指南 在高速PCB设计领域&#xff0c;信号完整性问题如同悬在硬件工程师头顶的达摩克利斯之剑。当信号速率突破10Gbps&#xff0c;板间距离压缩至毫米级时&#xff0c;传统"设计-打样-测试"的迭代模式已…...

pdf2htmlEX高级调试技术:汇编级调试与反汇编

pdf2htmlEX高级调试技术&#xff1a;汇编级调试与反汇编 【免费下载链接】pdf2htmlEX Convert PDF to HTML without losing text or format. 项目地址: https://gitcode.com/gh_mirrors/pd/pdf2htmlEX pdf2htmlEX是一款能够将PDF文件转换为HTML格式同时保持文本和格式完…...

把 SAP ABAP CDS View Code Mapping 讲透:从 SEGW 映射到 SADL 运行时的关键机制与项目实践

很多 ABAP 开发者在第一次接触 CDS View Code Mapping 时,容易把它理解成一次普通的字段映射操作:左边是 CDS 字段,右边是 OData 属性,拖一拖、连一连,事情就结束了。真正进入项目以后,大家才会发现,这个动作背后牵动的是 SAP Gateway、SADL、DPC 运行时、关联导航,以及…...

Qwen3-4B-Instruct-2507部署避坑指南:从vLLM到Chainlit,新手必看

Qwen3-4B-Instruct-2507部署避坑指南&#xff1a;从vLLM到Chainlit&#xff0c;新手必看 1. 环境准备与快速部署 1.1 系统要求检查 在开始部署前&#xff0c;请确保您的环境满足以下最低要求&#xff1a; 操作系统&#xff1a;Ubuntu 20.04/22.04 或兼容的Linux发行版GPU&a…...