您好,欢迎访问一九零五行业门户网

手把手教你用Vue3写播放器

本篇文章给大家带来了关于vue3的相关知识,其中主要跟大家聊一聊怎么用vue3写个播放器,感兴趣的朋友下面一起来看一下吧,希望对大家有帮助。
ps:音乐可能播放失败。原因是 audio 的链接是临时的,手动替换下即可。
todo
实现播放/暂停;实现开始/结束时间及开始时间和滚动条动态跟随播放动态变化;实现点击进度条跳转指定播放位置;实现点击圆点拖拽滚动条。页面布局及 css 样式如下
<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>
实现播放/暂停思路:给 ”播放“ 注册点击事件,在点击事件中通过 audio 的属性及方法来判定当前歌曲是什么状态,是否播放或暂停,然后声明一个属性同步这个状态,在模板中做出判断当前应该显示 ”播放/暂停“。
关键性 api:
audio.paused:当前播放器是否为暂停状态
audio.play():播放
audio.pause():暂停
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');});
最后把属性及事件应用到模板中去。
<div style="margin-left: 10px; color: #409eff; cursor: pointer;" @click="toggleplayer">   {{ audioisplaying ? '暂停' : '播放'}}</div>
实现开始/结束时间及开始时间和滚动条动态跟随播放动态变化思路:获取当前已经播放的时间及总时长,然后再拿当前时长 / 总时长及得到歌曲播放的百分比即滚动条的百分比。通过侦听 audio 元素的 timeupdate 事件以做到每次当前时间改变时,同步把 dom 也进行更新。最后播放完成后把状态初始化。
关键性api:
audio.currenttime:当前的播放时间;单位(s)
audio.duration:音频的总时长;单位(s)
timeupdate:currenttime 变更时会触发该事件。
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);});
实现点击进度条跳转指定播放位置思路:给滚动条注册鼠标点击事件,每次点击的时候获取当前的 offsetx 以及滚动条的宽度,用宽度 / offsetx 最后用总时长 * 前面的商就得到了我们想要的进度,再次更新进度条即可。
关键性api:
event.offsetx:鼠标指针相较于触发事件对象的 x 坐标。
/** * @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);});
实现点击圆点拖拽滚动条。思路:使用 hook 管理这个拖动的功能,侦听这个滚动条的 鼠标点击、鼠标移动、鼠标抬起事件。
点击时: 获取鼠标在窗口的 x 坐标,圆点距离窗口的 left 距离及最大的右移距离(滚动条宽度 - 圆点距离窗口的 left)。为了让移动式不随便开始计算,在开始的时候可以弄一个开关 flag
移动时: 实时获取鼠标在窗口的 x 坐标减去 点击时获取的 x 坐标。然后根据最大移动距离做出判断,不要让它越界。最后: 总时长 * (圆点距离窗口的 left + 计算得出的 x / 滚动条长度) 得出百分比更新滚动条及进度
抬起时:将 flag 重置。
/** * @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
// 是否显示可拖拽 dot// 可以在原点元素上增加 v-if 用来判定是否需要拖动功能const startsongdragdot = ref(true);usesongprogressdrag(audioele, pgswrapperele, updateprogress, startsongdragdot);
【相关推荐:vue.js视频教程】
以上就是手把手教你用vue3写播放器的详细内容。
其它类似信息

推荐信息