VUE練手項目實現音樂播放器(四)------- 播放控制組件

2020.3.31 9:18 html

好的,早上好各位,今天咱們來進行一個很炫酷的頁面開發——播放器控制頁面( src\components\Play.vue ),以下圖:vue

                                         

完成目標:正則表達式

一、歌曲上半部分圖片封面及隱藏頁面按鈕佈局算法

二、設計播放進度條數組

三、歌詞顯示ide

四、播放控制按鈕佈局

 

咱們能夠看到,這些元素完美的結合在一塊兒,整個頁面有沒有一種很高大上的感受!好了,讓咱們來親自動手實現它吧!this

 

一、 歌曲封面&隱藏按鈕spa

首先經過 getters 獲取到歌曲的封面:設計

computed: {
  imgUrl: function() {
    return this.$store.getters.coverImgUrl                //PlayService.js 中的 Getters
  },
}

目前的 HTML 結構以下:

<div id="play" class="music-play-page">
  <div class="music-album">
    <div class="hide-icon">
      <img src="../assets/icon-jiantou.png">
    </div>
    <img v-lazy="imgUrl">
  </div>
 </div>

此時設置 CSS:

.music-play-page {
    width: 100%;
    max-width: 68vh;
    height: 100%;
    position: fixed;
    top: 0;
    z-index: 5;
  }

 

                                 

你會發現,儘管根元素 設置了 width:100% ,可是歌曲的封面仍然只有一點,寬度根本沒有填充到100%,上右圖。不要緊,只須要將 .music-album img 設置 width: 100% 便可,如上左圖。

緣由其實很簡單,父元素 width 設置了 100%,可是子元素的內容並無填充滿100%,爲了方便調試,咱們在這種狀況下,能夠先設置 父元素 的背景顏色,好比藍色,便可查看到父元素的 width 沒有問題, 就會意識到 是 子元素 的 width 不夠。

 

下一步,咱們來實現播放進度條,效果如圖:

 

 

 

實現起來很簡單,關鍵點是咱們須要一個 隨歌曲的播放時間的更新,而不斷更新的變量,做爲 進度條指針移動 的參考, 咱們將這個變量命名爲: indicatorPosition,

首先在 Vuex 裏獲取 currentTime(歌曲播放當前時間) 和 duration(歌曲時長),兩個變量的比,就是 indicatorPosition:

computed: {         //Vue計算屬性
  ...mapState({
    indicatorPosition: state => state.PlayService.currentTime / state.PlayService.duration * 100,         
  }),
}

 

有了 indicatorPosition,咱們就能夠進行下一步,在 組件中 添加 html

<div class="progress-bar-group">
<div class="progress-bar"> //進度條及紅色刻度 <div class="progress" :style="{width:indicatorPosition+'%'}"></div> //已播放部分進度條顏色加深 <div class="indicater" :style="{left:indicatorPosition+'%'}"></div> //紅色刻度移動代碼 </div> <div class="time-indicater"> <span>{{currentTime}}</span> //當前時間 <span>{{duration}}</span> //歌曲時長 </div> </div>

 

因爲QMplayer返回的時間是以秒爲單位,咱們須要在 PlayService.js 裏將秒轉化爲 --分 : --秒的形式,Vuex 的 getters 就至關於 Vue 的 computed(計算屬性)

getters: {
    currentTime: state =>
    parseInt(state.currentTime / 60) + ':' + (Array(2).join(0) + (state.currentTime % 60)).slice(-2) //Array(2).join(0) 表示兩個數組元素,以0做爲間隔,因此其輸出爲 ‘0’
    ,
    duration: state =>
    parseInt(state.duration / 60) + ':' + (Array(2).join(0) + (state.duration % 60)).slice(-2),
}

 

爲進度條部分添加 CSS :

.progress-bar-group {
    height: 30px;
}
  
.progress-bar-group .progress-bar {
    height: 4px;
    background: #cccccc;
    position: relative;
}
  
.progress-bar-group .progress-bar .progress {
    height: 100%;
    background: #7f7f7f;
    /*width: 20%;*/
}
  
.progress-bar-group .progress-bar .indicater {
    position: absolute;
    width: 2px;
    height: 12px;
    background: #ff2d55;
    top: 0;
    /*left: 20%;*/
}

 

此時,咱們的頁面效果:

                             

 

是否是已經有模有樣了呢,很好,下一步咱們接着完成播放控制按鈕。

 咱們用列表元素,將五個 控制按鈕陳列出來:

