首先安裝vuex,在根目錄(有package.json的目錄中)打開終端。css
npm install vuex --save
等待安裝完成以後,在main.js文件中進行vuex的註冊。註冊步驟相似於vue-router,他們都是vue的官方插件。html
在src目錄中建立store目錄,這個目錄用於儲存關於vuex的一切。因此目錄中能夠建立若干js文件做爲模塊,分別有index.js,actions.js,getters.js,mutations.js,mutation-types.js。因爲項目不大,因此我只建立一個index.js,若是須要那麼之後再擴展。在main.js中引入的store是一個文件夾,他會自動搜尋index文件並做爲入口。vue
編輯index.js文件:vue-router
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
export default new Vuex.Store({
// 狀態儲存值
state: {
},
// 狀態惟一的改變方法,commit調用
mutations: {
},
// 相似於computed計算屬性,接受state參數
getters: {
},
// 異步經過mutations修改狀態值,dispatch調用
actions: {
}
})
以上就是vuex的大致結構,如今對於音樂播放器的控制來講,儲存與觀察的狀態有以下幾點:vuex
歌曲是否正在播放npm
歌曲時長json
歌曲是否標記爲喜歡api
播放模式異步
播放用戶列表音樂仍是播放推薦頻道svg
暫且想到了這麼多,其實還有當前播放歌曲索引,當前歌單什麼的。可是考慮到要修改以前的代碼,就先不考慮這個,等以後再修改。因此修改index.js的代碼:
state: {
// 是否正在播放
isPlaying: false,
// 是否點擊喜歡這是歌曲
likeThisMusic: false,
// 音樂時長
musicDuration: 0,
// 播放模式,0表明順序播放,1表明隨機播放,2表明單曲循環
displayModel: 0,
// 是否播放用戶自定義歌曲,若不是則爲播放推薦頻道
privateSongList: false,
},
mutations: {
// 切換播放與暫停狀態
togglePlayPause (state) {
state.isPlaying = !state.isPlaying
}
},
如今若是我想觀測某一個state,讓他在有變化的時候觸發某個函數應當怎麼作呢?好比這裏的isPlaying狀態,觀測值改變爲true的時候觸發播放,改變爲false的時候暫停。
十點半宿舍快要關門了,明天繼續。
這種狀況可使用computed屬性,官方文檔給出的例子以下:
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
// return store.state.count 也可使用注入的$store屬性:
return this.$store.state.count
}
}
}
而後若是須要多個狀態的時候,能夠私用mapState輔助函數。這個函數能夠幫助生成計算屬性,以下:
// 在單獨構建的版本中輔助函數爲 Vuex.mapState
import { mapState } from 'vuex'
export default {
computed: mapState({
// 箭頭函數可以使代碼更簡練
count: state => state.count,
// 傳字符串參數 'count' 等同於 `state => state.count`
countAlias: 'count',
// 爲了可以使用 `this` 獲取局部狀態,必 須使用常規函數
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
另外若是state中的狀態名與組件中計算屬性名一致的話,也能夠簡寫爲一個字符串。以下:
computed: mapState([
// 映射 this.count 爲 store.state.count
'count'
])
因爲vuex我也是剛剛接觸,因此準備用與不用mapState都嘗試一下,因此先對代碼修改以下:
<template>
<div class="music-controller" @click="togglePlayPause">
新垣結衣的播放控制器
<div class="control-panel">
<i class="iconfont danqu" ></i>
<i class="iconfont liebiao"></i>
<i class="iconfont suiji"></i>
<i class="iconfont xin"></i>
<i class="iconfont shangyishou"></i>
<i class="iconfont bofang"></i>
<i class="iconfont zanting"></i>
<i class="iconfont xiayishou"></i>
<i class="iconfont xiangqing"></i>
</div>
</div>
</template>
<script>
export default {
methods: {
togglePlayPause () {
console.log('clicked')
this.$store.commit('togglePlayPause')
},
_logChanged () {
console.log('STATE CHANGED!')
console.log(this.$store.state.isPlaying)
}
},
computed: {
isPlaying () {
return this.$store.state.isPlaying
}
},
watch: {
isPlaying () {
this._logChanged()
}
}
}
</script>
如今若是點擊播放器控制的div就會觸發togglePlayPause函數,而後提交commit,執行togglePlayPause這個mutation,這樣就會isPlaying狀態就會發生變化。而後組件代碼中的computed屬性返回這個狀態。而後讓watch屬性來觀察這個computed屬性。如今state中的某個狀態屬性發生了變化的時候就會經過computed返回而且被watch觀察到。能夠在控制檯中看到每當點擊控制面板的時候就會顯示狀態發生了改變。
若是是使用mapState呢?這裏有個注意的地方,看到官方文檔中的mapState是直接代替爲compued的全部屬性,可是大部分狀況是不僅關心vuex中的state,並且還有組件中的一些狀態須要計算屬性。這個時候就須要使用ES6的擴展運算符,將多個屬性打包成一個對象:
<template>
<div class="music-controller">
新垣結衣的播放控制器
<div class="control-panel">
<i class="iconfont danqu" @click="changePlayMode"></i>
<i class="iconfont liebiao" @click="changePlayMode"></i>
<i class="iconfont suiji" @click="changePlayMode"></i>
<i class="iconfont xin"></i>
<i class="iconfont shangyishou"></i>
<i class="iconfont bofang" @click="togglePlayPause"></i>
<i class="iconfont zanting" @click="togglePlayPause"></i>
<i class="iconfont xiayishou"></i>
<i class="iconfont xiangqing"></i>
</div>
</div>
</template>
<script>
import store from 'store'
import {mapState} from 'vuex'
export default {
methods: {
togglePlayPause () {
console.log('togglePlayPause')
this.$store.commit('togglePlayPause')
},
changePlayMode () {
console.log('changePlayMode')
this.$store.commit('changePlayMode')
},
_logIsPlayingChanged () {
console.log('STATE CHANGED!')
console.log(this.$store.state.isPlaying)
},
_logPlayModeChanged () {
console.log('PLAYMODE CHANGED!')
console.log(this.$store.state.playMode)
}
},
computed: {
以上的代碼提供了兩個狀態屬性與狀態修改作實驗,如今點擊對應的圖標,就會有咱們須要的結果了。
如今vuex的使用方法就已經主要弄明白了,如今就是繼續對控制面板界面與邏輯進行編寫:
<template>
<div class="music-controller">
新垣結衣的播放控制器
<div class="control-panel">
<div v-if="privateSongList" @click="changePlayMode">
<i class="iconfont danqu" v-show="playMode === 0"></i>
<i class="iconfont liebiao" v-show="playMode === 1"></i>
<i class="iconfont suiji" v-show="playMode === 2"></i>
</div>
<div v-else @click="toggleLikeThisMusic">
<i class="iconfont dislike" v-show="!likeThisMusic"></i>
<i class="iconfont like" v-show="likeThisMusic"></i>
</div>
<i class="iconfont shangyishou" @click="changeToPrevMusic"></i>
<i class="iconfont bofang" @click="togglePlayPause" v-show="isPlaying"></i>
<i class="iconfont zanting" @click="togglePlayPause" v-show="!isPlaying"></i>
<i class="iconfont xiayishou" @click="changeToNextMusic"></i>
<i class="iconfont xiangqing" @click="showMusicDetail"></i>
</div>
</div>
</template>
尚未加css樣式,這裏有個略微繞的問題就是這些狀態的命名與切換。由於在平常生活中,播放的時候顯示的是暫定圖標,因此在開發的時候就比較混亂,倒不是什麼大問題,注意一下就好。
<template>
<div class="music-controller">
<div class="control-panel">
<div class="play-mode control-unit" v-if="privateSongList" @click="changePlayMode">
<i class="iconfont danqu" v-show="playMode === 0"></i>
<i class="iconfont liebiao" v-show="playMode === 1"></i>
<i class="iconfont suiji" v-show="playMode === 2"></i>
</div>
<div class="like-this-music control-unit" v-else @click="toggleLikeThisMusic">
<i class="iconfont dislike" v-show="!likeThisMusic"></i>
<i class="iconfont like" v-show="likeThisMusic"></i>
</div>
<i class="iconfont shangyishou control-unit" @click="changeToPrevMusic"></i>
<i class="iconfont bofang control-unit" @click="togglePlayPause" v-show="isPlaying"></i>
<i class="iconfont zanting control-unit" @click="togglePlayPause" v-show="!isPlaying"></i>
<i class="iconfont xiayishou control-unit" @click="changeToNextMusic"></i>
<i class="iconfont xiangqing control-unit" @click="showMusicDetail"></i>
</div>
</div>
</template>
......
<style scoped>
@font-face {
font-family: 'iconfont'; /* project id 431442 */
src: url('//at.alicdn.com/t/font_431442_ylcevnla67xpqfr.eot');
src: url('//at.alicdn.com/t/font_431442_ylcevnla67xpqfr.eot?#iefix') format('embedded-opentype'),
url('//at.alicdn.com/t/font_431442_ylcevnla67xpqfr.woff') format('woff'),
url('//at.alicdn.com/t/font_431442_ylcevnla67xpqfr.ttf') format('truetype'),
url('//at.alicdn.com/t/font_431442_ylcevnla67xpqfr.svg#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont";
font-size: 40px;
font-style: normal;
}
.music-controller {
width: 100%;
height: 30%;
display: flex;
justify-content: center;
align-items: