欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue-music关于Player播放器组件详解

程序员文章站 2022-06-25 13:26:51
本文实例为大家分享了关于player播放器组件的具体内容,供大家参考,具体内容如下 迷你播放器: 1.播放器组件会在各个页面的情况下会打开。 首先在vuex s...

本文实例为大家分享了关于player播放器组件的具体内容,供大家参考,具体内容如下

vue-music关于Player播放器组件详解

迷你播放器:

vue-music关于Player播放器组件详解

1.播放器组件会在各个页面的情况下会打开。 首先在vuex state.js 中定义全局的播放器状态

import {playmode} from 'common/js/config.js';

const state = {
 singer:{}, 
 playing:false, //是否播放
 fullscreen:false, //是否全屏
 playlist:[], //播放列表
 sequencelist:[], // 非顺序播放列表
 mode:playmode.sequence, // 播放模式(顺序0,循环1,随机2)
 currentindex:-1, //当前播放索引
}
export default state 


---------------------------------------------
// config.js

export const playmode = {
 sequence:0,
 loop:1,
 random:2
}

2.进入播放器页面时获取播放列表数据,改变播放状态   在music-list列表中打开

在song-list 组件中派发事件到父组件,传入当前歌曲的信息和索引

<li @click="selectitem(song,index)" v-for="(song,index) in songs" class="item">

------------------------------
selectitem(item,index){
 this.$emit('select',item,index)
},

在music-list 组件中接受派发事件。

<song-list :rank="rank" :songs="songs" @select="selectitem"></song-list> 

3. 如果commit 多个状态在actions 里设置

import {playmode} from 'common/js/config.js'

export const selectplay = function({commit,state},{list,index}){
 commit(types.set_sequence_list, list)
 commit(types.set_playlist, list)
 commit(types.set_current_index, index)
 commit(types.set_full_screen, true)
 commit(types.set_playing_state, true)
}

4. 在music-list 组件中 用mapactions提交 改变值

import {mapactions} from 'vuex'

methods:{
 selectitem(item,index){
  this.selectplay({
  list:this.songs,
  index
  })
 },
 ...mapactions([
  'selectplay'
 ])
 },

5.在palyer 中获取vuex 全局状态,赋值状态到相应位置(代码为完整代码,对照后面讲解慢慢理解)

<div class="player" v-show="playlist.length>0">    // 如果有列表数据则显示
  <div class="normal-player" v-show="fullscreen">  //如果全屏
   <div class="background">
   <img :src="currentsong.image" alt="" width="100%" height="100%">    //模糊背景图
   </div>
   <div class="top">
    <div class="back" @click="back">
    <i class="icon-back"></i>
    </div>
    <h1 class="title" v-html="currentsong.name"></h1>    //当前歌曲名称
    <h2 class="subtitle" v-html="currentsong.singer"></h2>  //当前歌手名
   </div>
   <div class="middle">
    <div class="middle-l">
    <div class="cd-wrapper">
     <div class="cd" :class="cdcls">
     <img :src="currentsong.image" alt="" class="image">    //封面图
     </div>
    </div>
    </div>
   </div>
   <div class="bottom">
   <div class="progress-wrapper">
   <span class="time time-l">{{ format(currenttime) }}</span>
   <div class="progress-bar-wrapper">
    <progress-bar :percent="percent" @percentchange="onprogressbarchange"></progress-bar>
   </div>
   <span class="time time-r">{{ format(currentsong.duration) }}</span>
   </div>
     <div class="operators">
    <div class="icon i-left">
     <i :class="iconmode" @click="changemode"></i>
    </div>
     <div class="icon i-left" :class="disablecls">
      <i @click="prev" class="icon-prev"></i>
      </div>
      <div class="icon i-center" :class="disablecls">
      <i :class="playicon" @click="toggleplaying"></i>
      </div>
      <div class="icon i-right" :class="disablecls">
      <i @click="next" class="icon-next"></i>
      </div>
      <div class="icon i-right">
      <i class="icon icon-not-favorite"></i>
      </div>
    </div>
    </div>
   </div>
   </transition>
   <transition name="mini">
    <div class="mini-player" v-show="!fullscreen" @click="open">
     <div class="icon">
      <img :src="currentsong.image" alt="" width="40" height="40" :class="cdcls">
     </div>
     <div class="text">
      <h2 class="name" v-html="currentsong.name"></h2>
      <p class="desc" v-html="currentsong.singer"></p>
     </div>
     <div class="control">
      <i :class="miniicon" @click.stop="toggleplaying"></i>
     </div>
     <div class="control">
      <i class="icon-playlist"></i>
     </div>
    </div>
   </transition>
   <audio :src="currentsong.url" ref="audio" @canplay="ready" @error="error" @timeupdate="updatetime" @ended="end"></audio>
 </div>

