vue 循環(huán)多個audio播放器,點擊一個播放其它暫停

需求:封裝一個音樂播放器組件,并在同一個頁面多次引入,播放其中一個時其它暫停播放,效果圖如下:
1

1.播放器的代碼可以直接參考Vue 實現(xiàn)音樂播放器,上圖樣式是稍微改了下的,看的更順眼點。
2.為了解決點擊一個播放其它暫停(指的是按鈕變回暫停),目前做法是通過父頁面的數(shù)據(jù)設(shè)置一個isPlay進行控制,當組件播放狀態(tài)進行變化時,修改數(shù)據(jù)的isPlay達到修改組件按鈕狀態(tài)的目的。
3.遇到的另一個問題是,滑塊拖動進度條問題,滑塊拖動成功,但是進度設(shè)置無效。解決方法可以看這里vue實現(xiàn)audio進度拖拽播放及拖拽播放問題解決

原因:
2
解決方式:
3
對應(yīng)本文的代碼就是:
4

5
完整代碼
父頁面引用
<template>
  <div style="margin-top: 10px" v-for="(item, index) in list" :key="index">
     音樂{{ index }}
     <audioPlayer
       :audioSrc="item.src"
       :id="index"
       :isPlay="item.isPlay"
       @changSatus="changSatus"
     />
  </div>
</template>

<script>
 import audioPlayer from '@/components/audioPlayer/index'
  export default {
    components: {
      audioPlayer,
    },
    data() {
      return {
        list: [
          {
            src: 'xxx', // 音頻路徑
            isPlay: false, // 播放狀態(tài)
          },
          {
            src: 'xxx',
            isPlay: false,
          },
          {
            src: 'xxx',
            isPlay: false,
          },
        ],
      }
    },
    methods: {
      // 子組件傳回當前點擊的播放器狀態(tài),其它音頻的播放狀態(tài)全部設(shè)置為暫停
      changSatus(index, status) {
        this.list.forEach((item, i) => {
          if (i === index) {
            this.$set(this.list[index], 'isPlay', status)
          } else {
            this.$set(this.list[i], 'isPlay', false)
          }
        })
      },
    },
  }
</script>
組件頁
<template>
  <div class="audio-player-box">
    <el-row :gutter="10">
      <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="3">
        <div class="play-btn-box">
          <i
            class="play-btn"
            :class="isPlay ? 'el-icon-video-pause' : 'el-icon-video-play'"
            @click="musicPlay()"
          ></i>
        </div>
      </el-col>
      <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="16">
        <div
          class="slider-box"
          @mousedown="isDraging = true"
          @mouseup="isDraging = false"
        >
          <el-slider
            v-model="sliderVal"
            :format-tooltip="formatTooltip"
            :min="sliderMin"
            :max="sliderMax"
            @change="spliderSelect"
          />
        </div>
      </el-col>
      <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="5">
        {{ currentTime }} / {{ duration }}
      </el-col>
    </el-row>
    <audio
      :ref="`singeBox_${id}`"
      class="audio"
      controls
      :src="src"
      style="display: none"
    >
      <source src="horse.mp3" type="audio/mpeg" />
      您的瀏覽器不支持 audio 元素。
    </audio>
  </div>
</template>

<script>
  export default {
    name: 'AudioPlayer',
    props: {
      audioSrc: {
        // 音頻路徑
        type: String,
        default: '',
      },
      id: {
        // 標識
        type: Number,
        default: 1,
      },
      isPlay: {
        // 是否正在播放
        type: Boolean,
        default: false,
      },
    },
    watch: {
      isPlay(newV, oldV) {
        this.play = newV ? true : false
      },
    },
    data() {
      return {
        box: {}, // audio對象
        src: '', // 播放地址
        duration: '00:00', // 音樂總時長
        currentTime: '00:00', // 當前播放時長
        sliderVal: 0, // 這個對接當前時長。
        sliderMin: 0,
        sliderMax: 0, // 這個對接總時長。
        index: 0, // 當前播放的音樂素質(zhì)索引
        play: false, // 播放狀態(tài),true為正在播放
        isDraging: false, // 設(shè)置拖動修改的時機
      }
    },
    mounted() {
      const _this = this
      this.src = this.audioSrc
      this.$nextTick(() => {
        _this.init()
      })
    },
    methods: {
      init() {
        const _that = this
        this.box = this.$refs['singeBox_' + this.id]
        // 綁定三個觸發(fā)方法
        // 當時長有變化時觸發(fā),由"NaN"變?yōu)閷嶋H時長也算
        this.box.ondurationchange = function () {
          console.log('時長發(fā)生了變化')
          _that.updateTime()
        }
        // 當前數(shù)據(jù)可用是觸發(fā)
        this.box.oncanplay = function () {
          console.log('已經(jīng)可以播放了')
        }
        // 播放位置發(fā)送改變時觸發(fā)。
        this.box.ontimeupdate = function () {
          console.log('播放位置發(fā)送了變動')
          _that.updateTime()
        }
        // 音頻播放完畢
        this.box.onended = function () {
          // console.log('播放完畢,謝謝收聽')
        }
        // 音頻播放完畢
        this.box.onerror = function () {
          // console.log('加載出錯!')
        }
      },
      updateTime() {
        if (!this.isDraging) {
          const total = this.formatTime(this.box.duration)
          const current = this.formatTime(this.box.currentTime)
          this.duration = `${total.min}:${total.sec}`
          this.currentTime = `${current.min}:${current.sec}`
          this.sliderMax = this.box.duration
          // 值為xx.xxxxx 需要取整
          this.sliderVal = Math.floor(this.box.currentTime)
        }
      },
      formatTime(time) {
        // 格式化毫秒,返回String型分秒對象
        // 有可能沒獲取到,為NaN
        if (!time) return { min: '00', sec: '00' }
        return {
          min: Math.floor(time / 60)
            .toString()
            .padStart(2, '0'),
          sec: Math.floor(time % 60)
            .toString()
            .padStart(2, '0'),
        }
      },
      formatTooltip(val) {
        // 格式化毫秒數(shù),由于組件提示為純數(shù)字,所以這里需要將數(shù)字轉(zhuǎn)化為我們所需要的的格式,string類型的。'03:45',
        const time = this.formatTime(val)
        return `${time.min}:${time.sec}`
      },
      spliderSelect() {
        // 滑塊松動后觸發(fā)。更新當前時長,
        // 時長發(fā)生變動會init里的方法進行更新數(shù)據(jù)
        this.box.currentTime = this.sliderVal
      },
      musicPlay() {
        this.play = !this.play
        if (this.play) {
          const audios = document.getElementsByTagName('audio')
          ;[].forEach.call(audios, function (i, index) {
            if (i !== audioDom) {
              i.pause()
              // i.currentTime = 0
            }
          })
          let audioDom = this.$refs['singeBox_' + this.id]
          audioDom.play()
          this.$emit('changSatus', this.id, true)
        } else {
          this.box.pause()
          this.$emit('changSatus', this.id, false)
        }
      },
    },
  }
</script>

<style lang="scss" scope>
  .audio-player-box {
    width: 500px;
    height: 50px;
    line-height: 50px;
    border: 1px solid #ccc;
    .play-btn-box {
      text-align: center;
      .play-btn {
        display: inline-block;
        width: 20px;
        height: 20px;
        font-size: 30px;
        cursor: pointer;
        color: #409eff;
        line-height: 50px;
      }
    }

    .slider-box {
      position: relative;
      top: 6px;
    }
  }
</style>

如果有更好的實現(xiàn)方式,歡迎留言探討。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容