案例展示:
在本案例中vue使用的vue3 的setup语法糖的写法。
一、安装wavesurfer.js
npm install wavesurfer.js
或者
yarn add wavesurfer.js
二、wavesurfer的使用
<script lang="ts" setup>
import { onMounted, ref, nextTick, h } from 'vue';
import WaveSurfer from 'wavesurfer.js/dist/wavesurfer';
import Regions from 'wavesurfer.js/dist/plugins/regions';
import Timeline from 'wavesurfer.js/dist/plugins/timeline';
import _ from 'lodash';
let wavesurfer = ref();
let waveform = ref();
let wsRegions = ref();
let start_time = ref(0);
let table_data = ref<any>([]);
let ws_regions_end = ref<any>(null);
let current_time = ref<string>('00:00:000');
let duration_time = ref<string>('00:00:000');
function getImageUrl() {
return new URL('/src/assets/voice.mp3', import.meta.url).href;
}
const formatTime = (seconds: number) => {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = Math.floor(seconds % 60);
const milliseconds = Math.floor((seconds - Math.floor(seconds)) * 1000);
const formattedMinutes = String(minutes).padStart(2, '0');
const formattedSeconds = String(remainingSeconds).padStart(2, '0');
const formattedMilliseconds = String(milliseconds).padStart(3, '0');
return `${formattedMinutes}:${formattedSeconds}:${formattedMilliseconds}`;
};
const init = () => {
wavesurfer.value = WaveSurfer.create({
container: waveform.value,
cursorColor: 'red', // 播放进行时线条颜色
cursorWidth: 1, // 播放进行时线条宽度
waveColor: '#4986ff', // 未播放的波纹颜色
progressColor: 'blue', // 已播放的波纹颜色
audioRate: 1, // 倍速
height: 200, // 高度
url: getImageUrl()
});
wsRegions.value = wavesurfer.value.registerPlugin(Regions.create());
wavesurfer.value.registerPlugin(
Timeline.create({
height: 20,
primaryLabelInterval: 2,
// insertPosition: 'beforebegin',
style: {
fontSize: '10px',
color: '#6A3274'
}
})
);
};
/* 播放时暂停,暂停时播放 */
function clickMusic() {
wavesurfer.value.playPause();
}
/* 设置开始时间 */
function setStart(current: number) {
if (table_data.value.length <= 0) {
start_time.value = 0;
} else {
// 重组二维数组
let res = table_data.value.map((item: any) => [item.start, item.end]);
/* 检测当前时间是否在二维数组中间 */
let isIn: any = _.some(res, (subArray) => {
let start = subArray[0];
let end = subArray[1];
return current >= start && current <= end;
});
if (isIn) {
// 在已分割的片段内
start_time.value = -1;
alert('不可切割');
} else {
// 不在分割的片段内,且获取start值
let obj = _.minBy(res, (subArray: any) => {
if (subArray[1] < current) {
return Math.abs(subArray[1] - current);
}
});
if (obj) {
start_time.value = obj[1];
} else {
start_time.value = 0;
}
}
}
return start_time.value;
}
/* 剪切 */
function cutMusic() {
wavesurfer.value.pause(); // 暂停播放
let current = wavesurfer.value.getCurrentTime();
let start = setStart(current);
if (start == -1) {
return false;
}
let _item = {
start: start,
end: current,
// content: contentEle.value,
content: `${formatTime(start)} 至 ${formatTime(current)}`,
color: 'hsla(200, 50%, 70%, 0.4)',
drag: false,
resize: false
};
console.log(wsRegions.value, '---------');
wsRegions.value.addRegion(_item);
table_data.value = wsRegions.value.regions;
}
function drawRegion() {
table_data.value.forEach((item: any) => {
wsRegions.value.addRegion(item);
});
}
function delRegions(id: string) {
table_data.value = table_data.value.filter((item: any) => item.id != id);
wsRegions.value.clearRegions();
wsRegions.value.regions = [];
drawRegion();
}
function currentPlay(start: number, end: number) {
ws_regions_end.value = end;
wavesurfer.value.setTime(start);
wavesurfer.value.play();
}
async function makedata(res: any, current: number, flag: 'prev' | 'next') {
let index = res.indexOf(current);
if (index == -1) return;
if (flag == 'prev') {
if (index == 0) {
alert('无上一个切割位置');
return;
}
wavesurfer.value.setTime(res[index - 1]);
wavesurfer.value.isPlaying() ? wavesurfer.value.play() : wavesurfer.value.pause();
} else {
if (index == res.length - 1) {
alert('无下一个切割位置');
return;
}
wavesurfer.value.setTime(res[index + 1]);
wavesurfer.value.isPlaying() ? wavesurfer.value.play() : wavesurfer.value.pause();
}
}
async function changeTime(flag: 'prev' | 'next') {
let current = wavesurfer.value.getCurrentTime();
let res: any = [current];
table_data.value.map((item: any) => {
if (res.indexOf(item.start) == -1) {
res.push(item.start);
}
if (res.indexOf(item.end) == -1) {
res.push(item.end);
}
});
res.sort(function (a: any, b: any) {
return a - b;
});
await makedata(res, current, flag);
}
onMounted(() => {
nextTick(() => {
init();
wavesurfer.value.on('audioprocess', () => {
current_time.value = formatTime(wavesurfer.value.getCurrentTime());
if (ws_regions_end.value !== null && wavesurfer.value.getCurrentTime() >= ws_regions_end.value - 0.1) {
wavesurfer.value.pause(); // 暂停播放
wavesurfer.value.setTime(ws_regions_end.value);
current_time.value = formatTime(ws_regions_end.value);
ws_regions_end.value = null;
}
});
wavesurfer.value.on('ready', function () {
duration_time.value = formatTime(wavesurfer.value.getDuration());
});
});
});
</script>
未解决问题:
区域 wsRegions的content值。官方文档提示可接收string和HTMLElement两种格式。但在插入HTMLElement格式时只显示最后一次添加的内容。(有没有童鞋知道为什么呢?)