(资料图片)
TODO
实现播放/暂停;实现开始/结束时间及开始时间和滚动条动态跟随播放动态变化;实现点击进度条跳转指定播放位置;实现点击圆点拖拽滚动条。页面布局及 css
样式如下
00:00 00:00 播放
登录后复制
实现播放/暂停
const audioIsPlaying = ref(false); // 用于同步当前的播放状态const audioEle = ref(null); // audio 元素/** * @description 播放/暂停音乐 */const togglePlayer = () => { if (audioEle.value) { if (audioEle.value?.paused) { audioEle.value.play(); audioIsPlaying.value = true; } else { audioEle.value?.pause(); audioIsPlaying.value = false; } }};onMounted(() => { // 页面点击的时候肯定是加载完成了,这里获取一下没毛病 audioEle.value = document.querySelector("audio");});
登录后复制
最后把属性及事件应用到模板中去。
{{ audioIsPlaying ? "暂停" : "播放"}}
登录后复制
实现开始/结束时间及开始时间和滚动条动态跟随播放动态变化
import dayjs from "dayjs";const audioCurrentPlayTime = ref("00:00"); // 当前播放时长const audioCurrentPlayCountTime = ref("00:00"); // 总时长const pgsInnerEle = ref(null);/** * @description 更新进度条与当前播放时间 */const updateProgress = () => { const currentProgress = audioEle.value!.currentTime / audioEle.value!.duration; pgsInnerEle.value!.style.width = `${currentProgress * 100}%`; // 设置进度时长 if (audioEle.value) audioCurrentPlayTime.value = dayjs(audioEle.value.currentTime * 1000).format("mm:ss");};/** * @description 播放完成重置播放状态 */const audioPlayEnded = () => { audioCurrentPlayTime.value = "00:00"; pgsInnerEle.value!.style.width = "0%"; audioIsPlaying.value = false;};onMounted(() => { pgsInnerEle.value = document.querySelector(".progress-inner"); // 设置总时长 if (audioEle.value) audioCurrentPlayCountTime.value = dayjs(audioEle.value.duration * 1000).format("mm:ss"); // 侦听播放中事件 audioEle.value?.addEventListener("timeupdate", updateProgress, false); // 播放结束 event audioEle.value?.addEventListener("ended", audioPlayEnded, false);});
登录后复制
实现点击进度条跳转指定播放位置
/** * @description 点击滚动条同步更新音乐进度 */const clickProgressSync = (event: MouseEvent) => { if (audioEle.value) { // 保证是正在播放或者已经播放的状态 if (!audioEle.value.paused || audioEle.value.currentTime !== 0) { const pgsWrapperWidth = pgsWrapperEle.value!.getBoundingClientRect().width; const rate = event.offsetX / pgsWrapperWidth; // 同步滚动条和播放进度 audioEle.value.currentTime = audioEle.value.duration * rate; updateProgress(); } }};onMounted({ pgsWrapperEle.value = document.querySelector(".progress-wrapper"); // 点击进度条 event pgsWrapperEle.value?.addEventListener("mousedown", clickProgressSync, false);});// 别忘记统一移除侦听onBeforeUnmount(() => { audioEle.value?.removeEventListener("timeupdate", updateProgress); audioEle.value?.removeEventListener("ended", audioPlayEnded); pgsWrapperEle.value?.removeEventListener("mousedown", clickProgressSync);});
登录后复制
实现点击圆点拖拽滚动条。
/** * @method useSongProgressDrag * @param audioEle * @param pgsWrapperEle * @param updateProgress 更新滚动条方法 * @param startSongDragDot 是否开启拖拽滚动 * @description 拖拽更新歌曲播放进度 */const useSongProgressDrag = ( audioEle: Ref, pgsWrapperEle: Ref, updateProgress: () => void, startSongDragDot: Ref) => { const audioPlayer = ref(null); const audioDotEle = ref(null); const dragFlag = ref(false); const position = ref({ startOffsetLeft: 0, startX: 0, maxLeft: 0, maxRight: 0, }); /** * @description 鼠标点击 audioPlayer */ const mousedownProgressHandle = (event: MouseEvent) => { if (audioEle.value) { if (!audioEle.value.paused || audioEle.value.currentTime !== 0) { dragFlag.value = true; position.value.startOffsetLeft = audioDotEle.value!.offsetLeft; position.value.startX = event.clientX; position.value.maxLeft = position.value.startOffsetLeft; position.value.maxRight = pgsWrapperEle.value!.offsetWidth - position.value.startOffsetLeft; } } event.preventDefault(); event.stopPropagation(); }; /** * @description 鼠标移动 audioPlayer */ const mousemoveProgressHandle = (event: MouseEvent) => { if (dragFlag.value) { const clientX = event.clientX; let x = clientX - position.value.startX; if (x > position.value.maxRight) x = position.value.maxRight; if (x < -position.value.maxLeft) x = -position.value.maxLeft; const pgsWidth = pgsWrapperEle.value?.getBoundingClientRect().width; const reat = (position.value.startOffsetLeft + x) / pgsWidth!; audioEle.value!.currentTime = audioEle.value!.duration * reat; updateProgress(); } }; /** * @description 鼠标取消点击 */ const mouseupProgressHandle = () => dragFlag.value = false; onMounted(() => { if (startSongDragDot.value) { audioPlayer.value = document.querySelector(".audio-player"); audioDotEle.value = document.querySelector(".progress-dot"); // 在捕获中去触发点击 dot 事件. fix: 点击原点 offset 回到原点 bug audioDotEle.value?.addEventListener("mousedown", mousedownProgressHandle, true); audioPlayer.value?.addEventListener("mousemove", mousemoveProgressHandle, false); document.addEventListener("mouseup", mouseupProgressHandle, false); } }); onBeforeUnmount(() => { if (startSongDragDot.value) { audioPlayer.value?.removeEventListener("mousedown", mousedownProgressHandle); audioPlayer.value?.removeEventListener("mousemove", mousemoveProgressHandle); document.removeEventListener("mouseup", mouseupProgressHandle); } });};
登录后复制
最后调用这个 hook
// 是否显示可拖拽 dot// 可以在原点元素上增加 v-if 用来判定是否需要拖动功能const startSongDragDot = ref(true);useSongProgressDrag(audioEle, pgsWrapperEle, updateProgress, startSongDragDot);
登录后复制
【相关推荐:vue.js视频教程】
以上就是手把手教你用Vue3写播放器的详细内容,更多请关注php中文网其它相关文章!