vue-router跳转页面后,子组件音乐播放器的当前播放时间会不停在两个值之前跳动?

点击查看demo github地址

问题描述:
在【音乐播放页】选中一首歌曲,歌曲能正常播放;
当切换到【音乐详情页】之后,页面上的当前播放时间会不停的在两个值中间跳动?
定时器timer已经在路由切换的时候关了,但是还会不停的执行timer这个方法


图片描述

clipboard.png

切换路由后,当前播放的音乐播放器组件,时间一直在跳动?

musicBar.vue

<template>
   <div>
     <div style="border: 1px solid #ddd;padding: 10px;margin-top: 50px;">
       <div>
         <p>选中的歌曲列表</p>
         <ul>
           <li v-for="(item,index) in musicList" @click="playListMusic()" :class="{red:currentIndex==index}">{{item.name}}</li>
         </ul>
       </div>
       <button @click="turnMusic"><span>{{isPlayingMsg}}</span></button>
       <button @click="next()">下一首</button>
       <button @click="updateTime()">跳转到上一次位置</button>
       <audio :src=currentMusic.src autoplay  @error="errorFun()" @ended="next()" id="musicId"></audio>
      当前播放音乐是:{{currentMusic.name}}
      <!--当前播放进度:{{musicProgress}}-->
      当前播放的时间:{{currentTime}}s
     </div>
   </div>
</template>

<script>
  import $ from "jquery"
  import {mapState,mapMutations,mapActions,mapGetters} from "vuex"
export default {
  name: 'app',
  data () {
    return {
      timer:""
    }
  },
  computed: {
    ...mapGetters(["currentMusic","musicList","musicProgress","currentTime","currentIndex","isPlaying","isPlayingMsg"])
  },
  methods: {
    addMusic: function (item) {
      this.playMusic();
      this.$store.commit("addMusic",item);
    },
    playMusic: function () {
      var audioPlay = document.getElementById("musicId");
      var _this = this;
      var palam={
        musicProgress:"",
        currentTime:""
      }
      var musicProgress;
      _this.timer=setInterval(function () {
          console.log(8);
        palam.musicProgress = audioPlay.currentTime / audioPlay.duration * 100 + "%";
        palam.currentTime = audioPlay.currentTime;
        _this.$store.commit("playMusic",palam);
      }, 500)
      if(audioPlay.currentTime){
        audioPlay.play();
      }
    },
    turnMusic:function () {
      var audioPlay = document.getElementById("musicId");
      this.$store.commit("turnMusic");
      if (this.isPlaying) {
        audioPlay.play();
      }
      else {
        audioPlay.pause();
      }
    },
    errorFun: function () {
      //判断是否是第一次默认加载
      if (this.musicList.length > 0) {
        console.log("歌曲出错了");
      }
    },
    //播放下一曲
    next: function () {
        this.$store.commit("next");
    },
    //更新进度条
    updateTime(){
        console.log("开始更新进度条");
      //清除之前的定时器
      clearInterval(this.timer);  //跳转到musicDetail后调用这个方法,为什么不起作用?
//      var audioPlay = document.getElementById("musicId");
//      audioPlay.currentTime=this.$store.getters.currentTime;  //每次路由跳转后音乐都会重头开始播放,所以这里我重置音乐开始时间等于上次记录时间;
      this.playMusic();  //如果不加这句,跳转路由后,音乐就停了;加了之后播放时间会不停跳动
    }
  },
  created:function(){
  }
}
</script>
<style>
  .red{
    color: red;
  }
</style>

musicDeatil.vue

<template>
   <div>
     <h3>我是音乐详情页</h3>
     <musicBar ref="musicBar"></musicBar>
   </div>
</template>

<script>
  import $ from "jquery"
  import {mapState,mapMutations,mapActions,mapGetters} from "vuex"
  import musicBar from "./musicBar.vue"
export default {
  name: 'app',
  data () {
    return {
      musicListAll:[
        {
            name:"歌曲一",
            src:"/src/assets/a.mp3",
            id:1
        },
        {
          name:"歌曲二",
          src:"/src/assets/b.mp3",
          id:2
        },
        {
          name:"歌曲三",
          src:"/src/assets/c.mp3",
          id:3
        },
        {
          name:"一首链接出错的歌曲",
          src:"/src/assets/d.mp34",
          id:4
        }
      ]
    }
  },
  computed:{
  },
  methods:{
  },
  components:{
    musicBar
  },
  created:function(){
  },
  //在进入路由前
  beforeRouteEnter:function(to,from,next){
    next(function(vm){     //参数vm代表vue这个实例
       vm.$refs.musicBar.updateTime();
    });
    //父级触发子组件的事件
  },
  //路由离开
  beforeRouteLeave:(to,from,next)=>{
      next();
  }
}
</script>

<style>
</style>

playMusic.vue

<template>
   <div>
     <h3>歌曲列表</h3>
     <ul>
       <li  v-for="item in musicListAll"><a href="javascript:" @click="addMusic(item)">{{item.name}}</a></li>
     </ul>
     <musicBar ref="musicBar"></musicBar>
   </div>
</template>

<script>
  import $ from "jquery"
  import {mapState,mapMutations,mapActions,mapGetters} from "vuex"
  import musicBar from "./musicBar.vue"
export default {
  name: 'app',
  data () {
    return {
      musicListAll:[
        {
            name:"歌曲一",
            src:"/src/assets/a.mp3",
            id:1
        },
        {
          name:"歌曲二",
          src:"/src/assets/b.mp3",
          id:2
        },
        {
          name:"歌曲三",
          src:"/src/assets/c.mp3",
          id:3
        },
        {
          name:"一首链接出错的歌曲",
          src:"/src/assets/d.mp34",
          id:4
        }
      ]
    }
  },
  computed:{
  },
  methods:{
    addMusic:function(item){
        //父组件要触发子组件的值,并传递参数;
      this.$refs.musicBar.addMusic(item);
    }
  },
  components:{
    musicBar
  },
  created:function(){
  },
  route:{
    data:function(transition){
      console.log(transition);
      console.log(101);
    }
  }
}
</script>

<style>
</style>

回答:

不同页面调用同一个组件,但是会生成两套组件(musicBar)参数,所以会产生两个定时器timer;
所以在切换router的时候,会有两个timer不停迭代,应该把timer定时器放在vuex中,保持唯一性;

在playMusic.vue 和 musicDetail.vue中添加router的进入方法beforRouteEnter;当进入到这两个页面后,先关闭store中的定时器timer,再打开一个新的定时器,这样就不会重复;

//  //在进入路由前
  beforeRouteEnter:function(to,from,next){
    next(function(vm){     //参数vm代表vue这个实例
       vm.$refs.musicBar.updateTime();
    });
  }

在musicBar.vue 中的添加的方法;

  //更新进度条
    updateTime(){      
      //清除之前的定时器
      this.$store.commit("clearTime");
      var audioPlay = document.getElementById("musicId");
       audioPlay.pause();
      audioPlay.currentTime=this.$store.getters.currentTime;  //跳转到上次记录的时间
      if(this.isPlaying){
        this.playMusic();
      }
    }

app.js中使用 keep-alive保持在打开已经打开过的页面时不会重新载入

      <keep-alive>
        <router-view></router-view>
      </keep-alive>
      

router/index.js 中

  setTimer:function(state,timer){
     state.timer=timer;
   },
   clearTime:function(state){
     console.log("在store中清除timer");
     clearInterval(state.timer);
   }

暂无评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注