Rumah  >  Artikel  >  hujung hadapan web  >  Ajar anda langkah demi langkah cara menulis pemain menggunakan Vue3

Ajar anda langkah demi langkah cara menulis pemain menggunakan Vue3

藏色散人
藏色散人ke hadapan
2023-03-03 15:53:432281semak imbas

Artikel ini membawakan anda pengetahuan yang berkaitan tentang Vue3 terutamanya tentang cara menulis pemain dengan Vue3. Rakan yang berminat boleh melihatnya bersama-sama.

ps: Muzik mungkin gagal dimainkan. Sebabnya ialah pautan audio bersifat sementara dan boleh diganti secara manual.

TODO

  • Menyedari main/jeda; lompat ke Kedudukan main balik yang ditentukan;
  • Klik titik untuk menyeret bar skrol.
  • Susun atur halaman dan gaya
  • adalah seperti berikut

Realisasikan main/jedacss

<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>
Idea: Daftar acara klik untuk "Main ", dalam Dalam acara klik, gunakan atribut dan kaedah

untuk menentukan status lagu semasa, sama ada untuk memainkan atau menjeda, kemudian mengisytiharkan atribut untuk menyegerakkan status ini dan membuat pertimbangan dalam templat bahawa " main/jeda" hendaklah dipaparkan.

Api kekunci:

audio

: Sama ada pemain semasa dijeda

: Bermainaudio.paused

: Dijedaaudio.play()

audio.pause()Akhir sekali, gunakan atribut dan acara pada templat.

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');
});
Realisasikan masa mula/tamat, masa mula dan bar skrol untuk mengikuti dinamik main balik secara dinamik

<div 
  style="margin-left: 10px; color: #409eff; cursor: pointer;"
  @click="togglePlayer"> 
  {{ audioIsPlaying ? '暂停' : '播放'}}</div>
Idea: Dapatkan masa main semasa dan jumlah tempoh, dan kemudian dapatkan Tempoh semasa / jumlah tempoh dan peratusan main balik lagu ialah peratusan bar skrol. Dengan mendengar acara

elemen

, setiap kali masa semasa berubah, DOM juga dikemas kini secara serentak. Selepas main balik terakhir selesai, keadaan dimulakan.

Api kunci: audiotimeupdate

: masa main balik semasa; 🎜>

: Acara ini akan dicetuskan apabila

berubah.

audio.currentTime

Sedari mengklik pada bar kemajuan untuk melompat ke kedudukan main balik yang ditentukanaudio.duration

Idea: daftarkan acara klik tetikus untuk bar skrol, dan dapatkan semasa satu setiap kali ia dikliktimeupdate Dan lebar bar skrol, gunakan lebar / currentTime Akhir sekali, gunakan jumlah tempoh * Hasil bagi sebelumnya akan mendapat kemajuan yang kita mahu, cuma kemas kini bar kemajuan sekali lagi.

Api kekunci:
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);
});

: Koordinat x penuding tetikus berbanding objek yang mencetuskan acara.

offsetXoffsetXKlik titik untuk menyeret bar skrol.

Idea: Gunakan

untuk mengurus fungsi menyeret dan mendengar klik tetikus, pergerakan tetikus dan peristiwa angkat tetikus pada bar skrol ini. Apabila event.offsetX

diklik: Dapatkan
koordinat tetikus dalam tetingkap, jarak
/**
 * @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);
});
titik dari tetingkap dan jarak pergerakan kanan maksimum (lebar bar tatal -

daripada jarak titik dari tingkap). Untuk mengelakkan mudah alih daripada memulakan pengiraan secara santai, anda boleh menetapkan suis pada permulaan

Apabila bergerak: Dapatkan hook koordinat tetikus dalam tetingkap dalam masa nyata tolak

koordinat diperoleh apabila mengklik. Kemudian buat pertimbangan berdasarkan jarak pergerakan maksimum dan jangan biarkan ia melampaui batas. Akhir sekali: Jumlah tempoh * (tetingkap jarak titik

+ dikira x / panjang bar skrol) untuk mendapatkan peratusan untuk mengemas kini bar skrol dan kemajuan left Apabila left dinaikkan: Tetapkan semula flag Tetapkan.

xxAkhirnya panggil ini leftx

[Cadangan berkaitan: flagtutorial video vue.js

]
/**
 * @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);
    }
  });
};

Atas ialah kandungan terperinci Ajar anda langkah demi langkah cara menulis pemain menggunakan Vue3. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.im. Jika ada pelanggaran, sila hubungi admin@php.cn Padam