打开播放器的状态

import {mapgetters,mapmutations} from 'vuex';

...mapgetters([
 'fullscreen',
 'playlist',
 'currentsong',
 'playing',
 'currentindex',
])

注意:不可在组件中直接赋值改版vuex 中的状态 this.fullscreen = false 需要通过mutations 改变,定义mutation-types 和mutations 然后 用vuex的 mapmutations 代理方法调用

[types.set_full_screen](state, flag) {
 state.fullscreen = flag
 },

import {mapgetters,mapmutations} from 'vuex';
methods:{
 ...mapmutations({
 setfullscreen:"set_full_screen", 
 }),
 back(){
 this.setfullscreen(false)
 },
}

设置点击播放按钮方法

 <i :class="playicon" @click="toggleplaying"></i>
toggleplaying(){
 this.setplayingstate(!this.playing); //改变全局变量playing 的属性
},

// 然后watch 监听playing 操作实际的audio 标签的播放暂停
watch:{
  playing(newplaying){
   let audio = this.$refs.audio;
   this.$nexttick(() => {
    newplaying ? audio.play():audio.pause();
   })
  }
 },

// 用计算属性改变相应的播放暂停图标
playicon(){
 return this.playing? 'icon-pause':'icon-play'
},

设置点击播放上一首和下一首按钮方法。用mapgetters 获取currentindex 的值(加一或减一) 并改变,从而改变 currentsong 的状态,监听切换播放。判断播放列表界限重置。

prev(){
    if(!this.songready){
      return;
    }

 let index = this.currentindex - 1;
 if(index === -1){    //判断播放列表界限重置
  index = this.playlist.length-1;
 }
 this.setcurrentindex(index);
 if(!this.playing){  //判断是否播放改变播放暂停的icon
  this.toggleplaying();
 }
 this.songready = false;
},
next(){
 if(!this.songready){
    return;
   }
 let index = this.currentindex + 1;
 if(index === this.playlist.length){    //判断播放列表界限重置
  index = 0;
 }
 this.setcurrentindex(index);
 if(!this.playing){
  this.toggleplaying();
 }
 this.songready = false;
},

监听audio 元素标签的canpaly 事件,当歌曲加载就绪 和 error 事件,当歌曲发生错误的时候,做用户体验,防止用户快速切换导致报错。

设置songready 标志位 如果歌曲没有准备就绪,点击下一首的时候直接return false

data(){
 return {
  songready:false,
 }
},

ready(){
 this.songready = true;
},
error(){
 this.songready = true;
},

进度条

audio元素监听 timeupdate 事件获取当前播放时间的 可读写属性 时间戳。用formt做格式化时间处理,(_pad 为补零函数 )

获取音频总时长 currentsong.duration

<div class="progress-wrapper">
 <span class="time time-l">{{ format(currenttime) }}</span>
 <div class="progress-bar-wrapper">
 <progress-bar :percent="percent" @percentchange="onprogressbarchange"></progress-bar>
 </div>
 <span class="time time-r">{{ format(currentsong.duration) }}</span>
</div>

<audio :src="currentsong.url" ref="audio" @canplay="ready" @error="error" @timeupdate="updatetime" @ended="end"></audio>

updatetime(e){
 this.currenttime = e.target.currenttime; // 获取当前播放时间段
},

format(interval){
 interval = interval | 0;
 const minute = interval/60 | 0;
 const second = this._pad(interval % 60);
 return `${minute}:${second}`;  
},

