当前位置: 首页 > 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;此…...

Godot 3动态区域加载系统:构建无缝大世界的核心方案

1. 项目概述与核心思路如果你正在用Godot引擎开发一个大型的2D或3D游戏&#xff0c;比如一个开放世界RPG或者一个广阔的平台跳跃游戏&#xff0c;你可能会遇到一个头疼的问题&#xff1a;整个游戏世界太大&#xff0c;一次性全部加载到内存里&#xff0c;不仅启动慢得像蜗牛&am…...

RAG检索增强生成——让大模型学会“开卷作答”

前言 在前面的文章中&#xff0c;我们拆解了Embedding如何把文字变成向量&#xff0c;Transformer如何理解词与词之间的关系&#xff0c;以及大模型为什么会产生幻觉。这三条知识线最终汇聚到一个技术上——RAG&#xff08;检索增强生成&#xff09;。 你可能会问&#xff1a;R…...

2026年AI大模型接口中转站全网实测:五大头部服务商谁能脱颖而出,引领行业潮流?

【2026年3月31日 科技产业快讯】2026年&#xff0c;全球AI大模型产业正式从技术创新阶段步入规模化商业落地阶段。AI大模型接口中转站作为连接底层模型能力和上层产业应用的关键基础设施&#xff0c;其市场需求呈现出指数级的增长。国家数据局最新公布的数据显示&#xff0c;截…...

如何在Windows上实现macOS风格的三指拖拽功能?终极指南

如何在Windows上实现macOS风格的三指拖拽功能&#xff1f;终极指南 【免费下载链接】ThreeFingersDragOnWindows Enables macOS-style three-finger dragging functionality on Windows Precision touchpads. 项目地址: https://gitcode.com/gh_mirrors/th/ThreeFingersDragO…...

别再混淆了!一文讲透WLAN中‘直接转发’和‘隧道转发’到底怎么选?附华为配置对比

WLAN转发模式深度解析&#xff1a;直接转发与隧道转发的实战选型指南 在无线局域网&#xff08;WLAN&#xff09;的架构设计中&#xff0c;数据转发模式的选择往往成为网络工程师最纠结的技术决策之一。想象一下这样的场景&#xff1a;当你正在为一个大型企业园区设计无线网络时…...

如何轻松下载网页视频?这款开源浏览器插件给你答案

如何轻松下载网页视频&#xff1f;这款开源浏览器插件给你答案 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 还在为无法保存网页上的精彩视…...

保姆级教程:手把手教你修改Material Studio的Perl交联脚本,适配你的自定义聚合物

深度定制Material Studio交联脚本&#xff1a;从环氧树脂到多元聚合物的Perl魔改指南 当你第一次在论文中看到那个神奇的环氧树脂交联脚本时&#xff0c;可能和我一样兴奋——终于不用手动跟踪每个反应位点了&#xff01;但现实很快给了我们这些研究聚酰亚胺、聚氨酯等非环氧体…...

如何快速掌握量化交易:QuantConnect教程的完整入门指南

如何快速掌握量化交易&#xff1a;QuantConnect教程的完整入门指南 【免费下载链接】Tutorials Jupyter notebook tutorials from QuantConnect website for Python, Finance and LEAN. 项目地址: https://gitcode.com/gh_mirrors/tutorials2/Tutorials 想要进入量化交易…...

互联网大厂 Java 求职面试:从音视频到微服务的技术探讨

互联网大厂 Java 求职面试&#xff1a;从音视频到微服务的技术探讨 在这场严肃的面试中&#xff0c;面试官与搞笑的候选人燕双非之间的对话充满了技术和幽默。以下是他们的对话记录。第一轮提问 面试官&#xff1a;燕双非&#xff0c;首先请你介绍一下 Java SE 的特点&#xff…...

STTS技术:视频理解中的智能token剪枝方法

1. 项目背景与核心价值视频理解一直是多模态AI领域的硬骨头。传统方法通常简单截取关键帧或均匀采样&#xff0c;就像用渔网捞鱼——不管大鱼小鱼统统收进来。STTS&#xff08;Spatio-Temporal Token Selection&#xff09;技术的突破在于&#xff0c;它像智能声纳一样精准定位…...