<div class="music-ctrl">
  <ul>
    <li><img src="../assets/icon-like.png"></li>
    <li><img src="../assets/icon-shangyiqu.png"></li>
    <li><img :src="playing?$parent.iconPause:$parent.iconPlay"></li>
    <li><img src="../assets/icon-xiayiqu.png"></li>
    <li><img src="../assets/icon-list.png"></li>
  </ul>
</div>

 

重點 CSS :

.music-ctrl ul li {
    float: left;        /*將按鈕排列成一行*/
    width: 20%;         /*設置每一個 按鈕 寬度均等*/
    height: 100%;
  }

.music-ctrl ul li img {
    display: block;
    width: 35px;       /*設置每一個按鈕大小*/
    margin: 0 auto;    /*設置每一個按鈕相對父元素框 居中顯示*/
  }

 

爲 播放上一曲 按鈕添加 事件點擊:

<li><img src="../assets/icon-shangyiqu.png"
         @touchend.prevent="playFront"
         @click="playFront">
</
li>

 

PlayService.js 添加 mutations :

playFront (state) {
  state.index = (state.index - 1 + state.playList.length) % state.playList.length
  state.song = state.playList[state.index]
  player.play(state.song.mid);
},

 

好了,到這裏咱們的 播放界面基本完成,效果圖:

                   

仍是很炫酷的。不過,仍是少了歌詞,要是再把歌詞加上去,豈不是 perfect!感興趣的同窗,一塊兒向下研究。

 

歌詞組件: src\components\Lyric.vue ,兩個 props:'currentTime', 'songid' ,來自於父組件( src\components\Play.vue ):

<div class="lyric">
  <lyric :songid="song.id" :currentTime="currentTime"></lyric>  <!--song、currentTIme 來自於PlayService.js 中的 state和getters-->
</div>

 

Lyric.vue中的 watch 屬性,監聽 songid,當 songid 發生變化時,經過 this.$store.dispatch('getLyric', id) 獲取歌詞,可是獲取到的歌詞是加過密的,並且還須要 utf_8解析,數據以下圖:

 

咱們首先須要作的就是解密,解密文件: src\utils\base64.js ,方法 decode 爲解密算法,其中涉及到字符串的方法 charAt(),indexOf(), fromCharCode() ,這裏重點說一下其中的正則表達式:

input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");    //將input中 非字母、數字、'+'、'/'、'=' 替換爲 空

參考正則表達式資料: https://www.cnblogs.com/snandy/p/3662423.html,上面表達式屬於 排除性組合字符組。

 

.decode() 解密後,數據格式:

 

可是離咱們想要的 數組鍵值對的格式 仍是有必定的差距的,咱們須要一步一步解析:

 

 

注意: 第三步的 return語句:

return {[t[0]] : t[1]}

 

t[0] 的外面還有一層 '[ ]',能夠看到該返回值 是一個對象,在JS的語法中,對象的屬性名能夠是標識符,也能夠是表達式。這裏採用表達式命名屬性名,根據ES6語法,必須將表達式放在中括號裏。

 

OK,歌詞解析好了,只須要完成歌詞與播放時間匹配就能夠啦:

computed: {
  currentLyric: function () {
    if (this.lyric !== null) {
      let that = this
      let pastLyric = []
      let i = 0
      Object.keys(this.lyric).forEach(function (key) {
        if (key.split(':')
          .reduce((a, b) =>
          parseInt(a) * 60 * 100 + b
            .split('.')
            .reduce((a, b) =>
            parseInt(a) * 100 + parseInt(b))) - 120 <=          that.currentTimeStamp) {     //歌詞的時間點 與 當前播放時間比較
          if (that.lyric[key] !== '\n') pastLyric.push(that.lyric[key])
        } else if (i <= 1 && that.lyric[key] !== '\n') {
          pastLyric.push(that.lyric[key])
          i++
        }
      })
      return pastLyric.slice(pastLyric.length - 4, pastLyric.length - 1)                      //播放器顯示最後三條歌詞
    }
  },
  currentTimeStamp: function () {                
    let t = this.currentTime.split(':')                    //currentTime不斷更新
    return (parseInt(t[0]) * 60 + parseInt(t[1])) * 100
  }
},

 

到這裏,咱們的播放界面就基本完工啦,本身試聽一下,有沒有一點炫酷的感受呢,哈哈。

相關文章
相關標籤/搜索