_pad(num,n=2){
 let len = num.tostring().length;
 while(len<n){
 num = '0' + num;
 len ++;
 }
 return num;
},

建立progress-bar 组件 接收pencent 进度参数,设置进度条宽度和小球的位置。player组件 设置计算属性percent

percent(){
 return this.currenttime / this.currentsong.duration  // 当前时长除以总时长
},

progress-bar 组件

<div class="progress-bar" ref="progressbar" @click="progressclick">
 <div class="bar-inner">
  <div class="progress" ref="progress"></div>
  <div class="progress-btn-wrapper" ref="progressbtn"
   @touchstart.prevent="progresstouchstart"
   @touchmove.prevent="progresstouchmove"
   @touchend="progresstouchend"  
  >
  <div class="progress-btn"></div>
  </div>
 </div>
 </div>
const progressbtnwidth = 16 //小球宽度

props:{
 percent:{
 type:number,
 default:0
 }
},


watch:{
 percent(newpercent){
 if(newpercent>=0 && !this.touch.initated){    
  const barwidth = this.$refs.progressbar.clientwidth - progressbtnwidth;
  const offsetwidth = newpercent * barwidth;
  this.$refs.progress.style.width = `${offsetwidth}px`;
  this.$refs.progressbtn.style.transform=`translate3d(${offsetwidth}px,0,0)`
 }
 }
}

设置拖动

在进度条小按钮progressbtn 上添加touchstart,touchmove,touchend 事件监听方法,事件添加 prevent 防止拖动默认浏览器行为,获取拖动的信息进行计算

在实例上创建一个touch 对象维护不同的回调之间的通讯共享状态信息。  touchstart事件方法中 ,首先设置this.touch.initated为true,表示拖动开始。  记录开始点击位置 e.touches[0].pagex 存到 touch 对象上,记录当前的进度宽度。

在touchmove 中首先判断 是否先进入了 touchstart 方法,计算得到 移动的位置 减去 点击开始的位置的 偏移量长度。 let deltax = e.touches[0].pagex - this.touch.startx

就可以 设置进度条 已有的长度加上偏移量长度。最大不能超过父级progressbar 的宽度

调用this._offset(offsetwidth) 方法设置进度条宽度

在touchend 事件方法中将 this.touch.initated 设置为false,表示拖动结束,并派发事件到player 组件将audio的currenttime 值设置为正确值,参数为pencent

在progressbar 中增加点击事件,调用this._offset(e.offsetx),并且派发事件

 created(){
 this.touch = {};
 },

methods:{
 progresstouchstart(e){
 this.touch.initiated = true;
 this.touch.startx = e.touches[0].pagex;
 this.touch.left = this.$refs.progress.clientwidth;
 },
 progresstouchmove(e){
 if(!this.touch.initiated){
  return;
 }
 let deltax = e.touches[0].pagex - this.touch.startx;
 let offsetwidth = math.min(this.$refs.progressbar.clientwidth - progressbtnwidth,math.max(0,this.touch.left + deltax));
 this._offset(offsetwidth);
 },
 progresstouchend(e){
 this.touch.initiated = false;
 this._triggerpercent();
 },
 progressclick(e){
 const rect = this.$refs.progressbar.getboundingclientrect();
 const offsetwidth = e.pagex - rect.left;
 this._offset(offsetwidth);
 // this._offset(e.offsetx);
 this._triggerpercent();
 },
 _offset(offsetwidth){
 this.$refs.progress.style.width = `${offsetwidth}px`;
 this.$refs.progressbtn.style[transform] = `translate3d(${offsetwidth}px,0,0)`;
 },
 _triggerpercent(){
 const barwidth = this.$refs.progressbar.clientwidth - progressbtnwidth;
 const percent = this.$refs.progress.clientwidth / barwidth;
 this.$emit("percentchange",percent)
 }
},

本文已被整理到了《vue.js前端组件学习教程》,欢迎大家学习阅读。

关于vue.js组件的教程,请大家点击专题vue.js组件学习教程进行学习。

更多vue学习教程请阅读专题《vue实战教程》

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。