147 lines
4.1 KiB
Vue
147 lines
4.1 KiB
Vue
<script setup lang="ts">
|
||
import WaveSurfer from "wavesurfer.js";
|
||
import { getTime } from "@pureadmin/utils";
|
||
import { Play, Pause, Forward, Rewind } from "./svg";
|
||
import { ref, onMounted, onBeforeUnmount } from "vue";
|
||
|
||
defineOptions({
|
||
name: "Wavesurfer"
|
||
});
|
||
|
||
const loading = ref(true);
|
||
const wavesurfer = ref(null);
|
||
const wavesurferRef = ref();
|
||
// 音频总时长(格式化后 mm:ss)
|
||
const totalTime = ref();
|
||
// 音频总时长(单位秒)
|
||
const totalSecondTime = ref();
|
||
// 音频当前播放位置时长
|
||
const curTime = ref();
|
||
// 音频是否正在播放
|
||
const isPlay = ref(false);
|
||
|
||
const { VITE_PUBLIC_PATH } = import.meta.env;
|
||
const url = `${VITE_PUBLIC_PATH}audio/海阔天空.mp3`;
|
||
|
||
function init() {
|
||
wavesurfer.value = WaveSurfer.create({
|
||
container: wavesurferRef.value,
|
||
height: "auto",
|
||
waveColor: "rgb(200, 0, 200)",
|
||
progressColor: "rgb(100, 0, 100)",
|
||
cursorColor: "rgb(64, 158, 255)",
|
||
cursorWidth: 4,
|
||
// backend: "MediaElement",
|
||
url
|
||
});
|
||
|
||
// 音频被解码后触发
|
||
wavesurfer.value.on("decode", () => (loading.value = false));
|
||
|
||
// 当音频已解码并可以播放时触发
|
||
wavesurfer.value.on("ready", () => {
|
||
if (!wavesurfer.value) return;
|
||
const { decodedData } = wavesurfer.value;
|
||
totalSecondTime.value = decodedData.duration;
|
||
const { m, s } = getTime(decodedData.duration);
|
||
totalTime.value = `${m}:${s}`;
|
||
// 光标位置取中
|
||
wavesurfer.value.setTime(decodedData.duration / 2);
|
||
// 设置音频音量(范围0-1)
|
||
// wavesurfer.value.setVolume(1);
|
||
});
|
||
|
||
// 音频位置改变时,播放期间连续触发
|
||
wavesurfer.value.on("timeupdate", timer => {
|
||
if (timer > totalSecondTime.value) return;
|
||
const { m, s } = getTime(timer);
|
||
curTime.value = `${m}:${s}`;
|
||
});
|
||
|
||
// 音频播放时触发
|
||
wavesurfer.value.on("play", () => (isPlay.value = true));
|
||
|
||
// 音频暂停时触发
|
||
wavesurfer.value.on("pause", () => (isPlay.value = false));
|
||
}
|
||
|
||
onMounted(init);
|
||
|
||
onBeforeUnmount(() => {
|
||
if (wavesurfer.value) {
|
||
wavesurfer.value.destroy();
|
||
wavesurfer.value = null;
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<el-card shadow="never">
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span class="font-medium">
|
||
音频可视化,采用开源的
|
||
<el-link
|
||
href="https://wavesurfer-js.org/"
|
||
target="_blank"
|
||
style="margin: 0 4px 5px; font-size: 16px"
|
||
>
|
||
wavesurfer.js
|
||
</el-link>
|
||
<span class="text-[red]">
|
||
(温馨提示:音频默认最大声音,播放时请调低电脑声音,以免影响到您)
|
||
</span>
|
||
</span>
|
||
</div>
|
||
<el-link
|
||
class="mt-2"
|
||
href="https://github.com/pure-admin/vue-pure-admin/blob/main/src/views/able/wavesurfer"
|
||
target="_blank"
|
||
>
|
||
代码位置 src/views/able/wavesurfer
|
||
</el-link>
|
||
</template>
|
||
<div
|
||
v-loading="loading"
|
||
class="w-8/12 !m-auto !mt-[20px]"
|
||
element-loading-background="transparent"
|
||
>
|
||
<div ref="wavesurferRef" />
|
||
<div v-show="totalTime" class="flex justify-between">
|
||
<span class="text-[#81888f]">00:00</span>
|
||
<h1 class="text-4xl mt-2">{{ curTime }}</h1>
|
||
<span class="text-[#81888f]">{{ totalTime }}</span>
|
||
</div>
|
||
<div v-show="totalTime" class="flex mt-2 w-[180px] justify-around m-auto">
|
||
<Rewind
|
||
v-tippy="{
|
||
content: '快退(可长按)',
|
||
placement: 'bottom'
|
||
}"
|
||
v-longpress:0:100="() => wavesurfer?.skip(-1)"
|
||
class="cursor-pointer"
|
||
/>
|
||
<div
|
||
v-tippy="{
|
||
content: isPlay ? '暂停' : '播放',
|
||
placement: 'bottom'
|
||
}"
|
||
class="cursor-pointer"
|
||
@click="wavesurfer?.playPause()"
|
||
>
|
||
<Play v-if="isPlay" v-motion-pop />
|
||
<Pause v-else v-motion-pop />
|
||
</div>
|
||
<Forward
|
||
v-tippy="{
|
||
content: '快进(可长按)',
|
||
placement: 'bottom'
|
||
}"
|
||
v-longpress:0:100="() => wavesurfer?.skip(1)"
|
||
class="cursor-pointer"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</el-card>
|
||
</template>
|