Vue aduio播放歌曲

javascript 复制代码
<template >
   <div class="container">
      
      <div class="box1">
        <ul>
          <!-- <li v-for="(item,index) in lrc"  -->
            <li v-for="(item,index) in result" 
          :class="colorHover===index?'lrcHighLight':'lrcDefault'" 
          :key="index" @mousedown="mousedown(index,item)">
          {{ item.words }}
        </li>
      </ul>
    </div>

    <div class="box2">
        <audio 
              controls 
              ref="audio" 
              @timeupdate="timeUpdate"
              @ended="overAudio"
              @pause="onPause"
              @play="onPlay"
              >
        <source src="./song/song.mp3" type="audio/mpeg"/>
        </audio>
      </div>

   </div>
    
 
      
</template>
    
<script>
import  { lrc }  from  './song/index.js';

export default {
  name: "test",
  
  data() {
    return {
      result: [], // 歌词时间对象
      audio: this.$refs.audio,
      doms: {},
      colorHover: 0
    };
  },
  created() {
    // 解析歌词并渲染
    this.parseLrc();

  },

  computed: {
  
    // audioCurrentTime(){
    //   var _this = this;
    //   this.$nextTick(() => { 
    //     alert(_this.$refs.audio.currentTime);
    //     // return document.querySelector('audio').currentTime;
    //     return _this.$refs.audio.currentTime;
    //   })
      
    // }
  },
  watch: {
    // audioCurrentTime(oldTime, newTime) {
    
    //   console.log(1);
    //   this.findIndex();
    // }
  },
  mounted() {

    // this.addEventListeners();
    // this.$refs.audio.addEventListener('timeupdate', this.setOffset());
    this.doms = {
        audio: this.$refs.audio,
        ul: this.$el.querySelector(".container ul"),
        container: this.$el.querySelector('.container'),
      }

      // 播放器默认音量,最大音量1
      this.$refs.audio.volume = 0.25;
  },
  methods: {
    // addEventListeners: function () {
    //     this.$refs.audio.addEventListener('timeupdate', this.setOffset());
    //   },


    // addEventListeners: function () {
    //     const audio = this.$refs.audio;
    //     self.$refs.audio.addEventListener('timeupdate', audio.currentTime)
    //     // self.$refs.player.addEventListener('canplay', audio.durationTime)
    // },

    /** 解析歌词字符串
     * 得到一个歌词对象的数组
     * 每句歌词对象:
     * {time: 开始时间, words: 歌词}
     */
     parseLrc(){
      var lines = lrc.split("\n");
      // 存放所有时间/歌词数组
      this.result = [];
      lines.forEach(item => {
        var parts = item.split("]");
        var timeStr = parts[0].substring(1);

        // this.parseTime(timeStr);
        var obj = {
          time: this.parseTime(timeStr),
          words: parts[1]
        }
        this.result.push(obj);
      })
      // this.createLrcElement();
      return this.result;
    },

        // 原生js添加歌词
      createLrcElement(){
      // 文档片段
      var frag = document.createDocumentFragment();
      for(var i = 0; i<this.result.length; i++){
          var li = this.$el.createElement("li");
          li.textContent = this.result[i].words;
          frag.append(li);
      }
      this.doms.ul.appendChild(frag);
    },

    /** 
     * 将一个时间字符串解析数字(秒)
     * @param {string} timeStr 事件字符串
     * @return 
     */
     parseTime(timeStr){
      var parts =timeStr.split(":");
      return +parseInt(parts[0]) * 60 + parseInt(parts[1]);
    },

    /**
     * 计算出播放器当前播放时间应该高亮哪句歌词的下标
     * 
     */
    findIndex() {
      var lrcTime = this.result;
 
       // DOM上绑定的src属性无法立即更新
      
        // var curTime = document.querySelector('audio').currentTime;
        var curTime = this.$refs.audio.currentTime
        for(var i = 0; i < lrcTime.length; i++){
          // console.log('播放器当前时间', curTime)
          // console.log('歌词时间', lrcTime[i].time)

          if(curTime < lrcTime[i].time) {
            // console.log(lrcTime[i].words);
            return i - 1;
          }
        }
        // 如果遍历完没有歌词,说明播放到最后一句了
        return lrcTime.length - 1;
    

    },




    test(){
      // 容器高度
      var containerHeight = this.doms.container.clientHeight;
      // 每个 li 的高度
      var liHeight = this.doms.ul.children[0].clientHeight;

    },

    /**
     * 设置 Ul 的偏移量
     */
    setOffset(){
      
      // 容器高度
      // var containerHeight = this.doms.container.clientHeight;
      // // 每个 li 的高度
      // var liHeight = this.doms.ul.children[0].clientHeight;

      var index = this.findIndex();
      this.colorHover = index;
      // alert(index)
      // var offset = liHeight * index + liHeight / 2 - containerHeight / 2;
      // if(offset < 0){
      //   offset = 0;
      // }
      // if(offset > maxOffset){
      //   offset = maxOffset;
      // }

      // this.doms.ul.style.transform = `translateY(-${offset}px)`;
      // // 去掉之前的 active 的样式
      // var li = this.doms.ul.querySelector('.active');
      // if(li){
      //   li.classList.remove('active');
      // }
      //  li = this.doms.ul.children[index];
      // if(li){
      //   li.classList.add('active');
      // }
    },
    // 监听播放器时间
    timeUpdate() {
      this.setOffset();
    },
    // 当音频播放
    onPlay () {
        console.log('开始播放声音');
    },
    // 当音频暂停
    onPause () {
        console.log('暂停播放声音');
    },
    //播放完毕执行
    overAudio(){
        console.log('播放声音完毕');
    },
    mousedown(index, item){
      console.log(this.$refs.audio);
 
      this.$refs.audio.currentTime = item.time;
      this.timeUpdate();
    },

    

  }
};
</script>
<style lang="scss" scoped>
.lrcDefault{
 
  color:black;
  }
