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

一. 前言

在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>

四. 功能扩展建议

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值