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

web网页上实现录音功能(vue3)

文章目录

    • 一. 前言
    • 二. 技术实现
        • 1.核心API介绍
        • 2.模板部分
        • 3.核心逻辑实现
      • 4. 关键功能点解析
    • 三. 完整代码
    • 四. 功能扩展建议

一. 前言

在Web开发中实现音频录制功能是许多应用场景的常见需求。本文将通过一个完整的Vue 3组件示例,详细解析如何利用现代浏览器API实现网页端的录音功能。

二. 技术实现

1.核心API介绍

MediaRecorder API 是实现录音功能的核心,它允许我们直接捕获来自用户设备的媒体流。主要方法:

getUserMedia() 获取媒体设备权限
MediaRecorder() 创建录音实例
ondataavailable 接收音频数据
onstop 处理录音结束事件

2.模板部分
<template>
  <div class="voice-recorder">
    <!-- 录音控制 -->
    <button @click="toggleRecording" :class="{ recording: isRecording }">
      {{ isRecording ? "停止录音" : "开始录音" }}
    </button>

    <!-- 生成的音频文件列表 -->
    <div v-if="audioFiles.length > 0" class="audio-list">
      <div v-for="(audio, index) in audioFiles" :key="index">
        <audio controls :src="audio.url"></audio>
      </div>
    </div>
  </div>
</template>
3.核心逻辑实现
const isRecording = ref(false);
const mediaRecorder = ref(null);
const audioChunks = ref([]);
const audioFiles = ref([]);
// 开始录音
const startRecording = async (e) => {
  if (isRecording.value) return;
  try {
    audioChunks.value = [];
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    mediaRecorder.value = new MediaRecorder(stream);

    mediaRecorder.value.ondataavailable = (e) => {
      audioChunks.value.push(e.data);
    };
    mediaRecorder.value.onstop = () => {
      const audioBlob = new Blob(audioChunks.value, { type: "audio/webm" });
      const audioURL = URL.createObjectURL(audioBlob);
      audioFiles.value.push({
        name: `recording_${Date.now()}.${getFileExtension(audioBlob.type)}`,
        url: audioURL,
      });
      audioChunks.value = [];
    };
    mediaRecorder.value.start();
    isRecording.value = true;
  } catch (error) {
    console.error("录音错误:", error);
  }
};

4. 关键功能点解析

(1) 音频格式处理
通过MIME类型映射获取文件扩展名:

// 获取文件扩展名
const getFileExtension = (mimeType) => {
  const extensions = {
    "audio/webm": "webm",
    "audio/ogg": "ogg",
    "audio/mp4": "mp4",
    "audio/mpeg": "mp3",
    "audio/wav": "wav",
  };
  return extensions[mimeType] || "webm";
};

(2) 资源管理
组件卸载时自动释放资源:

//停止录音
const stopRecording = () => {
  console.log("停止录音");
  isRecording.value = false;
  if (mediaRecorder.value) {
    mediaRecorder.value.stop();
    mediaRecorder.value.stream.getTracks().forEach((track) => track.stop());
  }
};
// 清理资源
onUnmounted(() => {
  stopRecording();
});

在这里插入图片描述

三. 完整代码

<template>
  <div class="voice-recorder">
    <!-- 录音控制 -->
    <button @click="toggleRecording" :class="{ recording: isRecording }">
      {{ isRecording ? "停止录音" : "开始录音" }}
    </button>

    <!-- 生成的音频文件列表 -->
    <div v-if="audioFiles.length > 0" class="audio-list">
      <div v-for="(audio, index) in audioFiles" :key="index">
        <audio controls :src="audio.url"></audio>
      </div>
    </div>
  </div>
</template>

<script setup>
const isRecording = ref(false);
const mediaRecorder = ref(null);
const audioChunks = ref([]);
const audioFiles = ref([]);