.lrcHighLight{  
  // transform:  scale(1.5);
  // transition: 1s ease-in; 
  color:#00a0e9;
  }
.box1{
  display: flex;
  justify-content: center;
  height: 90%;

 
}  
.box2{
  display: flex;
  justify-content: center;
  height: 10%;
  bottom: -12px;
  background-color: #000;
  box-shadow: 0 -10px 20px #403f3f;
}  
ul{
  list-style-type: none;
 
  height: 90%;
  overflow-y: scroll;

  scrollbar-color: dark;
  /** 隐藏滚动条,但是元素还是可以滚动 */
  scrollbar-width: none;
  li{
    height: 30px;
    line-height: 30px;
    font-size: 16px;
    cursor:pointer;
  }
}
  .container{
    height: 80vh;
    background: #708090;
}
 
  
</style>
      
      
java 复制代码
var lrc = `[0:00:00]小手拉大手-许梦
[0:06:00]词-陈大毛
[0:13:00]曲-过儿
[0:20:14]编曲-狗蛋
[0:27:08]还记得那场音乐会的烟火
[0:30:02]还记得那个凉凉的深秋
[0:34:13]还记得人潮把你推向了我
[0:38:13]游乐园拥挤的正是时候
[0:42:26]一个夜晚坚持不睡的等候
[0:45:01]一起泡温泉奢侈的享受
[0:49:01]有一次日记里愚蠢的困惑
[0:53:01]因为你的微笑幻化成风
[0:56:01]你大大的勇敢保护着我
[01:02:01]我小小的关怀喋喋不休
[01:04:01]感谢我们一起走了那么久
[01:07:01]又再一次回到凉凉深秋
[01:11:01]给我你的手
[01:13:34]像温柔野兽
[01:15:53]把自由交给草原的辽阔
[01:19:06]我们小手拉大手
[01:21:35]一起郊游
[01:23:11]今天别想太多
`;
// 注意"歌词行"别留空格
export {
    lrc,
  }

1.歌曲需下载

2.点击歌词播放,如果初始化时暂停状态,需手动点击播放(累,没去看aduio方法)

3.歌词时间不准确,自己手动输入的时间,只影响点击歌词播放功能一点点

4.本意是想用原生写(注释部分),但vue框架始终报错document未定义,未果。

5.写得有点乱,望海涵!

相关推荐
会发光的猪。2 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客2 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
周全全3 小时前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
ZwaterZ3 小时前
vue el-table表格点击某行触发事件&&操作栏点击和row-click冲突问题
前端·vue.js·elementui·c#·vue
码农六六3 小时前
vue3封装Element Plus table表格组件
javascript·vue.js·elementui
徐同保3 小时前
el-table 多选改成单选
javascript·vue.js·elementui
快乐小土豆~~3 小时前
el-input绑定点击回车事件意外触发页面刷新
javascript·vue.js·elementui
周三有雨3 小时前
【面试题系列Vue07】Vuex是什么?使用Vuex的好处有哪些?
前端·vue.js·面试·typescript
大霞上仙5 小时前
element ui table 每行不同状态
vue.js·ui·elementui
lv程序媛5 小时前
el-table表头前几列固定,后面几列根据接口返回的值不同展示不同
javascript·vue.js·elementui