vue项目:歌词随歌曲同步滚动

  • Post author:
  • Post category: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) // 歌词滚动函数



版权声明:本文为qq_43634982原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。