### 樣式作用域
scoped
### vuex的輔助函數(Player.vue)
mapState:將state值直接映射到計算屬性
原來拿到state中的songList:
computed: { songList(){ return this.$store.state.songList; } }
通過mapState拿到state中的songList:
computed: { ...mapState(["songList"]) }
步驟:
①引入
import {mapState,mapMutations,mapActions,mapGetters} from "vuex";
②computed中使用...mapState()拿到store中state中的屬性,使用...mapGetters拿到store中getters中的方法
computed: { // songList(){ // return this.$store.state.songList.length; // } ...mapState(["songList","fullScreen","currentIndex"]), // currentSong(){ // return this.$store.getters.currentSong // } ...mapGetters(["currentSong"]) }
### 點擊Detail.vue列表歌曲,跳轉至Player.vue
①在store.js中,聲明歌單列表和當前播放歌曲的下標
const store=new Vuex.Store({ state:{ playing:false, fullScreen:false, songList:[], // 歌單列表 currentIndex:-1, // 當前正在播放的歌曲 }, mutations:{ setSongList(state,list){ state.songList=list; }, setCurrentIndex(state,index){ state.currentIndex=index; } }, getters:{ currentSong(state){ // 根據下標獲取當前播放歌曲的信息 return state.songList[state.currentIndex]; } } })
②Detail.vue中通過goPlayer()方法中的commit()觸發mutations中的方法,將當前歌手的歌單列表和當前下標分別傳過去
goPlayer(index){ this.$store.commit("setSongList",this.list); this.$store.commit("setCurrentIndex",index); }
③Player.vue中,可以通過getters拿到
{{this.$store.getters.currentSong}}
這個取值的方法太繁瑣了,可以通過輔助函數mapGetters拿到:
computed: { ...mapGetters(["currentSong"]) }
然后就{{currentSong}}就可以了
最好是通過actions來觸發,稍作修改:
store.js中:
actions:{ addSongList({commit},{index,list}){ commit("setSongList",list); commit("setCurrentIndex",index); } },
Detail.vue中:
goPlayer(index){ // this.$store.commit("setSongList",this.list); // this.$store.commit("setCurrentIndex",index); this.$store.dispatch("addSongList",{list:this.list,index:index}); }
注意:actions的用途就是處理異步和做多個commit的封裝。
### 利用const將mutations中函數的名字做封裝,避免命名重復(store.js)
①store文件夾下新建mutations-type.js文件:
const SET_SONG_LIST="SET_SONG_LIST"; const SET_CURRENT_INDEX="SET_CURRENT_INDEX"; export default{ SET_SONG_LIST, SET_CURRENT_INDEX }
②store.js中用常量名替代原來的函數名:
引入:
import type from "./mutations-type.js"
mutations和actions中:
mutations:{ [type.SET_SONG_LIST](state,list){ state.songList=list; }, [type.SET_CURRENT_INDEX](state,index){ state.currentIndex=index; } }, actions:{ addSongList({commit},{index,list}){ commit(type.SET_SONG_LIST,list); commit(type.SET_CURRENT_INDEX,index); } },
### utils工具的使用(Player.vue)
①在src下新建utils/formatUrl.js:
// 專輯 export const albumUrl=(albumMid)=>{ return `https://y.gtimg.cn/music/photo_new/T002R300x300M000${albumMid}.jpg?max_age=2592000`; } // 歌曲 export const songUrl=(songMid)=>{ return `http://aqqmusic.tc.qq.com/amobile.music.tc.qq.com/C400${songMid}.m4a?guid=4887996690&vkey=16121C6B6E73C564FA01F98651C808B32B6D8788E8C7A1FCCFD030B194EC90658BB78D0A988B6DBC9F0C6E1535FD194E2C459CE01510E438&uin=0&fromtag=38`; }
②引入:(Player.vue)
import * as urlObj from "utils/formatUrl.js";
或
import {albumUrl,songUrl} from "utils/formatUrl.js";
注意:
1、export default{} 只能拋出一個對象,如果要拋出多個用 export const ...
2、引入的時候加上 * as,或者通過解構:import {albumUrl,songUrl} from "utils/formatUrl.js";
### &符號的意思(Player.vue)
img{ .w(300); .h(300); border-radius: 50%; border: 10px solid hsla(0,0%,100%,.1); box-sizing: border-box; &.play{ animation: rotate 20s linear infinite; } &.paused{ animation-play-state: paused; } }
加&表示play、paused和img是同級的,不加&表示play、paused是img的子級。
### audio標簽的timeupdate事件:當前播放時間(Player.vue)
audio綁定timeupdate事件,可以通過e.target.currentTime拿到當前播放時間
①定義timeupdate事件
<audio controls @timeupdate="timeUpdate"></audio>
②將當前時間賦給current當前時間
timeUpdate(e){ console.log("時間變化",e.target.currentTime) this.current=e.target.currentTime; }
### 點擊play按鈕,實現播放和暫停,播放時img旋轉,暫停時img暫停旋轉(Player.vue)
①給img標簽綁定類名playClass
<img :class="playClass" v-if="currentSong" :src="albumUrl">
②按鈕添加點擊事件play
<div class="control"> <button @click="play">play</button> </div>
③data中聲明playing為false
data() { return { playing:false } }
④設置play和paused類名的樣式
img{ .w(300); .h(300); border-radius: 50%; border: 10px solid hsla(0,0%,100%,.1); box-sizing: border-box; &.play{ animation: rotate 20s linear infinite; } &.paused{ animation-play-state: paused; } }
⑤computed中將playing的值賦給playClass類
playClass(){ return this.playing?"play":"play paused"; }
接下來控制playing的布爾值就可以控制img的旋轉
⑥play()方法中判斷是否處於暫停中,如果是點擊播放,否則點擊暫停,同時設置playing值
play(){ let audio=this.$refs.audio; if(audio.paused){ audio.play(); this.playing=true; }else{ audio.pause(); this.playing=false; } console.log(audio.__proto__) }
注意:
1、添加類名的時候不可以寫 return this.playing?"play":"paused"; 這樣會造成暫停過后,img重新開始旋轉。
2、打印audio標簽的__proto__對象,可以獲取audio的一系列屬性和方法。
### 上一曲(prev)和下一曲(next)(Player.vue)
①添加prev和next按鈕:
<div class="control"> <button @click="prev">prev</button> <button @click="play">play</button> <button @click="next">next</button> </div>
②通過commit()觸發mutations中的SET_CURRENT_INDEX方法:
next(){ let index=this.currentIndex+1; this.$store.commit("SET_CURRENT_INDEX",index); }, prev(){ let index=this.currentIndex-1; this.$store.commit("SET_CURRENT_INDEX",index); }
③邊界判斷,當SET_CURRENT_INDEX方法中判斷當index大於列表最后一項時,讓index為0;當index小於列表第一項時,讓index為列表最后一項。這就是循環播放:
[type.SET_CURRENT_INDEX](state,index){ if(index>state.songList.length-1){ index=0; }else if(index<0){ index=state.songList.length-1; } state.currentIndex=index; },
### audio標簽的ended事件:播放完成觸發(Player.vue)
①
<audio controls @ended="ended"></audio>
②
ended(){ console.log("播放完成") }
### props傳值(Player.vue、P-scrollBar.vue)
props用於父傳子傳值。
傳遞:當子組件在父組件中當做標簽傳值使用的時候,給當前子組件綁定一個自定義屬性,值為需要傳遞的數據。
<one :val="msg"></one>
接收:在子組件內部通過props屬性來進行接收。props接收的方式有數組和對象兩種:
數組接收:
props:["msg"]
對象接收:
props:{ msg:{ type:Number, default:0, required:true } }
type:限制外部數據的類型
default:默認值,當父組件沒有給子組件傳值時用默認值
required:布爾值,當前屬性是不是必傳的值,如果值為true,不傳msg屬性時會報錯
傳遞:(Player.vue)
<PScrollBar :current="current" :duration="duration"></PScrollBar>
接收:(P-scrollBar.vue)
props:{ "current":{type:Number,default:0}, "duration":{type:Number,default:0}, }
### watch監聽控制進度條的寬度(P-scrollBar.vue)
watch: { current(newValue){ let percentage=(newValue/this.duration)*100; this.$refs.container.style.width=`${percentage}%`; } }
注意:watch中的方法是data中的屬性,watch依賴於data,當data中的屬性發生改變的時候,觸發watch中函數執行。current()是data中的屬性,這里它是由props傳遞過來的,當current()執行時,進度條寬度被不斷地重新定義。
### 點擊滾動條控制播放時間(P-scrollBar.vue)
①給wrapper盒子綁定點擊事件clickDarg
<div class="wrapper" @click="clickDarg" ref="wrapper"> <div class="container" ref="container"> </div> </div>
②將比例賦給container盒子,並將這個百分比傳給父組件Player.vue
clickDarg(e){ let percentage=(e.offsetX/this.$refs.wrapper.clientWidth)*100; this.$refs.container.style.width=`${percentage}%`; // 派發jump事件給Player.vue this.$emit("jump",percentage); }
③給PScrollBar組件綁定jump事件
<PScrollBar :current="current" :duration="duration" @jump="jump"></PScrollBar>
④audio的currentTime屬性可讀也可寫
jump(percentage){ this.$refs.audio.currentTime=this.duration*percentage/100; }