说明:
用vue做一款录音系统
1.点击按钮,开始录制音频
2.录制过程中,可以暂停和停止录制 有时长显示
3.点击停止录制 可以保存音频,保存在本地
4.找到刚刚保存的音频路径,可以点击播放 ,需要显示音频总时长
5.可以下载音频
效果图:
step1:
<template><div class="container"><h1>录音系统</h1><!-- 录音控制 --><div class="controls"><button @click="toggleRecording" :disabled="isPaused">{{ isRecording ? '正在录音...' : '开始录音' }}</button><button @click="togglePause" :disabled="!isRecording">{{ isPaused ? '继续录音' : '暂停录音' }}</button><button @click="stopRecording" :disabled="!isRecording && !isPaused">停止并保存</button></div><!-- 录音时长 --><div class="duration">当前时长: {{ formatTime(currentDuration) }}</div><!-- 保存的录音 --><div class="recordings" v-if="currentRecording"><h2>保存的录音</h2><div class="audio-item"><audio ref="audioPlayer" controls @loadedmetadata="updateDuration"></audio><div><button @click="playRecording">播放</button><span>时长: {{ formatTime(currentRecording.duration) }}</span><a :href="currentRecording.url" download="recording.webm">下载</a><button @click="deleteRecording" class="delete-btn">删除</button></div></div></div></div>
</template><script>
export default {data() {return {isRecording: false,isPaused: false,currentDuration: 0,timer: null,mediaRecorder: null,audioChunks: [],currentRecording: null};},methods: {async toggleRecording() {if (!this.isRecording) {try {const stream = await navigator.mediaDevices.getUserMedia({ audio: true });this.mediaRecorder = new MediaRecorder(stream);this.mediaRecorder.ondataavailable = event => {this.audioChunks.push(event.data);};this.mediaRecorder.onstop = () => {const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' });const audioUrl = URL.createObjectURL(audioBlob);// 只保留最新录音this.currentRecording = {url: audioUrl,duration: this.currentDuration};this.audioChunks = [];stream.getTracks().forEach(track => track.stop());};this.mediaRecorder.start();this.startTimer();this.isRecording = true;this.isPaused = false;} catch (err) {console.error('无法访问麦克风:', err);}}},// 新增删除方法deleteRecording() {if (this.currentRecording) {URL.revokeObjectURL(this.currentRecording.url);this.currentRecording = null;}},togglePause() {if (this.isPaused) {this.mediaRecorder.resume();this.startTimer();} else {this.mediaRecorder.pause();clearInterval(this.timer);}this.isPaused = !this.isPaused;},stopRecording() {this.mediaRecorder.stop();clearInterval(this.timer);this.isRecording = false;this.isPaused = false;this.currentDuration = 0;},startTimer() {this.timer = setInterval(() => {this.currentDuration++;}, 1000);},playRecording() {const audioElement = this.$refs.audioPlayer;audioElement.src = this.currentRecording.url;audioElement.play();},updateDuration() {const audioElement = this.$refs.audioPlayer;if (this.currentRecording) {this.currentRecording.duration = Math.round(audioElement.duration);}},formatTime(seconds) {const mins = Math.floor(seconds / 60);const secs = seconds % 60;return `${mins}:${secs.toString().padStart(2, '0')}`;}},beforeUnmount() {clearInterval(this.timer);if (this.currentRecording) {URL.revokeObjectURL(this.currentRecording.url);}}
};
</script><style>
/* 新增删除按钮样式 */
.delete-btn {background-color: #ff4444;margin-left: 10px;
}.container {max-width: 600px;margin: 0 auto;padding: 20px;
}.controls {margin: 20px 0;display: flex;gap: 10px;
}.audio-item {margin: 10px 0;padding: 10px;border: 1px solid #ddd;border-radius: 4px;
}.duration {font-size: 1.2em;margin: 10px 0;
}button {padding: 8px 16px;cursor: pointer;background-color: #4CAF50;color: white;border: none;border-radius: 4px;
}button:disabled {background-color: #cccccc;cursor: not-allowed;
}a {margin-left: 10px;color: #2196F3;text-decoration: none;
}</style>
end