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

在h5端实现录音发送功能(兼容内嵌微信小程序) recorder-core

本文将通过一个实际的 Vue3 组件示例,带你一步步实现“按住录音,松开发送,上滑取消”的语音录制功能。

我们将使用强大且小巧的开源库 recorder-core,支持 MP3、WAV、AAC 等编码格式,兼容性较好。

🔧 项目依赖

pnpm add recorder-core dayjs
# 或
npm install recorder-core dayjs

我们实现的组件是一个 input 输入框,按下开始录音,松开结束录音,上滑取消录音。核心逻辑全部由 recorder-core 管理。

✅ 权限处理机制

第一次调用 rec.open() 时会触发麦克风授权窗口,用户点击「允许」后才能真正录音。所以我们用 isAuthorized 标记避免重复弹窗。


✅ 录音时间和状态展示

我们通过 onProcess() 回调实时拿到录音时间和音量等级,再结合 dayjs 把时间格式化展示在 UI 上(audioLoading.vue 可以自定义成动画弹窗或语音时长条等)。


✅ 录音取消(上滑手势)

录音时用户可能不想发送,我们监听 @touchmove 来模拟“上滑取消”操作,直接关闭并丢弃录音。

完整代码如下

<template><inputdisabled="true"placeholder="按住 说话"@touchstart="handleTouchStart"@touchmove="handleTouchMove"@touchend="handleTouchEnd"/><AudioLoading :audioLoading="audioLoading" :audioTime="audioTime" />
</template><script setup>import { ref } from 'vue';import dayjs from 'dayjs';import Recorder from 'recorder-core';import 'recorder-core/src/engine/mp3'; // mp3 封装import 'recorder-core/src/engine/mp3-engine'; // mp3 编码核心模块const audioLoading = ref(false); //语音弹框const audioTime = ref(0); //语音时间const isAuthorized = ref(false); // 是否授权import AudioLoading from './audioLoading.vue';
function formatDateToss(inputStr) {return dayjs(inputStr).format('mm:ss');}let rec = null;/*长按开始录制语音*/const handleTouchStart = e => {audioTime.value = 0;rec = Recorder({type: 'mp3',sampleRate: 16000,bitRate: 16,onProcess(buffers, powerLevel, duration, sampleRate) {audioLoading.value = true;audioTime.value = formatDateToss(duration);},});rec.open(() => {if (isAuthorized.value) {rec.start();}isAuthorized.value = true;},(msg, isUserNotAllow) => {audioLoading.value = false;console.log('停止录音失败: ' + msg);},);};/*语音录制结束*/const handleTouchEnd = () => {audioLoading.value = false;rec.stop((blob, duration) => {rec.close();const url = URL.createObjectURL(blob);console.log(url);},msg => {rec.close();console.log('停止录音失败: ' + msg);},);};//上滑取消const handleTouchMove = () => {rec.close();rec.stop();audioLoading.value = false;};
</script>

AudioLoading加载组件

<template><view class="modal-body" v-if="audioLoading"><view class="time">{{ audioTime }}</view><view class="sound-waves"><viewv-for="(item, index) in radomHeight":key="index":style="`height: ${item}rpx; margin-top: -${item / 2}rpx;`"></view><view style="clear: both; width: 0; height: 0"></view></view><view class="desc">松开发送,上滑取消</view></view>
</template><script setup>import { watch, ref } from 'vue';import { onLoad } from '@dcloudio/uni-app';const props = defineProps({audioTime: {type: Number,},audioLoading: {type: Boolean,default: false,},});const radomHeight = ref([50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,50, 50, 50,]);onLoad(() => {});let timer;watch(() => props.audioLoading,val => {if (val) {timer = setInterval(() => {myradom();}, 500);} else {clearInterval(timer);}},);const myradom = () => {let _radomheight = radomHeight.value;for (var i = 0; i < radomHeight.value.length; i++) {//+1是为了避免为0_radomheight[i] = 100 * Math.random().toFixed(2) + 10;}radomHeight.value = _radomheight;};
</script><style scoped lang="scss">.modal-body {position: fixed;top: 500rpx;left: 235rpx;width: 280rpx;height: 280rpx;background: rgba(0, 0, 0, 0.75);border-radius: 16rpx;backdrop-filter: blur(20rpx);box-sizing: border-box;padding-top: 40rpx;}.time {width: 100%;text-align: center;font-size: 28rpx;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #ffffff;}.sound-waves {width: 100%;box-sizing: border-box;padding-left: 10%;margin-top: 70rpx;height: 50rpx;text-align: center;}.sound-waves view {transition: all 0.5s;width: 1%;margin-left: 1.5%;margin-right: 1.5%;height: 100rpx;background-color: #ffffff;float: left;}.desc {width: 100%;font-size: 30rpx;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #ffffff;line-height: 42rpx;text-align: center;margin-top: 20rpx;}.record-btn {width: 584rpx;height: 74rpx;line-height: 74rpx;text-align: center;background: #ffffff;border-radius: 16rpx;font-size: 32rpx;font-family: PingFangSC-Semibold, PingFang SC;font-weight: 600;color: #000000;}.record-btn::after {border: none;}
</style>

注意如果内嵌到微信小程序中开发环境 会直接拒绝权限

必须部署到http环境才可以

相关文章:

  • 了解一下C#的SortedSet
  • MicroPython 开发ESP32应用教程 之 线程介绍及实例分析
  • LockSupport与Condition解析
  • 数据库大学实验二
  • 53、用例(Use Case)详解
  • Java网络编程性能优化
  • 六大常用查找算法对比分析
  • Mybatis使用update更新值为null时不生效问题解决
  • Python+AI Agent:解锁MCP Servers的智能潜力
  • (自用)Java学习-5.16(取消收藏,批量操作,修改密码,用户更新,上传头像)
  • 相机定屏问题分析四:【cameraserver 最大request buffer超标】后置视频模式预览定屏闪退至桌面
  • 自动驾驶规划控制教程——不确定环境下的决策规划
  • 函数到底有多少细节?
  • Docker+MobaXterm+x11实现容器UI界面转发本地
  • rlemasklib 安装笔记
  • algolia使用配置教程-为SSG静态站增加algolia搜索功能
  • 投影机光源三代发展史:从高压汞灯、白光 LED 到三色光源
  • 【Python】日期计算和自动化运行脚本
  • 2025年我国低空经济产业链研究与梳理
  • IEEE Journal on Selected Areas in Communications 2025年论文整理2(中英文摘要)
  • 企梦网站建设/智能营销方法
  • 万网做网站多少钱/怎么制作微信小程序
  • 小型手机网站建设多少钱/如何检测网站是否安全
  • 在服务器网站上做跳转/水果网络营销策划书
  • 娃哈哈网站建设策划书/全球网站流量排名100
  • 阿里云个人怎么免费做网站/爱站网权重查询