效果图展示

插件安装
js
npm i wavesurfer
实现过程
js
<!--
@author: weileiming
@date: 2025-04-26 14:04:08
@description: 悬浮音波层
@props:
isRecord: 录制状态
waveOptions: 音波基础配置
overlayStyle: 基础蒙层配置
@methods:
togglePlay: 切换录制状态
-->
<template>
<div>
<!-- 悬浮音波层 -->
<div v-if="isRecord" class="floating-wave" :style="overlayStyle">
<div id="waveform"></div>
</div>
</div>
</template>
<script setup>
import { ref, nextTick, watch } from "vue";
import WaveSurfer from "wavesurfer.js";
import RecordPlugin from "wavesurfer.js/dist/plugins/record.esm.js";
const props = defineProps({
// 录制状态
isRecord: {
type: Boolean,
required: true,
},
// 音波基础配置
waveOptions: {
type: Object,
default: () => ({
waveColor: "#4CAF50",
progressColor: "#52C41A",
height: 20,
barWidth: 2,
barGap: 3,
barRadius: 2,
barMinHeight: 1,
normalize: true,
interact: false,
fillParent: true,
pixelRatio: 1,
minPxPerSec: 50,
cursorWidth: 0,
responsive: true,
partialRender: true,
removeMediaControl: true,
hideScrollbar: true,
}),
},
// 基础蒙层配置
overlayStyle: {
type: Object,
default: () => ({
background: 'rgba(0, 0, 0, 0.15)',
width: '150px',
height: '50px',
minWidth: '150px',
padding: '15px 10px',
boxSizing:'border-box',
}),
},
});
const wavesurfer = ref(null);
const recorder = ref(null);
// 先声明 createWaveform
const createWaveform = async () => {
await nextTick();
try {
wavesurfer.value = WaveSurfer.create({
container: "#waveform",
...props.waveOptions,
});
// 创建录音插件前先检查权限
await navigator.mediaDevices.getUserMedia({ audio: true });
recorder.value = wavesurfer.value.registerPlugin(
RecordPlugin.create({
scrollingWaveform: true,
renderRecordedAudio: false,
mediaRecorderOptions: {
audioBitsPerSecond: 128000,
},
})
);
recorder.value.on("record-start", () => {
console.log("录音开始");
});
recorder.value.on("record-end", () => {
console.log("录音结束");
});
} catch (err) {
console.error("创建 WaveSurfer 实例失败:", err);
throw err;
}
};
// 初始化录制
const initRecorder = async () => {
if (!wavesurfer.value) {
await createWaveform();
}
};
// 监听当前的启动状态 使用initRecorder 保证父组件获取到的状态和组件一致
watch(
() => props.isRecord,
async (newVal) => {
try {
await initRecorder();
if (newVal) {
await recorder.value.startRecording();
} else {
await recorder.value.stopRecording();
}
} catch (error) {
console.error("录音操作失败:", error);
}
},
{ immediate: true }
);
const togglePlay = async () => {
try {
await initRecorder();
} catch (error) {
console.error("麦克风访问错误:", error);
alert("请允许访问麦克风");
}
};
// 暴露方法
defineExpose({
togglePlay,
});
</script>
<style scoped>
</style>
使用示例
js
<script setup>
import { ref } from 'vue';
import SoundWave from './components/SoundWave/SoundWave.vue'
const mkRef = ref(null);
const isRecord = ref(false);
const handleToggle = () => {
console.log('handleToggle', mkRef.value);
mkRef.value.togglePlay();
isRecord.value = !isRecord.value;
};
</script>
<template>
<button class="control-btn" @click="handleToggle">START</button>
<SoundWave ref="mkRef" :isRecord="isRecord"></SoundWave>
</template>
<style scoped>
.control-btn {
background-color: #4CAF50;
border: none;
color: white;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px;
cursor: pointer;
border-radius: 4px;
transition: background-color 0.3s ease;
}
.control-btn:hover {
background-color: #45a049;
}
</style>
npm下载该功能
上面功能可以直接去我的npm主页下载
js
npm i vue-sound-wave
说明
只针对麦克风音波效果开发,不做音频文件导出