Vuex 概念篇
Vuex 是什么魔策?
Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式姜钳。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化遇八。
什么是“狀態(tài)管理模式”?
從軟件設(shè)計的角度丽啡,就是以一種統(tǒng)一的約定和準(zhǔn)則,對全局共享狀態(tài)數(shù)據(jù)進行管理和操作的設(shè)計理念硬猫。你必須按照這種設(shè)計理念和架構(gòu)來對你項目里共享狀態(tài)數(shù)據(jù)進行CRUD补箍。所以所謂的“狀態(tài)管理模式”就是一種軟件設(shè)計的一種架構(gòu)模式(思想)改执。
為什么需要這種“狀態(tài)管理模式”應(yīng)用到項目中呢?
現(xiàn)如今坑雅,流行組件化辈挂、模塊化開發(fā),多人開發(fā)各自組件的時候裹粤,不難保證各個組件都是唯一性的终蒂,多個組件共享狀態(tài)肯定是存在的,共享狀態(tài)又是誰都可以進行操作和修改的遥诉,這樣就會導(dǎo)致所有對共享狀態(tài)的操作都是不可預(yù)料的拇泣,后期出現(xiàn)問題,進行 debug 也是困難重重矮锈,往往我們是盡量去避免全局變量霉翔。
但大量的業(yè)務(wù)場景下,不同的模塊(組件)之間確實需要共享數(shù)據(jù)苞笨,也需要對其進行修改操作债朵。也就引發(fā)軟件設(shè)計中的矛盾:模塊(組件)之間需要共享數(shù)據(jù) 和 數(shù)據(jù)可能被任意修改導(dǎo)致不可預(yù)料的結(jié)果。
為了解決其矛盾瀑凝,軟件設(shè)計上就提出了一種設(shè)計和架構(gòu)思想序芦,將全局狀態(tài)進行統(tǒng)一的管理,并且需要獲取猜丹、修改等操作必須按我設(shè)計的套路來。就好比馬路上必須遵守的交通規(guī)則硅卢,右行斑馬線就是只能右轉(zhuǎn)一個道理射窒,統(tǒng)一了對全局狀態(tài)管理的唯一入口,使代碼結(jié)構(gòu)清晰将塑、更利于維護脉顿。
Vuex 是借鑒了 Flux 、Redux 和 The Elm Architecture 架構(gòu)模式点寥、設(shè)計思想的產(chǎn)物艾疟。
什么情況下我應(yīng)該使用 Vuex?
不打算開發(fā)大型單頁應(yīng)用敢辩,使用 Vuex 可能是繁瑣冗余的蔽莱。應(yīng)用夠簡單,最好不要使用 Vuex戚长。一個簡單的 global event bus (父子組件通信盗冷,父組件管理所需的數(shù)據(jù)狀態(tài))就足夠您所需了。構(gòu)建一個中大型單頁應(yīng)用同廉,您很可能會考慮如何更好地在組件外部管理狀態(tài)仪糖,Vuex 將會成為自然而然的選擇柑司。
個人見解,什么時候用锅劝?管你小中大型應(yīng)用攒驰,我就想用就用唄,一個長期構(gòu)建的小型應(yīng)用項目故爵,誰能知道項目需求以后會是什么樣子玻粪,畢竟在這浮躁的時代,需求就跟川劇變臉一樣快稠集,對不對奶段?畢竟學(xué)習(xí)了 Vuex 不立馬用到項目實戰(zhàn)中,你永遠不可能揭開 Vuex 的面紗剥纷。項目中使用多了痹籍,自然而然就會知道什么時候該用上狀態(tài)管理,什么時候不需要晦鞋。老話說的好熟能生巧蹲缠,你認為呢?
(括弧 -- 先了解好Vuex 一些基本概念悠垛,然后在自己的項目中使用過后线定,再用到你公司項目上,你別這么虎一上來就給用上去了~)
Vuex 基本使用篇
安裝
npm i vuex -S
項目全局中任何地方使用 Vuex, 需要將 Vuex 注冊到 Vue 實例中:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
Vuex 上車前的一個??
上車規(guī)則:
- 每一個 Vuex 應(yīng)用的核心就是 store(倉庫)确买,一個項目中必須只有一個 store 實例斤讥。包含著你的應(yīng)用中大部分的狀態(tài) (state)。
- 不能直接改變 store 中的狀態(tài)湾趾。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation芭商。
Vuex 和單純的全局對象有以下兩點不同:
(1) Vuex 的狀態(tài)存儲是響應(yīng)式的。Vue 組件從 store 中讀取狀態(tài)的時候搀缠,若 store 中的狀態(tài)發(fā)生變化铛楣,那么相應(yīng)的組件也會相應(yīng)地得到高效更新。
(2)不能直接改變 store 中的狀態(tài)艺普。(重要的事情多來一遍)
上??:
<div id="app">
<p>{{ count }}</p>
<p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</p>
</div>
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex) // Vuex 注冊到 Vue 中
// 創(chuàng)建一個 store
const store = new Vuex.Store({
// 初始化 state
state: {
count: 0
},
// 改變狀態(tài)唯一聲明處
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
})
new Vue({
el: '#app',
// 從根組件將 store 的實例注入到所有的子組件
store,
computed: {
count () {
// Vuex 的狀態(tài)存儲是響應(yīng)式的簸州,從 store 實例中讀取狀態(tài)最簡單的方法就是在計算屬性中返回某個狀態(tài),
// 每當(dāng)狀態(tài) count 發(fā)生變化,都會重新求取計算
return this.$store.state.count
}
},
methods: {
increment () {
this.$store.commit('increment')
},
decrement () {
this.$store.commit('decrement')
}
}
})
state
一個對象管理應(yīng)用的所有狀態(tài)歧譬,唯一數(shù)據(jù)源(SSOT, Single source of truth)岸浑,必須前期初始化就定義好,不然后面在來修改設(shè)置 state
瑰步,程序就不會捕獲到 mutations(突變的意思)
所以數(shù)據(jù)也就不會又任何的更新助琐,組件上也無法體現(xiàn)出來。
獲取 store 管理的狀態(tài)面氓, 因為在 Vue 實例化的時候?qū)?Vuex store 對象 注入了進來 兵钮,所以任何地方都可以通過 this.$store
獲取到 store, this.$store.state
來獲取狀態(tài)對象蛆橡, this.$store.commit
來觸發(fā)之前定義好的 mutations 中的方法
this.$store.state('count') // => 0
this.$store.commit('increment') // => 1
通過提交 mutation
的方式,而非直接改變 store.state.count
, 使用 commit
方式可以讓 Vuex 明確地追蹤到狀態(tài)的變化掘譬,利于后期維護和調(diào)試泰演。
通過了解 state
(狀態(tài),數(shù)據(jù))和 mutations
(修改數(shù)據(jù)唯一聲明的地方葱轩,類似 SQL 語句)知道了 Vuex 最重要的核心兩部分睦焕,然后通過掌握 gttter、action靴拱、module 來讓 Vuex 更加的工程化垃喊、合理化來適應(yīng)更大型的項目的狀態(tài)管理。
mapState 輔助函數(shù)
mapState
可以干什么呢袜炕?字面意思狀態(tài)映射本谜,通過 mapState
可以更加快捷方便幫我們生成計算屬性,拿上面的例子進行演示:
computed: {
count () {
return this.$store.state.count
}
}
// 使用 mapState
import { mapState } from 'vuex' // 需要先導(dǎo)入
computed: mapState([
// 箭頭函數(shù)方式
count: state => state.count ,
// or 傳字符串參數(shù)方式, 'count' 等同于 state => state.count
countAlias: 'count'
// 獲取狀態(tài)后偎窘,你還需要和當(dāng)前組件別的屬性值時,就必須使用常規(guī)函數(shù)的寫法了, 只有這樣才能獲取到當(dāng)前組件的 this
countPlusLocalState (state) {
return state.count + this.localCount
}
])
當(dāng)前計算屬性名稱和狀態(tài)名稱相同時乌助,可以傳遞一個字符串?dāng)?shù)組:
computed: mapState([
// 映射 `this.count` 為 `this.$store.state.count`
'count'
])
以上使用 mapState
輔助函數(shù)后,整個 computed
計算屬性都成了 state
狀態(tài)管理聚集地了陌知, 組件里并不是所有的計算屬性都需要被狀態(tài)管理化他托,還是有很多計算屬性是不需要狀態(tài)管理的數(shù)據(jù)的,那如何將它與局部計算屬性混合使用呢仆葡?
因為 mapState
函數(shù)返回的是一個對象赏参。所以我們使用對象擴展運算符就可以把局部計算屬性和 mapState
函數(shù)返回的對象融合了。
computed: {
...mapState({
count: state => state.count
}),
localComputed () {
/* ... */
}
}
?? 注意:
對象擴展運算符沿盅,現(xiàn)處于 ECMASCript 提案 stage-4 階段(將被添加到下一年度發(fā)布)把篓,所以項目中要使用需要安裝 babel-plugin-transform-object-rest-spread 插件 或 安裝 presets 環(huán)境為 stage 為 1的 env 版本 babel-preset-stage-1 和修改 babelrc 配置文件
.babelrc
{
"presets": [
"env",
"stage-1" // 添加此項
],
"plugins": [
"transform-vue-jsx",
"syntax-dynamic-import"
]
}
核心概念
上面以講述過 state 了,這里就不過多的說明嗡呼。
Getter
Getter
就是 Store
狀態(tài)管理層中的計算屬性纸俭,獲取源 State
后皇耗,希望在對其進行一些包裝南窗,再返回給組件中使用。也是就將直接獲取到 State
后在 computed
里進行再次的過濾郎楼、包裝邏輯統(tǒng)統(tǒng)提取出放到 Getter
里進行万伤,提高了代碼的復(fù)用性、可讀性呜袁。
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
提取到 Getter
:
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
// `Getter` 默認第一個參數(shù)為 `state`:
getters: {
doneTodos: state => {
return state.todos.filter( todo => todo.done )
}
}
})
// 組件中獲取敌买,通過屬性訪問
computed: {
doneTodosCount () {
return this.$store.getters.doneTodos.length
}
}
?? 注意: getter 在通過屬性訪問時是作為 Vue 的響應(yīng)式系統(tǒng)的一部分進行緩存。
Getter 還接受其他 getter 作為第二個參數(shù)
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter( todo => todo.done )
},
// 第二個參數(shù)為 getters
doneTodosLength: (state, getters) => {
return getters.doneTodos.length
}
}
})
還可以通過給 Getter 傳遞參數(shù)獲取特定的數(shù)據(jù)
getters: {
// ...
getTodoById: state => id => {
return state.todos.find( todo => todo.id === id )
}
}
組件內(nèi)調(diào)用方式
this.$store.getters.getTodoById(2) // => { id: 2, text: '...', done: false }
?? 注意:getter 在通過方法訪問時阶界,每次都會去進行調(diào)用虹钮,而不會緩存結(jié)果聋庵。
mapGetters 輔助函數(shù)
和前面 mapState
輔助函數(shù)作用和使用上基本相同。
import { mapGetters } from 'vuex'
// getter 名稱和 計算屬性名稱相同的情況下芙粱,可以傳遞字符串?dāng)?shù)組
export default {
// ...
computed: {
...mapGetters([
'doneTodos'
])
}
}
// 傳遞對象的方式
export default {
// ...
computed: {
...mapGetters({
doneTodos: 'doneTodos',
getTodoById: 'getTodoById' // 此處傳遞回來的是一個函數(shù)祭玉,所以在使用的時候 => {{ getTodoById(2) }}
})
}
}
Mutation
不能直接修改狀態(tài),需要通過 Vuex store 中聲明的 Mutations 里的方法修改狀態(tài)春畔。 更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation
脱货。mutation
是一個對象, 含有一個字符串的 事件類型 (type) 和 一個 回調(diào)函數(shù) (handler)律姨。
回調(diào)函數(shù)就是我們實際進行狀態(tài)更改的地方振峻,默認接受 state 作為第一個參數(shù)。
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
// increment 事件類型(type)名稱择份,increment() 回調(diào)函數(shù)
// increment: function (state) {} 原本寫法
increment (state) {
// 變更狀態(tài)
state.count++
}
}
})
mutation handler
不能被直接調(diào)用扣孟,需要通過 store.commit()
來通知我需要觸發(fā)一個 mutation handler
。
this.$store.commit('increment')
mutation
接收參數(shù)必須只能兩個缓淹,超出的都無法獲裙颉;第二個參數(shù)推薦傳遞的是一個對象讯壶,來接收更多的信息料仗。
this.$store.commit('increment', 10)
// or
this.$store.commit('increment', { num: 10 })
對象風(fēng)格的提交方式
this.$store.commit({
type: 'increment',
num: 10
})
Mutation 需要遵守 Vue 的響應(yīng)規(guī)則
Vuex 的 store 中的狀態(tài)是響應(yīng)式的,那么當(dāng)我們變更狀態(tài)時伏蚊,監(jiān)視狀態(tài)的 Vue 組件也會自動更新立轧。這也意味著 Vuex 中的 mutation 也需要與使用 Vue 一樣遵守一些注意事項:
- 最好提前在你的 store 中初始化好所有所需屬性(state 中的屬性)。
- 當(dāng)需要在對象上添加新屬性時躏吊,你應(yīng)該返回的是一個新對象
* 使用 Vue.set(obj, 'newProp', 123)氛改,或者
* 以新對象替換老對象。例如:Object.assgin({}, state.obj, newProps)
比伏、對象擴展運算符state.obj = {...state.obj, newProp: 123 }
mapMutation 輔助函數(shù)
使用方式跟 mapState
和 mapGetters
基本相同胜卤。
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
// 傳遞字符串?dāng)?shù)組,同名哦~
...mapMutations([
'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`
// `mapMutations` 也支持載荷:
'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)`
]),
// 傳遞對象
...mapMutations({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
})
}
}
調(diào)用方式就跟 methods
其他普通方法一樣赁项,通過 this.<methodName>
來調(diào)用葛躏。
?? 注意:
mutation 必須是同步函數(shù),修改 state 必須是同步的悠菜、同步的舰攒、同步的。
如果是異步的悔醋,當(dāng)觸發(fā) mutation 的時候摩窃,內(nèi)部的回調(diào)函數(shù)還沒有被調(diào)用,根本不知道實際執(zhí)行在何處芬骄,很難追蹤起問題猾愿。(實質(zhì)上任何在回調(diào)函數(shù)中進行的狀態(tài)的改變都是不可追蹤的鹦聪。
Vuex 也提供了異步操作的解決方案, 需要將異步操作提取出來放入到 Action 里進行操作蒂秘。而 Mutation 只負責(zé)同步事務(wù)椎麦。
Action
在之前也講述了,Action 是用來處理異步操作的材彪。這里在詳細說明一下 Action 的基本使用观挎。
Action 類似于 mutation, 不同在于:
- Action 提交的是 mutation段化,而不是直接變更狀態(tài)嘁捷。(不直接修改狀態(tài),修改狀態(tài)還是需要通過 mutation)
- Action 可以包含任意異步操作显熏。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
// 實踐中雄嚣,經(jīng)常用到參數(shù)解構(gòu)來簡化代碼, increment ({commit}) { commit('') }
increment (context) {
context.commit('increment')
}
}
})
Action 函數(shù)接受一個與 store 實例具有相同方法和屬性的 context 對象(并不是真正的 store 本身)喘蟆,因此可以調(diào)用 store.commit
進行提交 mutation缓升, 或者通過 context.state
和 context.getters
來獲取 state
和 getters
。
觸發(fā)Action
Action 通過 store.dispatch
方法觸發(fā):
this.$store.dispatch('increment')
// 以傳遞額外參數(shù)分發(fā)
store.dispatch('incrementAsync', {
amount: 10
})
// 以對象形式分發(fā)
store.dispatch({
type: 'incrementAsync',
amount: 10
})
與服務(wù)器數(shù)據(jù)異步請求基本在 Action 里進行蕴轨, 然后通過 Mutation 來同步應(yīng)用狀態(tài)state
mapAction 輔助函數(shù)
和 mapMutions
使用方式基本一致港谊。
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 將 `this.increment()` 映射為 `this.$store.dispatch('increment')`
// `mapActions` 也支持載荷:
'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.dispatch('incrementBy', amount)`
]),
// 傳遞對象
...mapActions({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.dispatch('increment')`
})
}
}
組合 Action
Action 通常是異步的,那么如何知道 action 什么時候結(jié)束呢橙弱?更重要的是歧寺,我們?nèi)绾尾拍芙M合多個 action,以處理更加復(fù)雜的異步流程棘脐?
通過返回一個 Promise 對象來進行組合多個 Action斜筐。
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
然后:
store.dispatch('actionA').then(() => {
// ...
})
利用 async / await
,我們可以如下組合 action:
// 假設(shè) getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
Module
由于 Vuex 使用單一狀態(tài)樹模式蛀缝,來統(tǒng)一管理應(yīng)用所有的狀態(tài)顷链,導(dǎo)致所有狀態(tài)會集中到一個比較大的對象,隨著后續(xù)不斷得迭代屈梁,這個對象就會越來越龐大嗤练,后期的代碼可讀性、可維護性就會不斷加大俘闯。
解決以上問題潭苞,就需要對這個對象的內(nèi)部進行拆分和細分化忽冻,對狀態(tài)進行分門別類真朗,也就產(chǎn)生了模塊(module) 這個概念。每個模塊擁有自己的 state僧诚、mutation遮婶、action蝗碎、getter、甚至是嵌套子模塊——從上至下進行同樣方式的分割旗扑,將龐大的系統(tǒng)進行合理有效的職能劃分蹦骑,遵循單一職責(zé)的理念,每個模塊清晰明了的自己的職責(zé)和職能臀防。
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)
聲明模塊后眠菇,state、mutation袱衷、action捎废、getter 等使用方式、作用和不在 modules
內(nèi)聲明方式基本一樣致燥,只是在細節(jié)上進行了一些細微的改變登疗,比如: getter 里默認接收一個參數(shù) state,模塊里接收 state 就是本身模塊自己的 state 狀態(tài)了嫌蚤,而不是全局的了辐益; 調(diào)用獲取上也多一道需要告知那個模塊獲取狀態(tài) 等一些細節(jié)上的差異。
Module 里 state脱吱、mutation智政、action、getter 上的一些差異
(1)模塊內(nèi)部的 mutation 和 getter箱蝠,接收的第一個參數(shù) state
是模塊的局部狀態(tài)對象女仰。
(2)模塊內(nèi)部的 action,局部狀態(tài)通過 context.state
暴露出來抡锈,根節(jié)點狀態(tài)則為 context.rootState
(3)模塊內(nèi)部的 getter疾忍,根節(jié)點狀態(tài)會作為第三個參數(shù)暴露出來
命名空間
默認情況下峰档,模塊內(nèi)部的 action底循、mutation 和 getter 是注冊在全局命名空間的——這樣使得多個模塊能夠?qū)ν?mutation 或 action 作出響應(yīng),所以必須防止模塊里屬性或方法重名灯蝴。
為了模塊具有更高的封裝度撇簿、復(fù)用性和獨立性聂渊,可以通過添加 namespaced: true
的方式使其成為帶命名空間的模塊。在調(diào)用上也就需要添加上聲明 getter四瘫、action 及 mutation 到底屬于那個模塊了汉嗽,以路徑的形式表示屬于那個模塊。
const store = new Vuex.Store({
modules: {
account: {
namespaced: true, // 開啟命名空間
// 模塊內(nèi)容(module assets)
state: { ... }, // 模塊內(nèi)的狀態(tài)已經(jīng)是嵌套的了找蜜,使用 `namespaced` 屬性不會對其產(chǎn)生影響
getters: {
isAdmin () { ... } // -> getters['account/isAdmin'] 調(diào)用時以路徑的形式表明歸屬
},
actions: {
login () { ... } // -> dispatch('account/login')
},
mutations: {
login () { ... } // -> commit('account/login')
},
// 嵌套模塊
modules: {
// 繼承父模塊的命名空間
myPage: {
state: { ... },
getters: {
profile () { ... } // -> getters['account/profile']
}
},
// 進一步嵌套命名空間
posts: {
namespaced: true,
state: { ... },
getters: {
popular () { ... } // -> getters['account/posts/popular']
}
}
}
}
}
})
在帶命名空間的模塊內(nèi)訪問全局內(nèi)容
帶命名空間的模塊內(nèi)訪問全局 state 饼暑、getter 和 action, rootState
和 rootGetter
會作為第三和第四參數(shù)傳入 getter
,也會通過 context
對象的屬性傳入 action弓叛。
需要在全局命名空間內(nèi)分發(fā) action
或提交 mutation
彰居,將 { root: true }
作為第三參數(shù)傳給 dispatch
或 commit
即可。
modules: {
foo: {
namespaced: true,
getters: {
// 在這個模塊的 getter 中撰筷,`getters` 被局部化了
// 全局的 state 和 getters 可以作為第三陈惰、四個參數(shù)進行傳入毕籽,從而訪問全局 state 和 getters
someGetter (state, getters, rootState, rootGetters) {
getters.someOtherGetter // -> 'foo/someOtherGetter'
rootGetters.someOtherGetter // -> 'someOtherGetter'
},
someOtherGetter: state => { ... }
},
actions: {
// 在這個模塊中, dispatch 和 commit 也被局部化了
// 他們可以接受 `root` 屬性以訪問根 dispatch 或 commit
someAction ({ dispatch, commit, getters, rootGetters }) {
getters.someGetter // -> 'foo/someGetter'
rootGetters.someGetter // -> 'someGetter'
dispatch('someOtherAction') // -> 'foo/someOtherAction'
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
commit('someMutation') // -> 'foo/someMutation'
commit('someMutation', null, { root: true }) // -> 'someMutation'
},
someOtherAction (ctx, payload) { ... }
}
}
}
在帶命名空間的模塊注冊全局 action
需要在帶命名空間的模塊注冊全局 action
画髓,你可添加 root: true
,并將這個 action 的定義放在函數(shù) handler 中平委。例如:
{
actions: {
someOtherAction ({dispatch}) {
dispatch('someAction')
}
},
modules: {
foo: {
namespaced: true,
actions: {
someAction: {
root: true,
handler (namespacedContext, payload) { ... } // -> 'someAction'
}
}
}
}
}
帶命名空間的模塊里輔助函數(shù)如何使用奈虾?
將模塊的空間名稱字符串作為第一個參數(shù)傳遞給上述函數(shù)廉赔,這樣所有綁定都會自動將該模塊作為上下文。
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo',
'bar'
])
}
還可以通過使用 createNamespacedHelpers
創(chuàng)建基于某個命名空間輔助函數(shù)蜡塌。它返回一個對象碉纳,對象里有新的綁定在給定命名空間值上的組件綁定輔助函數(shù):
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')
export default {
computed: {
// 在 `some/nested/module` 中查找
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
// 在 `some/nested/module` 中查找
...mapActions([
'foo',
'bar'
])
}
}
模塊動態(tài)注冊
在 store 創(chuàng)建之后,你可以使用 store.registerModule
方法注冊模塊:
// 注冊模塊 `myModule`
store.registerModule('myModule', {
// ...
})
// 注冊嵌套模塊 `nested/myModule`
store.registerModule(['nested', 'myModule'], {
// ...
})
模塊動態(tài)注冊功能使得其他 Vue 插件可以通過在 store 中附加新模塊的方式來使用 Vuex 管理狀態(tài)劳曹。例如琅摩,vuex-router-sync 插件就是通過動態(tài)注冊模塊將 vue-router
和 vuex
結(jié)合在一起,實現(xiàn)應(yīng)用的路由狀態(tài)管理蜕劝。
你也可以使用 store.unregisterModule(moduleName)
來動態(tài)卸載模塊轰异。注意岖沛,你不能使用此方法卸載靜態(tài)模塊(即創(chuàng)建 store 時聲明的模塊)婴削。
待更新~