// 开始录音
const startRecording = async (e) => {
  if (isRecording.value) return;
  try {
    audioChunks.value = [];
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    mediaRecorder.value = new MediaRecorder(stream);

    mediaRecorder.value.ondataavailable = (e) => {
      audioChunks.value.push(e.data);
    };
    mediaRecorder.value.onstop = () => {
      const audioBlob = new Blob(audioChunks.value, { type: "audio/webm" });
      const audioURL = URL.createObjectURL(audioBlob);
      audioFiles.value.push({
        name: `recording_${Date.now()}.${getFileExtension(audioBlob.type)}`,
        url: audioURL,
      });
      audioChunks.value = [];
    };
    mediaRecorder.value.start();
    isRecording.value = true;
  } catch (error) {
    console.error("录音错误:", error);
  }
};

//停止录音
const stopRecording = () => {
  console.log("停止录音");
  isRecording.value = false;
  if (mediaRecorder.value) {
    mediaRecorder.value.stop();
    mediaRecorder.value.stream.getTracks().forEach((track) => track.stop());
  }
};

// 获取文件扩展名
const getFileExtension = (mimeType) => {
  const extensions = {
    "audio/webm": "webm",
    "audio/ogg": "ogg",
    "audio/mp4": "mp4",
    "audio/mpeg": "mp3",
    "audio/wav": "wav",
  };
  return extensions[mimeType] || "webm";
};

// 切换录音状态
const toggleRecording = () => {
  if (!isRecording.value) {
    startRecording();
  } else {
    if (mediaRecorder.value) {
      mediaRecorder.value.stop();
      mediaRecorder.value.stream.getTracks().forEach((track) => track.stop());
    }
  }
  isRecording.value = !isRecording.value;
};

// 清理资源
onUnmounted(() => {
  stopRecording();
});
</script>

<style lang="scss" scoped>
.voice-recorder {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
  button {
    padding: 12px 24px;
    background: #42b983;
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.3s;
    &.recording {
      background: #ff4444;
    }
  }

  button:hover {
    background: #3aa876;
  }

  button:disabled {
    background: #ddd;
    cursor: not-allowed;
  }
}

.recording {
  background-color: #ff4444;
  color: white;
}

.audio-list {
  margin-top: 20px;
}
</style>

四. 功能扩展建议

添加录音时长显示
实现音频波形可视化

http://www.dtcms.com/a/106796.html

相关文章:

  • 大模型加速器2.0:构建智能知识库,助力大模型减少“幻觉”
  • 【dp + 裴蜀定理】P8646 [蓝桥杯 2017 省 AB] 包子凑数 题解
  • ubuntu中使用安卓模拟器
  • DeepBI如何深入了解竞品的广告策略和运营动机
  • 电子竞技战队网站设计与实现(ssm+jsp+mysql)含万字详细文档
  • einsum函数
  • 技术回顾day3
  • 大语言模型在端到端智驾中的应用
  • 【Ragflow】9.问答为什么比搜索响应慢?从源码角度深入分析
  • 社交类 APP 设计:打造高用户粘性的界面
  • LE AUDIO CIS连接建立失败问题分析
  • 6.git项目实现变更拉取与上传
  • C++虚函数与抽象类
  • 使用 libevent 处理 TCP 粘包问题(基于 Content-Length 或双 \r\n)
  • 操作系统高频(七)虚拟地址与页表
  • ADASH VA5 Pro中的route功能
  • electron 的 appData 和 userData 有什么区别
  • SPI高级特性分析
  • JavaScript instanceof 运算符全解析
  • 「DeepSeek-V3 技术解析」:无辅助损失函数的负载均衡
  • 双模多态驱动:DeepSeek-V3-0324与DeepSeek-R1医疗领域应用比较分析与混合应用讨论
  • 移动通信网络中漫游机制深度解析:归属网络与拜访网络的协同逻辑
  • PHP的相关配置和优化
  • openstack 查看所有项目配额的命令
  • SU CTF 2025 web 复现
  • tcp的粘包拆包问题,如何解决?
  • 【深度学习量化交易21】行情数据获取方式比测(2)——基于miniQMT的量化交易回测系统开发实记
  • 常见电源模块设计
  • ColPali:基于视觉语言模型的高效文档检索
  • 探索鸿蒙操作系统:迎接万物互联新时代