1. 程式人生 > >vue專案:歌詞隨歌曲同步滾動

vue專案:歌詞隨歌曲同步滾動

封裝成物件,暴露出去共享使用

1、新建js檔案
2、因為需要用到元素運動來實現歌詞自上而下滾動的效果,又不想引用jquery增大js的載入,所有在物件內部封裝了一個運動函式。
3、主要的函式是新增定時器來實現歌詞和歌曲的播放的時間同步,因為歌曲有暫停的功能,所以也添加了清除定時器來實現歌詞暫停的功能,此時在物件內部的兩個函式中用到了同一個引數定時器,所有需要將定時器定義成物件自身的一個引數來實現引數共享。
4、因為要滿足點選某一首歌曲來播放相關的歌詞,所以也需要一個函式來重置物件自身的引數。物件內部也需要解析歌詞資料的函式,將解析後的歌詞資料中的時間點都統一轉化成秒,來和audio的當前播放進度(Audio.currentTime)對比,達到歌詞滾動同步歌曲播放進度的效果。
5、每次點選播放某一首歌曲都要先重置物件自身的引數,再進行歌詞同步滾動。

新建的js程式碼如下:

export default {
  second2: 0, // 當前歌曲播放到多少毫秒
  gdtimer: '', // 歌詞滾動的定時器
  height: 20, // 每一行歌詞的高度
  obj: {}, // 解析歌詞後的物件
  obj2: {}, // 備份obj
  // 字串轉換成秒
  parse2 (stri) {
    var arr = stri.split(':')
    var num = 0
    num = parseInt(arr[0]) * 60 + parseFloat(arr[1])
    return num
  },
  // 解析歌詞
  parse (str) {
    var arr1 = []
    var arr2 = []
    this.obj = {
      time: [],
      content: []
    }
    this.obj2 = {
      time: [],
      content: []
    }
    arr1 = str.split('[')
    arr1.forEach((value, index) => {
      if (index > 0) {
        arr2 = arr2.concat(value.split(']'))
      }
    })
    arr2.forEach((value, index) => {
      if (index % 2 === 0) {
        this.obj.time.push(this.parse2(value))
        this.obj2.time.push(this.parse2(value))
      } else {
        this.obj.content.push(value)
        this.obj2.content.push(value)
      }
    })
  },
  // 將歌詞新增到 P 標籤中
  addcontent (conp) {
    this.obj.content.forEach((value, index) => {
      conp.innerHTML = conp.innerHTML + value + '<br>'
    })
  },
  // 實現歌詞滾動
  gundong (conp) {
    this.gdtimer = setInterval(() => {
      var myaudio = document.querySelector('#main-audio')
      // console.log(myaudio.currentTime)
      this.second2 = myaudio.currentTime
      // this.second2 = this.second2 + 10
      if (this.second2 >= this.obj2.time[0]) {
        // 刪除time陣列中已經過的時間
        this.obj2.time.shift()
        console.log(this.second2, this)
        // 獲取 p標籤的top值
        var top = window.getComputedStyle(conp).top
        this.startMove(conp, {
          top: parseInt(top) - this.height
        })
      }
      if (this.obj2.time.length <= 0) {
        this.second2 = 0
        this.lyticsEnd(conp)
        // clearInterval(this.gdtimer)
      }
    }, 50)
  },
  // 暫停歌詞
  pause () {
    if (this.gdtimer !== '') {
      clearInterval(this.gdtimer)
      // console.log(this.obj)
    }
  },
  // 歌曲放完,重置該物件
  lyticsEnd (conp) {
    this.pause()
    conp.innerHTML = ''
    conp.style.top = this.height + 'px' // 大坑。單位必須帶
    this.obj = {}
    this.obj2 = {}
    this.second2 = 0
    console.log('重置該物件成功', this)
  },
  // 運動函式
  startMove (obj, json, fnEnd) {
    var that = this
    clearInterval(obj.timer)// 先清除之前的定時器
    obj.timer = setInterval(function () {
      var bStop = true// 假設所有的值都到了
      for (var attr in json) { // 遍歷json屬性
        var cur = (attr === 'opacity') ? Math.round(parseFloat(that.getStyle(obj, attr)) * 100) : parseInt(that.getStyle(obj, attr))// 對opacity 特殊處理
        var speed = (json[attr] - cur) / 6
        speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed) // speed 數字轉化,防止不能到達目標的bug
        if (cur !== json[attr]) bStop = false// 如果沒有達到目標值,則bStop設為false;
        if (attr === 'opacity') {
          obj.style.filter = 'alpha(opacity=' + (cur + speed) + ')'
          obj.style.opacity = (cur + speed) / 100
        } else {
          obj.style[attr] = cur + speed + 'px'
        }
      }
      if (bStop) {
        clearInterval(obj.timer)
        if (fnEnd) fnEnd() // 執行回撥函式
      }
    }, 30)
  },
  getStyle (obj, name) {
    return obj.currentStyle ? obj.currentStyle[name] : window.getComputedStyle(obj, null)[name]
    // 瀏覽器相容性處理,注意getComputedStyle為只讀屬性
  },
  getByClass (oParent, sClass) {
    var aEle = oParent.getElementsByTagName('*')
    var aResult = []
    var re = new RegExp('\\b' + sClass + '\\b', 'i')
    for (var i = 0; i < aEle.length; i++) {
      if (re.test(aEle[i].className)) aResult.push(aEle[i])
    }
    return aResult
  }
}

vue檔案中如下使用:

		import lyrics from '../footer/lyrics'   
		// js檔案路徑視情況而定
		var conp = document.querySelector('.con-p')
		// 包裹歌詞的元素容器
        lyrics.lyticsEnd(conp) // 重置物件
        lyrics.parse(this.lyrics, conp) // 解析歌詞  this.lyrics 代表歌詞資料
        lyrics.addcontent(conp) // 向元素容器中新增歌詞內容
        lyrics.gundong(conp) // 歌詞滾動函式