前端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;"></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;"></p><p>任务详情 - 按住说话</p></div></div>
</template>
相关文章:
前端h5录音
时隔差不多半个月, 现在才来写这编博客。由于某些原因,我一直没有写,请大家原谅。前段时间开发了一个小模块。模块的主要功能就是有一个录音的功能。也就是说,模仿微信发送语音的功能一样。不多说,直接来一段代码 //自…...
Android Studio 使用Flutter开发第一个Web页面(进行中)
附上Flutter官方文档 1、新建Flutter项目(需要勾选web选项) 新建项目构成为: 2、配置 Flutter 使用 path 策略 官方文档 在main.dart中,需要导入flutter_web_plugins/url_strategy.dart包,并在main(){}函数中usePath…...
Vue.js组件精讲 第2章 基础:Vue.js组件的三个API:prop、event、slot
如果您已经对 Vue.js 组件的基础用法了如指掌,可以跳过本小节,不过当做复习稍读一下也无妨。 组件的构成 一个再复杂的组件,都是由三部分组成的:prop、event、slot,它们构成了 Vue.js 组件的 API。如果你开发的是一个…...
npm install 报 ERESOLVE unable to resolve dependency tree 异常解决方法
问题 在安装项目依赖时,很大可能会遇到安装不成功的问题,其中有一个很大的原因,可能就是因为你的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 中文件上传 为了能上传文件,必须将 from 表单的 method 设置为 POST,并将 enctype 设置为 multipart/form-data…...
WSL访问adb usb device
1.Windows上用PowerShell运行: winget install --interactive --exact dorssel.usbipd-win 2.在WSLUbuntu上终端运行: 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项目中需要条形码功能,用yarn add安装react-barcode后,在项目中使用import Barcode from ‘react-barcode’,页面中一直白屏,加载中 查看控制台报以下错误 load component failed Error: Module "./react-barcode"…...
ES6基础(JavaScript基础)
本文用于检验学习效果,忘记知识就去文末的链接复习 1. ECMAScript介绍 ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言…...
[蓝桥杯] 纸张尺寸(C语言)
题目链接 蓝桥杯2022年第十三届省赛真题-纸张尺寸 - C语言网 题目理解 输入一行包含一个字符串表示纸张的名称,该名称一定是 A0、A1、A2、A3、A4、A5、A6、A7、A8、A9 之一,输出两行,每行包含一个整数,依次表示长边和短边的长度…...
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
项目背景 在自研的系统,需要实现类似草料二维码的功能 将我们自己的小程序,通过代码生成相想要的小程序二维码 代码已经上传到 Github 需要的朋友可以自取 https://github.com/ctra-wang/wechat-mini-qrcode 一、生成Qrcode并提交到对象存储 通过源生A…...
kubeadm k8s 1.24之后版本安装,带cri-dockerd
最后编辑时间:2024/3/26 适用于1.24之后的版本 单节点配置 检查是否已经安装kubectl, kubelet, kubeadm直接输入命令确定,如果提示没有该指令则正确 kubectl kubelet kubeadm如果之前安装,首先reset,然后使用apt remove和snap r…...
13-pyspark的共享变量用法总结
目录 前言广播变量广播变量的作用 广播变量的使用方式 累加器累加器的作用累加器的优缺点累加器的使用方式 PySpark实战笔记系列第四篇 10-用PySpark建立第一个Spark RDD(PySpark实战笔记系列第一篇)11-pyspark的RDD的变换与动作算子总结(PySpark实战笔记系列第二篇))12-pysp…...
BI数据分析软件:行业趋势与功能特点剖析
随着数据量的爆炸性增长,企业对于数据的需求也日益迫切。BI数据分析软件作为帮助企业实现数据驱动决策的关键工具,在当前的商业环境中扮演着不可或缺的角色。本文将从行业趋势、功能特点以及适用场景等方面,深入剖析BI数据分析软件࿰…...
centos7上docker搭建vulhub靶场
1 vulhub靶场概述 VulHub是一个在线靶场平台,提供了丰富的漏洞环境供安全爱好者学习和实践。 该平台主要面向网络安全初学者和进阶者,通过模拟真实的漏洞环境,帮助用户深入了解漏洞的成因、利用方式以及防范措施。 此外,VulHub还…...
Flutter入门指南
文章目录 一、环境搭建二、基本概念三、创建一个简单的Flutter应用四、常用组件及代码示例五、总结推荐阅读 笔者项目中使用Flutter的模块并不多。虽然笔者还没有机会在项目中正式使用Flutter,但是也在学习Flutter的一些基本用法。本文就是一篇Flutter的入门介绍&am…...
keepalived脑裂问题
脑裂问题产生的原因 就是vip同时存在 master和backup 就叫做脑裂 比如说 backup 机器的防火墙没关,并且没有允许vrrp通过,backup 没有收到master的心跳数据,就会抢夺资源,发生脑裂问题测试 我们打开test3的防火墙,此…...
GitHub访问速度提升10倍的终极方案:Fast-GitHub加速插件完整指南
GitHub访问速度提升10倍的终极方案:Fast-GitHub加速插件完整指南 【免费下载链接】Fast-GitHub 国内Github下载很慢,用上了这个插件后,下载速度嗖嗖嗖的~! 项目地址: https://gitcode.com/gh_mirrors/fa/Fast-GitHub 你是否…...
C#怎么使用Switch表达式 C#新版switch表达式和传统switch语句的区别和升级写法【语法】
switch表达式必须返回值,是结果导向的;需覆盖所有可能路径,支持类型匹配when守卫,不可fall-through,null和_兜底需显式处理,不适用于副作用或条件耦合场景。Switch表达式必须返回值,不能只“做事…...
反激电源设计避坑指南:从原理到实践的5个关键点
反激电源设计避坑指南:从原理到实践的5个关键点 在电源设计领域,反激式拓扑因其结构简单、成本低廉而广受欢迎,但看似简单的电路背后却暗藏诸多设计陷阱。许多工程师在首次接触反激电源时,往往会被其"低门槛"所迷惑&…...
基于SpringBoot+Vue图书馆座位预约系统设计与实现+毕业论文+答辩PPT+指导搭建视频
开发工具: Idea或Eclipse数据库: MySQLJar包仓库: Maven前端框架: Vue2后端框架: Springboot具体请看视频演示源码已经过本人亲自测试,可完美运行...
数据智能体是什么?怎么理解数据智能体?
以前季度末做复盘,分析各区域的业绩达成、客户流失原因和下季度的增长预测,你得找数据分析师、等SQL查询、看静态报表,前后折腾三四天才能得出结论。而现在只需要告诉AI"帮我分析上季度各区域销售表现,找出掉队原因"&am…...
终极指南:3分钟掌握Ofd2Pdf免费OFD转PDF完整教程
终极指南:3分钟掌握Ofd2Pdf免费OFD转PDF完整教程 【免费下载链接】Ofd2Pdf Convert OFD files to PDF files. 项目地址: https://gitcode.com/gh_mirrors/ofd/Ofd2Pdf 你是否经常遇到OFD格式文件无法打开、无法分享的烦恼?作为中国自主研发的电子…...
Python实战:全球植被生产力BEPS模型数据(1981-2019)的读取、转换与可视化分析
1. 认识BEPS模型数据 全球植被生产力数据是研究生态系统碳循环的重要基础。居为民教授团队发布的1981-2019年全球逐日GPP/NEP/NPP数据集,采用BEPS(Boreal Ecosystem Productivity Simulator)模型生成,这个模型考虑了植被参数、气象…...
Ubuntu 18.04 远程桌面新选择:XRDP一键部署与安全配置指南
1. 为什么选择XRDP作为Ubuntu 18.04远程桌面方案 如果你正在管理Ubuntu 18.04服务器,突然需要图形化操作界面,XRDP绝对是个值得考虑的选择。相比传统的VNC方案,XRDP最大的优势就是原生支持Windows远程桌面协议(RDP)&am…...
如何调试Qwen3-Embedding-4B?日志分析与错误定位实战教程
如何调试Qwen3-Embedding-4B?日志分析与错误定位实战教程 1. 引言:为什么需要调试Embedding模型? 当你使用Qwen3-Embedding-4B构建知识库时,可能会遇到各种问题:模型加载失败、向量生成异常、检索结果不准确等。这些…...
ViGEmBus虚拟手柄驱动技术深度解析:Windows内核级游戏控制器模拟架构揭秘
ViGEmBus虚拟手柄驱动技术深度解析:Windows内核级游戏控制器模拟架构揭秘 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus ViGEmBus作为Windows内…...
