Heim >Web-Frontend >View.js >Bringen Sie Ihnen Schritt für Schritt bei, wie Sie mit Vue3 einen Player schreiben
Dieser Artikel vermittelt Ihnen relevantes Wissen über Vue3. Es geht hauptsächlich darum, wie man einen Player mit Vue3 schreibt. Ich hoffe, dass er für alle hilfreich ist.
ps: Musik kann möglicherweise nicht abgespielt werden. Der Grund dafür ist, dass die Audioverbindung temporär ist und manuell ersetzt werden kann.
TODO
css
-Stil sind wie folgt<template> <div class="song-item"> <audio src="" /> <!-- 进度条 --> <div class="audio-player"> <span>00:00</span> <div class="progress-wrapper"> <div class="progress-inner"> <div class="progress-dot" /> </div> </div> <span>00:00</span> <!-- 播放/暂停 --> <div style="margin-left: 10px; color: #409eff; cursor: pointer;" > 播放 </div> </div> </div></template><style lang="scss"> * { font-size: 14px; } .song-item { display: flex; flex-direction: column; justify-content: center; height: 100px; padding: 0 20px; transition: all ease .2s; border-bottom: 1px solid #ddd; /* 进度条样式 */ .audio-player { display: flex; height: 18px; margin-top: 10px; align-items: center; font-size: 12px; color: #666; .progress-wrapper { flex: 1; height: 4px; margin: 0 20px 0 20px; border-radius: 2px; background-color: #e9e9eb; cursor: pointer; .progress-inner { position: relative; width: 0%; height: 100%; border-radius: 2px; background-color: #409eff; .progress-dot { position: absolute; top: 50%; right: 0; z-index: 1; width: 10px; height: 10px; border-radius: 50%; background-color: #409eff; transform: translateY(-50%); } } } } }</style>
css
样式如下
const audioIsPlaying = ref(false); // 用于同步当前的播放状态const audioEle = ref<HTMLAudioElement | null>(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'); });
思路:给 ”播放“ 注册点击事件,在点击事件中通过
audio
的属性及方法来判定当前歌曲是什么状态,是否播放或暂停,然后声明一个属性同步这个状态,在模板中做出判断当前应该显示 ”播放/暂停“。关键性 api:
audio.paused
:当前播放器是否为暂停状态
audio.play()
:播放
audio.pause()
:暂停
<div style="margin-left: 10px; color: #409eff; cursor: pointer;" @click="togglePlayer"> {{ audioIsPlaying ? '暂停' : '播放'}}</div>
最后把属性及事件应用到模板中去。
import dayjs from 'dayjs';const audioCurrentPlayTime = ref('00:00'); // 当前播放时长const audioCurrentPlayCountTime = ref('00:00'); // 总时长const pgsInnerEle = ref<HTMLDivElement | null>(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); });
思路:获取当前已经播放的时间及总时长,然后再拿当前时长 / 总时长及得到歌曲播放的百分比即滚动条的百分比。通过侦听
audio
元素的timeupdate
事件以做到每次当前时间改变时,同步把 DOM 也进行更新。最后播放完成后把状态初始化。关键性api:
audio.currentTime
:当前的播放时间;单位(s)
audio.duration
:音频的总时长;单位(s)
timeupdate
:currentTime
变更时会触发该事件。
/** * @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); });
思路:给滚动条注册鼠标点击事件,每次点击的时候获取当前的
offsetX
以及滚动条的宽度,用宽度 /offsetX
最后用总时长 * 前面的商就得到了我们想要的进度,再次更新进度条即可。关键性api:
event.offsetX
:鼠标指针相较于触发事件对象的 x 坐标。
/** * @method useSongProgressDrag * @param audioEle * @param pgsWrapperEle * @param updateProgress 更新滚动条方法 * @param startSongDragDot 是否开启拖拽滚动 * @description 拖拽更新歌曲播放进度 */const useSongProgressDrag = ( audioEle: Ref<HTMLAudioElement | null>, pgsWrapperEle: Ref<HTMLDivElement | null>, updateProgress: () => void, startSongDragDot: Ref<boolean>) => { const audioPlayer = ref<HTMLDivElement | null>(null); const audioDotEle = ref<HTMLDivElement | null>(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
管理这个拖动的功能,侦听这个滚动条的 鼠标点击、鼠标移动、鼠标抬起事件。点击时: 获取鼠标在窗口的
x
坐标,圆点距离窗口的left
距离及最大的右移距离(滚动条宽度 - 圆点距离窗口的left
)。为了让移动式不随便开始计算,在开始的时候可以弄一个开关flag
移动时: 实时获取鼠标在窗口的
x
坐标减去 点击时获取的x
坐标。然后根据最大移动距离做出判断,不要让它越界。最后: 总时长 * (圆点距离窗口的left
+ 计算得出的x
/ 滚动条长度) 得出百分比更新滚动条及进度抬起时:将
flag
重置。
// 是否显示可拖拽 dot// 可以在原点元素上增加 v-if 用来判定是否需要拖动功能const startSongDragDot = ref(true);useSongProgressDrag(audioEle, pgsWrapperEle, updateProgress, startSongDragDot);
最后调用这个 hook
Idee: Registrieren Sie ein Klickereignis für „play“, verwenden Sie im Click-Ereignis die Attribute und Methoden von audio
, um den Status des aktuellen Songs zu bestimmen, ob er abgespielt oder pausiert wird, deklarieren Sie dann ein Attribut, um diesen Status zu synchronisieren, und erstellen Sie ein Urteil in der Vorlage, dass das aktuelle Lied „Play/Pause“ anzeigen soll.
Schlüssel-API: audio.paused
: Ob der aktuelle Player angehalten ist
audio.play()
: Wiedergabe 🎜🎜audio.pause ()
: Pause🎜🎜rrreee🎜Zuletzt Attribute und Ereignisse auf die Vorlage anwenden. 🎜rrreeetimeupdate
-Ereignisses des audio
-Elements wird das DOM jedes Mal, wenn sich die aktuelle Zeit ändert, auch synchron aktualisiert. Nachdem die endgültige Wiedergabe abgeschlossen ist, wird der Status initialisiert. 🎜🎜Schlüssel-API: 🎜🎜audio.currentTime
: aktuelle Wiedergabezeit(en) 🎜🎜audio.duration
: Gesamtdauer der Audioeinheit(en) 🎜🎜 timeupdate
: Dieses Ereignis wird ausgelöst, wenn sich currentTime
ändert. 🎜🎜rrreeeoffsetX
klicken, und die Breite der Bildlaufleiste, verwenden Sie width / offsetX
und verwenden Sie schließlich die Gesamtdauer *, um den gewünschten Fortschritt zu erhalten, und aktualisieren Sie einfach den Fortschritt Bar wieder. 🎜🎜Schlüssel-API: 🎜🎜event.offsetX
: Die x-Koordinate des Mauszeigers im Vergleich zum auslösenden Ereignisobjekt. 🎜🎜rrreeehook
, um diese Ziehfunktion zu verwalten und die Mausklick-, Mausbewegungs- und Maushubereignisse dieser Bildlaufleiste abzuhören. 🎜🎜Beim Klicken: Erhalten Sie die x
-Koordinaten der Maus im Fenster, den Abstand zwischen dem Punkt und der linken
des Fensters und die maximale Rechtsbewegungsentfernung (Bildlaufleiste). Breite – der Abstand zwischen dem Punkt und dem Fenster) links
). Um zu verhindern, dass das Mobiltelefon versehentlich mit der Berechnung beginnt, können Sie zu Beginn einen Schalter flag
setzen🎜🎜Beim Bewegen: Holen Sie sich die x
-Koordinaten der Maus im Fenster Echtzeit abzüglich des Klicks. Die x
-Koordinate von . Treffen Sie dann eine Beurteilung auf der Grundlage der maximalen Bewegungsdistanz und lassen Sie nicht zu, dass die Grenze überschritten wird. Schließlich: Gesamtdauer * (Punktabstand von links
des Fensters + berechnetes x
/ Länge der Bildlaufleiste) Der Prozentsatz wird ermittelt, um die Bildlaufleiste und den Fortschritt beim Anheben zu aktualisieren :Flag
zurücksetzen. 🎜🎜rrreee🎜Rufen Sie diesen Hook
endlich auf 🎜rrreee🎜[Verwandte Empfehlung: 🎜vue.js Video-Tutorial🎜]🎜🎜Das obige ist der detaillierte Inhalt vonBringen Sie Ihnen Schritt für Schritt bei, wie Sie mit Vue3 einen Player schreiben. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!