vue實踐04之vuex
vuex是一個專門為vue.js設計的集中式狀態管理架構。我把它理解為在data中的屬性需要共享給其他vue元件使用的部分,就叫做狀態。簡單的說就是data中需要共用的屬性。比如:我們有幾個元件要顯示使用者名稱稱和使用者等級,或者顯示使用者的地理位置。如果我們不把這些屬性設定為狀態,那每個元件遇到後,都會到伺服器進行查詢計算,返回後再顯示。在中大型專案中會有很多共用的資料,所以尤大神給我們提供了vuex。
vuex把元件的共享狀態抽取出來,以一個全域性單例模式管理。在這種模式下,我們的元件樹構成了一個巨大的“檢視”,不管在樹的哪個位置,任何元件都能獲取狀態或者觸發行為。通過定義和隔離狀態管理中的各種概念並強制遵守一定的規則,我們的程式碼將會變得更結構化且易維護。
注:圖中虛線標註的區域即為vuex,可以看出vue components可以共享vuex。適用場景
雖然 Vuex 可以幫助我們管理共享狀態,但也附帶了更多的概念和框架。這需要對短期和長期效益進行權衡。
如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗餘的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的global event bus
參考連結 就足夠您所需了。但是,如果您需要構建一箇中大型單頁應用,您很可能會考慮如何更好地在元件外部管理狀態,Vuex 將會成為自然而然的選擇。
開始
每一個 Vuex 應用的核心就是 store(倉庫)。“store”基本上就是一個容器,它包含著你的應用中大部分的狀態 (state)。Vuex 和單純的全域性物件有以下兩點不同:
-
Vuex 的狀態儲存是響應式的。當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。
-
你不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地瞭解我們的應用。
簡單例子
- 引入vuex
npm install vuex --save
需要注意的是這裡一定要加上 --save,因為你這個包我們在生產環境中是要使用的。 - 新建一個vuex目錄,在目錄中新建store.js檔案
state 對應定義的狀態值, mutations 內封裝對狀態值改變的函式。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
state.count++;
},
reduce(state) {
state.count--;
}
}
})
export default store
複製程式碼
- 在components目錄中新建count.vue檔案
<template>
<div>
<h2>{{msg}}</h2>
<hr/>
<h3>{{$store.state.count}}</h3>
<div>
<button @click="$store.commit('add')">+</button>
<button @click="$store.commit('reduce')">-</button>
</div>
</div>
</template>
<script>
import store from '@/vuex/store'
export default{
data(){
return{
msg:'Hello Vuex',
}
},
store
}
</script>
複製程式碼
注意上述程式碼中的兩個store.commit
事件。
- 通過提交 mutation 的方式,而非直接改變 store.state.count,是因為我們想要更明確地追蹤到狀態的變化。這個簡單的約定能夠讓你的意圖更加明顯,這樣你在閱讀程式碼的時候能更容易地解讀應用內部的狀態改變。此外,這樣也讓我們有機會去實現一些能記錄每次狀態改變,儲存狀態快照的除錯工具。有了它,我們甚至可以實現如時間穿梭般的除錯體驗。
- 由於 store 中的狀態是響應式的,在元件中呼叫 store 中的狀態簡單到僅需要在計算屬性中返回即可。觸發變化也僅僅是在元件的 methods 中提交 mutation。
- 在路由檔案router/index.js檔案中新增count的路由
{
path: '/count',
component: Count
}
複製程式碼
- 訪問頁面http://127.0.0.1:8080/#/count
- 測試下vuex在不同component之間共享資料 在App.vue檔案中同樣也引用store,App.vue 程式碼如下:
<script>
import store from '@/vuex/store'
export default {
name: "App",
methods:{
goback(){
this.$router.go(-1);
},
goHome(){
this.$router.push('/');
}
},
// 把 store 物件提供給 “store” 選項,這可以把 store 的例項注入所有的子元件
//(需呼叫 Vue.use(Vuex))
store
};
</script>
複製程式碼
注意上述程式碼中引入了store
選項,這個選項可以把store的例項注入所有的子元件。
在App.vue檔案template標籤裡增加顯示state的程式碼如下:
<h3>{{$store.state.count}}</h3>
複製程式碼
再次訪問count頁面,可以發現改變count元件的state值,App元件也會同步更新。
- 誤區-元件共享
筆者試著同時開啟兩個count頁面,天真以為改變一個頁面的計數值,另一個頁面也會自動變化,實際這是肯定不行的。vue就是一個單頁應用,多頁資料共享只能依賴與後端server的互動才能實現。vuex解決的時候單頁中的多component共享資料的問題。
vue元件獲得state
- 通過computed計算屬性直接賦值
computed:{
computeCount(){
return this.$store.state.count;
}
}
複製程式碼
顯示呼叫程式碼為<h4>{{computeCount}}</h4>
完整程式碼如下:
<template>
<div>
<h2>{{msg}}</h2>
<hr/>
<h3>{{$store.state.count}}</h3>
<h4>{{computeCount}}</h4>
<div>
<button @click="$store.commit('add')">+</button>
<button @click="$store.commit('reduce')">-</button>
</div>
</div>
</template>
<script>
import store from '@/vuex/store'
export default{
data(){
return{
msg:'Hello Vuex',
}
},
computed:{
computeCount(){
return this.$store.state.count;
}
},
store
}
</script>
複製程式碼
- 通過mapState的物件來賦值
當一個元件需要獲取多個狀態時候,將這些狀態都宣告為計算屬性會有些重複和冗餘。為了解決這個問題,我們可以使用 mapState 輔助函式幫助我們生成計算屬性,讓你少按幾次鍵。
- 首先要用import引入mapState
import {mapState} from 'vuex'
-然後還在computed計算屬性裡寫如下程式碼
computed: mapState({
// 箭頭函式可使程式碼更簡練
computeCount: state => state.count,
// 傳字串引數 'count' 等同於 `state => state.count`
countAlias: 'count',
// 為了能夠使用 `this` 獲取區域性狀態,必須使用常規函式
countPlusLocalState (state) {
return state.count + this.localCount
}
})
複製程式碼
count2完整程式碼如下:
<template>
<div>
<h2>{{msg}}</h2>
<hr/>
<h3>{{$store.state.count}}</h3>
<h4>{{computeCount}}</h4>
<h5>{{countAlias}}</h5>
<h6>{{countPlusLocalState}}</h6>
<div>
<button @click="$store.commit('add')">+</button>
<button @click="$store.commit('reduce')">-</button>
</div>
</div>
</template>
<script>
import store from '@/vuex/store'
import {mapState} from 'vuex'
export default{
data(){
return{
msg:'Hello Vuex',
localCount:20
}
},
computed: mapState({
// 箭頭函式可使程式碼更簡練
computeCount: state => state.count,
// 傳字串引數 'count' 等同於 `state => state.count`
countAlias: 'count',
// 為了能夠使用 `this` 獲取區域性狀態,必須使用常規函式
countPlusLocalState (state) {
return state.count + this.localCount
}
}),
store
}
</script>
複製程式碼
- 通過mapState的陣列來賦值
當對映的計算屬性的名稱與 state 的子節點名稱相同時,我們也可以給 mapState 傳一個字串陣列。
computed: mapState([
// 對映 this.count 為 store.state.count
'count'
])
複製程式碼
完整程式碼如下:
<template>
<div>
<h2>{{msg}}</h2>
<hr/>
<!--<h3>{{$store.state.count}}</h3>-->
<h6>{{count}}</h6>
<div>
<button @click="$store.commit('add')">+</button>
<button @click="$store.commit('reduce')">-</button>
</div>
</div>
</template>
<script>
import store from '@/vuex/store'
import {mapState} from 'vuex'
export default{
data(){
return{
msg:'Hello Vuex',
}
},
computed: mapState([
// 對映 this.count 為 store.state.count
'count'
]),
store
}
</script>
複製程式碼