[TOC]
>[success] # mutation 與 action / module

上圖是 **Vuex** 狀態管理的 **流程**,描述了從 **Vue Components(組件)** 執行 **異步操作** 的一個 **環形流程** ,實際上如果 **沒有異步操作的需求** 就不用走 **Actions** 的這個步驟, **2種操作(同步、異步操作)** 的流程如下:
1. **異步操作**: **Vue Components(組件)** > **Actions(請求接口操作寫這里)** > **Mutations(接口成功返回值后在這里修改State的值)** > **State狀態更新** > **Vue Components(組件)視圖更新**
2. **同步操作** : **Vue Components(組件)** > **Mutations(修改State的值)** > **State狀態更新** > **Vue Components(組件)視圖更新**
>[success] ## mutation
我們想修改 **State** 時,**不可以直接修改(例如:this.$store.state.appName = '小阿giao') state** ,而是要通過一個 **Commit** 提交一個 **Mutations** ,或者 **Dispatch** 一個 **Actions** 來走上圖( **Vuex狀態管理的流程圖** )這個 **環形流程** 來修改 **State**
1. 首先在 **store文件夾** 中 創建一個 **mutations.js**
**store/mutations.js**
~~~
const mutations = {
//
}
export default mutations
~~~
2. 在 **store/index.js** 中引入 **mutations.js**
**store/index.js**
~~~
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state' // state.js文件可以不寫.js結尾,這樣寫也會自動找到state.js文件
import getters from './getters'
import mutations from './mutations'
import actions from './actions'
import user from './module/user' // 引入模塊文件
Vue.use(Vuex)
export default new Vuex.Store({
state, // ES6對象簡寫的形式,state: state 等同與 state
getters,
mutations,
actions,
modules: { // 模塊引用
user
}
})
~~~
>[success] ### 使用方法
上面把 **根狀態** 的 **mutations** 引入完成了, 那么如何通過 **mutations** 來修改 **state** 呢,首先 **展示一個錯誤的修改方式**
>[success] #### 錯誤方式
**sotre.vue**
~~~
<template>
<div>
<p>{{ appName }}</p>
<button @click="handleChangeAppName">修改appName</button>
</div>
</template>
<script>
export default {
computed:{
appName(){
return this.$store.state.appName
}
},
methods:{
handleChangeAppName(){
// 不可以通過這種方式來修改state中的appName
this.appName = 'newAppName'
}
}
}
</script>
~~~
我在上面的 **store.vue** 文件中通過 **點擊事件** 直接 **修改計算屬性** ,這時瀏覽器會報錯

意思是 **【計算屬性】 被注冊,但是它沒有 【setter方法】**,大白話就是 **【一個計算屬性】,默認情況下只有一個【getter方法】,沒有【setter方法】。**
**getter方法觸發方式** :**計算屬性** 被 **讀取** 時,**getter方法** 會被觸發。
**setter方法觸發方式** :**修改計算屬性** 的時候,會觸發 **setter方法** 。
下面的代碼進行了 **錯誤的示范** 修改了 **計算屬性**:
**store.vue**
~~~
<template>
<div>
<p>{{ nameB }}</p>
<button @click="handleChangeNameB">修改計算屬性nameB</button>
</div>
</template>
<script>
export default {
data(){
return{
name: '路飛'
}
},
computed:{
nameB: {
set: function(newValue){ // nameB被修改時,該函數會被觸發。這里可以當做watch或者change來使用
this.name = `${ newValue }真是奧利給`
},
get: function(newValue){ // 處理過后的值,返回(return)給使用nameB的地方
return this.name + '索隆'
}
}
},
methods:{
handleChangeNameB(){
this.nameB = '娜美桑'
}
}
}
</script>
~~~
>[success] #### 正確方式
1. 使用 **commit** 調用 **mutations** 中的方法來修改 **state**
首先在 **store/state.js** 中設置 **appName全局變量**
**store/state.js**
~~~
const state = {
appName: 'admin'
}
export default state
~~~
然后在 **store/mutations.js** 中寫上 **修改 state 的方法**
**store/mutations.js**
~~~
const mutations = {
/**
* 修改app名稱方法
* @param state 【state】指的是同級的【state】,也就是【根級別】的中的state
* @param params 調用SET_APP_NAME方法時傳過來的參數,可以傳基本數據類型(字符串、布爾等),也可以傳入引用類型(對象、數組、等)
*/
SET_APP_NAME(state, params){
state.appName = params
}
}
export default mutations
~~~
在使用到文件中這樣使用即可
**store.vue**
~~~
<template>
<div>
<p>{{ appName }}</p>
<button @click="handleChangeAppName">修改Vuex中的appName</button>
</div>
</template>
<script>
export default {
computed:{
appName: function(){
return this.$store.state.appName
}
},
methods:{
handleChangeAppName(){
// commit第一個參數為mutations中方法名,第二個參數為要傳過去的值
this.$store.commit('SET_APP_NAME', 'newAppName')
}
}
}
</script>
~~~
或者 **commit** 也可以傳 **一個參數** , **傳個對象** ,如下:
**store.vue**
~~~
<template>
<div>
<p>{{ appName }}</p>
<button @click="handleChangeAppName">修改Vuex中的appName</button>
</div>
</template>
<script>
export default {
computed:{
appName: function(){
return this.$store.state.appName
}
},
methods:{
handleChangeAppName(){
this.$store.commit({
type: 'SET_APP_NAME', // type就是要執行mutations里的方法的名稱
appName: 'newAppName' // 這里appName可以對應state要修改的state
})
}
}
}
</script>
~~~
**store/mutations.js**
~~~
const mutations = {
/**
* 修改app名稱方法
* @param state 【state】指的是同級的【state】,也就是【根級別】的中的state
* @param params 調用SET_APP_NAME方法時傳過來的參數,可以傳基本數據類型(字符串、布爾等),也可以傳入引用類型(對象、數組、等)
*/
SET_APP_NAME(state, params){
state.appName = params.appName
}
}
export default mutations
~~~
2. 使用 **Vue** 的 **Set 動態添加State**
假如 **state 中有一個變量以后要使用** ,但是 **現在 state 中是沒有聲明定義這個變量** ,就需要用到 **Vue** 提供的 **Set** 方法來添加 **State**,因為在 **最初state 中 沒有聲明定義這個變量** ,然后通過的 **mutation** 來 **修改這個變量** 是 **不會觸發視圖更新** 的 ,因為 **最初沒有在實例上定義聲明的變量是沒有get跟set方法的**,所以**不會觸發視圖更新**,如果想 **觸發視圖更新** 只有通過 **Vue** 提供的 **Set** 方法來向 **State** 中 **添加變量**,同時也會給這個 **變量** 添加 **get** 跟 **set** 方法,以達到 **視圖更新** 的效果,案例如下:
假如我以后在 **store/state.js** 中有一個 **appVersion** 的變量以后要用到,但是目前沒有在 **state** 中 **定義聲明**
**store/state.js**
~~~
const state = {
appName: 'admin',
// appVersion: '1.0'
}
export default state
~~~
在 **store/mutations.js** 中寫 **動態添加appVersion** 變量的方法,主要是用到了 **Vue** 的 **Set** 方法,來做到動態添加 **State**
**store/mutations.js**
~~~
import vue from 'vue'
const mutations = {
SET_APP_VERSION(state, params){
vue.set(state, 'appVersion', params.appVersion) // vue的$set方法動態向state中添加appVersion
}
}
export default mutations
~~~
在 **頁面中使用** 這樣寫
**store.vue**
~~~
<template>
<div>
<p>版本號{{ appVersion }}</p>
<button @click="handleChangeAppVersion">向Vuex中添加appVersion</button>
</div>
</template>
<script>
export default {
computed:{
appVersion: function(){
return this.$store.state.appVersion
}
},
methods:{
// 點擊按鈕添加app版本號(appVersion)
handleChangeAppVersion(){
this.$store.commit({
type: 'SET_APP_VERSION',
appVersion: '1.0'
})
}
}
}
</script>
~~~
3. **mapMutations方法快速訪問 mutation 中的函數**
上面描述了通過 **commit** 方法執行一個 **mutation** 中定義的 **函數** 來修改 **state** ,以及使用 **Vue** 提供的 **Set** 方法動態向 **state** 中 **添加變量** ,接下來講一下如何使用 **Vuex** 提供的 **mapMutations** 方法來調用 **mutation** 中的方法。
*****
3.1 **使用 mapMutations 訪問 【根狀態】 以及 【module(模塊)】中的 【mutation】**
首先 **store.vue** 文件中引入 **mapMutations** ,然后再通過 **...mapMutations([ 'mutation中定義的方法名稱' ])** 把 **Vuex** 中的 **mutation** 中的方法(這里 **mapMutations方法** 中的 **數組參數** ,無論是 **根狀態(store/index.js)** 下,還是 **module(模塊)** 下的 **mutation** 方法,都可以通過 **mapMutations** 方法引入),引入到 **methods** 中
**store.vue**
~~~
<template>
<div>
<p>用戶名:{{ userName }}</p>
<p>app名稱:{{ appName }}</p>
<button @click="handleChangeAppName">修改app名稱</button>
<button @click="handleChangeUserName">修改用戶名</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
computed:{
appName: function(){ // 根狀態下的state
return this.$store.state.appName
},
userName: function(){ // module(模塊)下的state
return this.$store.state.user.userName
}
},
methods:{
...mapMutations([ // 1. 通過(擴展運算符)...mapMutations來把Vuex中mutation的方法展開到methods中
'SET_APP_NAME',
'SET_USER_NAME'
]),
handleChangeAppName(){
// 2. 調用根狀態下mutation中的SET_APP_NAME方法
this.SET_APP_NAME('看云app')
},
handleChangeUserName(){
// 2. 調用module(模塊)中mutation中的SET_USER_NAME方法
this.SET_USER_NAME('小黑')
}
}
}
</script>
~~~
**根狀態** 的 **store/mutations.js**
**store/mutations.js**
~~~
const mutations = {
/**
* 修改app名稱方法
* @param state 【state】指的是同級的【state】,也就是【根級別】的中的state
* @param params 調用SET_APP_NAME方法時傳過來的參數,可以傳基本數據類型(字符串、布爾等),也可以傳入引用類型(對象、數組、等)
*/
SET_APP_NAME(state, params){
state.appName = params
}
}
export default mutations
~~~
**根狀態** 的 **store/state.js**
**store/state.js**
~~~
const state = {
appName: '騰訊qq',
}
export default state
~~~
**module(模塊)的 js 文件**
**store/module/user.js**
~~~
const state = {
userName: '小明'
}
const mutations = {
SET_USER_NAME(state, params){
state.userName = params
}
}
const actions = {
//
}
const getters = {
firstLetter: (state) => { // 定義getter
return state.userName.substr(0, 1)
}
}
export default {
// namespaced: true, // 注意這里沒有開啟命名空間
getters,
state,
mutations,
actions
}
~~~
3.2 **mapMutations配合命名空間使用**
**store/module/user.js**
~~~
const state = {
userName: '小明'
}
const mutations = {
SET_USER_NAME(state, params){
state.userName = params
}
}
const actions = {
//
}
const getters = {
firstLetter: (state) => { // 定義getter
return state.userName.substr(0, 1)
}
}
export default {
namespaced: true, // 開啟命名空間
getters,
state,
mutations,
actions
}
~~~
**store.vue**
~~~
<template>
<div>
<p>用戶名:{{ userName }}</p>
<button @click="handleChangeUserName">修改用戶名</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
computed:{
userName: function(){ // module(模塊)下的state
return this.$store.state.user.userName
}
},
methods:{
...mapMutations('user',[ // 1. 第一個參數module(模塊)名稱,第二個參數模塊中的mutations里的方法名
'SET_USER_NAME'
]),
handleChangeUserName(){
// 2. 調用module(模塊)中mutation中的SET_USER_NAME方法
this.SET_USER_NAME('小黑')
}
}
}
</script>
~~~
或者可以使用**mapMutations**配合**Vuex**提供的**createNamespacedHelpers**方法一起使用來獲取**模塊**中的**mutations**,這種方式 **mapMutations 不需要寫第一個模塊名的參數**
~~~
<template>
<div>
<p>用戶名:{{ userName }}</p>
<button @click="handleChangeUserName">修改用戶名</button>
</div>
</template>
<script>
import { createNamespacedHelpers } from 'vuex'
const { mapMutations } = createNamespacedHelpers('user') // createNamespacedHelpers('模塊名稱')
export default {
computed:{
userName: function(){ // module(模塊)下的state
return this.$store.state.user.userName
}
},
methods:{
...mapMutations([ // 1. 上面使用了createNamespacedHelpers,這里就不用像之前一樣再寫模塊名作為第一個參數
'SET_USER_NAME'
]),
handleChangeUserName(){
// 2. 調用module(模塊)中mutation中的SET_USER_NAME方法
this.SET_USER_NAME('小黑')
}
}
}
</script>
~~~
>[success] ## action
我們想進行一些 **異步操作(請求接口)** 后想修改 **state** ,就要在 **action** 中寫 **異步操作(請求接口)**,然后執行 **commit** 方法提交一個 **mutation** ,再在 **mutation** 中修改 **state** 。
1. 首先在**store文件夾**中 創建一個**actions.js**
**store/actions.js**
~~~
const actions = {
/**
* 通過接口更新app名稱方法
* @param { commit } 【commit】是一個方法,調用它可以提交一個【mutation】的方法,通過【mutation】來修改【state】
* @param
*/
updateAppName({ commit }){
//
}
// 上面的寫法是ES6的結構賦值的寫法,相當于下面這樣寫:
// updateAppName(paramsObj){
// const commit = paramsObj.commit
// }
}
export default actions
~~~
2. 在 **store/index.js** 中引入**actions.js**
**store/index.js**
~~~
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state' // state.js文件可以不寫.js結尾,這樣寫也會自動找到state.js文件
import getters from './getters'
import mutations from './mutations'
import actions from './actions'
import user from './module/user' // 引入模塊文件
Vue.use(Vuex)
export default new Vuex.Store({
state, // ES6對象簡寫的形式,state: state 等同與 state
getters,
mutations,
actions,
modules: { // 模塊引用
user
}
})
~~~
>[success] ### 使用方法
**需求** :根據調用接口返回 **appName**,并且賦值給 **state** 中定義好的 **appName** 。
1. 使用 **mapActions** 方法來把 **action** 的 **異步方法** 引入到 **methods** 中使用。這種方法無論是 **根狀態** 的 **action** ,還是 **module** 的 **action** 都可以使用 **mapActions** 進行引入。
首先在 **actions.js** 中寫好 **異步操作** 的方法, **updateAppName** 方法,并且在 **updateAppName** 方法中調用了 **src/api/app.js** 中的 **getAppName接口**
**store/actions.js**
~~~
import { getAppName } from '@/api/app' // 前面的是簡寫,等同于@/api/app.js
const actions = {
/**
* 通過接口更新app名稱方法
* @param { commit } 【commit】是一個方法,調用它可以提交一個【mutation】的方法,通過【mutation】來修改【state】
*/
updateAppName({ commit }){
getAppName().then(res => {
// 解構賦值來取appName
const { info: { appName } } = res
commit('SET_APP_NAME', appName)
}).catch(err => {
console.log(err)
})
}
}
export default actions
~~~
下面是一個 **模擬的接口** , **如果成功就返回成功的數據,如果失敗就返回錯誤** 。
**src/api/app.js**
~~~
/**
* 獲取app名稱接口
*/
export const getAppName = () => {
return new Promise((resolve, reject) => {
const err = null
setTimeout(() => {
if(!err) resolve({ code: 200, info: { appName: 'newAppName' } })
else reject(err)
})
})
}
~~~
在上面的 **store/actions.js** 中的 **updateAppName** 方法調用后,執行了 **src/api/app.js** 中的 **getAppName** 接口,接口成功后通過 **commit** 執行了一個 **mutation** 方法,并且在 **mutation** 方法中修改了 **state** 中的 **appName** ,如下:
**store/mutations.js**
~~~
const mutations = {
/**
* 修改app名稱方法
* @param state 【state】指的是同級的【state】,也就是【根級別】的中的state
* @param params 調用SET_APP_NAME方法時傳過來的參數,可以傳基本數據類型(字符串、布爾等),也可以傳入引用類型(對象、數組、等)
*/
SET_APP_NAME(state, params){
state.appName = params
}
}
export default mutations
~~~
還有 **state.js** , **默認是空字符串**
**store/state.js**
~~~
const state = {
appName: '',
}
export default state
~~~
最終在使用 **action** 的 **store.vue組件** 中通過 **mapActions** 將 **action** 中異步的方法引入到 **methods** 中,通過點擊 **【獲取app名稱】** 按鈕來執行 **action** 中的 **updateAppName** 異步方法,來通過接口來 **獲取app名稱** 。
**store.vue**
~~~
<template>
<div>
<p>app名稱:{{ appName }}</p>
<button @click="handleChangeAppName">獲取app名稱</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
computed:{
appName: function(){
return this.$store.state.appName
}
},
methods:{
...mapActions([
'updateAppName'
]),
handleChangeAppName(){
this.updateAppName()
}
}
}
</script>
~~~
2. **mapActions** 配合 **命名空間** 使用
在 **module** 中開啟 **命名空間** 把 **namespaced:true**
**store/module/user.js**
~~~
const state = {
userName: '小明'
}
const mutations = {
SET_USER_NAME(state, params){
state.userName = params
}
}
const actions = {
updateUserName({ commit }){
// 這里假裝是執行完成接口后,執行commit
commit('SET_USER_NAME','小黑')
}
}
const getters = {
firstLetter: (state) => { // 定義getter
return state.userName.substr(0, 1)
}
}
export default {
namespaced: true, // 開啟命名空間
getters,
state,
mutations,
actions
}
~~~
然后組件中給 **mapActions** 添加 **第一個參數** ,**第一個參數為模塊名稱** 。
**store.vue**
~~~
<template>
<div>
<p>{{ userName }}</p>
<button @click="handleChangeUserName">獲取用戶名稱</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
computed:{
userName: function(){
return this.$store.state.user.userName
}
},
methods:{
...mapActions('user',[
'updateUserName'
]),
handleChangeUserName(){
this.updateUserName()
}
}
}
</script>
~~~
或者可以使用 **mapActions** 配合 **Vuex** 提供的 **createNamespacedHelpers** 方法一起使用來獲取 **模塊** 中的 **action**,這種方式 **mapActions 不需要寫第一個參數** 。
~~~
<template>
<div>
<p>{{ userName }}</p>
<button @click="handleChangeUserName">獲取用戶名稱</button>
</div>
</template>
<script>
import { createNamespacedHelpers } from 'vuex'
const { mapActions } = createNamespacedHelpers('user') // createNamespacedHelpers('模塊名稱')
export default {
computed:{
userName: function(){
return this.$store.state.user.userName
}
},
methods:{
...mapActions([
'updateUserName'
]),
handleChangeUserName(){
this.updateUserName()
}
}
}
</script>
~~~
3. 使用 **dispatch** 來調用 **action**
**store.vue**
~~~
<template>
<div>
<p>{{ userName }}</p>
<button @click="handleChangeUserName">獲取用戶名稱</button>
</div>
</template>
<script>
export default {
computed:{
userName: function(){
return this.$store.state.user.userName
}
},
methods:{
handleChangeUserName(){
this.$store.dispatch('updateUserName', '我是params')
}
}
}
</script>
~~~
**store/module/user.js**
~~~
const state = {
userName: '小明'
}
const mutations = {
SET_USER_NAME(state, params){
state.userName = params
}
}
const actions = {
/**
* 通過接口更新app名稱方法
* @param { commit } 【commit】是一個方法,調用它可以提交一個【mutation】的方法,通過【mutation】來修改【state】
* @param params this.$store.dispatch('updateUserName', '我是params')時傳的參數
*/
updateUserName({ commit }, params){
console.log(params) // 我是params
// 這里假裝是執行完成接口后,執行commit
commit('SET_USER_NAME','小黑')
}
}
const getters = {
firstLetter: (state) => { // 定義getter
return state.userName.substr(0, 1)
}
}
export default {
getters,
state,
mutations,
actions
}
~~~
>[success] ### 補充
上面 **actions.js** 文件中在 **處理異步調用接口** 時使用了 **.then** 與 **.catch** ,這種是類似于 **回調的形式** ,看起來不是特別好,我們可以使用 **ES8** 的 **async** 、**await**,然后用 **try** 包裹成功要處理的數據,**catch** 處理失敗,代碼如下:
**store/actions.js**
~~~
import { getAppName } from '@/api/app' // 前面的是簡寫,等同于@/api/app.js
const actions = {
/**
* 通過接口更新app名稱方法
* @param { commit } 【commit】是一個方法,調用它可以提交一個【mutation】的方法,通過【mutation】來修改【state】
*/
// updateAppName({ commit }){
// getAppName().then(res => {
// // 解構賦值來取appName
// const { info: { appName } } = res
// commit('SET_APP_NAME', appName)
// }).catch(err => {
// console.log(err)
// })
// }
// 用ES8后
async updateAppName({ commit }){
try{
const { info: { appName } } = await getAppName()
commit('SET_APP_NAME', appName)
} catch (err) {
console.log(err)
}
}
}
export default actions
~~~
>[success] ## module
之前在創建項目時就已經把 **user** 拆分成了 **module(模塊)** ,項目龐大時,**store** 變得非常臃腫,我們它們都拆分成 **module(模塊)** ,這樣專門管理起來比較 **清晰** , 每個 **module(模塊)** 都是一個獨立的 **store** ,所以在 **module(模塊)** 中還可以包含 **module(模塊)** ,如下:
**store/module/user.js**
~~~
const state = {}
const mutations = {}
const actions = {}
const getters = {}
export default {
getters,
state,
mutations,
actions,
modules: {
//
}
}
~~~
這樣就可以在 **module模塊** 中寫 **module模塊** 拆分出更細的 **模塊**
>[success] ### 命名空間
1. **module模塊** 使用 **命名空間**
如果想給某個模塊一個密閉的空間,防止其他地方污染到這個模塊,就可以添加一個**namespaced: true**即可變成為**命名空間**,如下:
**store/module/user.js**
~~~
const state = {
userName: '小明'
}
const mutations = {
SET_USER_NAME(state, params){
state.userName = params
}
}
const actions = {
//
}
const getters = {
firstLetter: (state) => { // 定義getter
return state.userName.substr(0, 1)
}
}
export default {
namespaced: true, // 開啟命名空間
getters,
state,
mutations,
actions
}
~~~
**module(模塊)** 中使用了 **命名空間**, 在 **組件中** 使用 **mapState** 、**mapGetters** 、**mapActions** 時就要在第一個參數上添加 **模塊名稱**
**store.vue**
~~~
<template>
<div>
<p>用戶名:{{ userName }}</p>
<button @click="handleChangeUserName">修改用戶名</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
computed:{
userName: function(){ // module(模塊)下的state
return this.$store.state.user.userName
}
},
methods:{
...mapMutations('user',[ // 1. 第一個參數module(模塊)名稱,第二個參數模塊中的mutations里的方法名
'SET_USER_NAME'
]),
handleChangeUserName(){
// 2. 調用module(模塊)中mutation中的SET_USER_NAME方法
this.SET_USER_NAME('小黑')
}
}
}
</script>
~~~
或者也可以使用 **Vuex** 提供的 **createNamespacedHelpers**方法來獲取使用 **命名空間** 模塊中的方法,上述代碼中已經介紹到了 **createNamespacedHelpers** 如何使用,這里就不在再次陳述了。
2. **module(模塊)中嵌套module(模塊)模塊**
**module(模塊)** 中嵌套 **module(模塊)** 在 **組件中如何獲取** 呢?
**store.vue**
~~~
<template>
<div>
獲取模塊中嵌套的模塊中的方法
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
methods:{
...mapMutations('user/next',[ // 這樣就能獲取到模塊中嵌套模塊中的方法
'SET_USER_NAME'
])
}
}
</script>
~~~
>[success] ### 動態注冊模塊
1. **動態添加模塊**
可以通過 **$store** 提供的 **registerModule** 方法來進行 **動態添加模塊** 的操作
**store.vue**
~~~
<template>
<div>
<button @click="registerModule">動態注冊模塊</button>
<p v-for="i in todoList" :key="i">
{{ i }}
</p>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState({
// 這里需要判斷,因為默認情況下是沒有這個模塊的,這個模塊是動態添加進去的
todoList: state => state.todo ? state.todo.todoList : []
})
},
methods:{
registerModule(){
// 第一個參數:要新創建的模塊名,第二個參數就是個對象,里面寫我們的state,getter等等
this.$store.registerModule('todo', {
state:{
todoList: [
'學習mutations',
'學習actions'
]
}
})
}
}
}
</script>
~~~
2. **動態給某個模塊添加模塊(嵌套的模塊)**
~~~
<template>
<div>
<button @click="registerModule">動態注冊模塊</button>
<p v-for="i in todoList" :key="i">
{{ i }}
</p>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState({
// 這里需要判斷,因為默認情況下是沒有這個模塊的,這個模塊是動態添加進去的
todoList: state => state.user.todo ? state.user.todo.todoList : []
})
},
methods:{
registerModule(){
// 第一個參數:要新創建的模塊名,第二個參數就是個對象,里面寫我們的state,getter等等
this.$store.registerModule(['user', 'todo'], { // 這里寫成數組的形式代表給user模塊添加一個todo子模塊
state:{
todoList: [
'學習mutations',
'學習actions'
]
}
})
}
}
}
</script>
~~~
>[success] ### 補充
在 **module(模塊)** 中使用 **action** 時,實際上除了 **commit參數** 外還有 **state參數(指向的是當前模塊中的state)** 、 **rootState(指向的是store/index.js中的根狀態中的state)、dispatch** ,如果想給某個模塊一個密閉的空間,防止其他地方污染到這個模塊,就可以添加一個 **namespaced: true** 即可變成為 **命名空間** ,代碼如下:
~~~
const state = {
//
}
const mutations = {
//
}
const actions = {
/**
* 更新用戶名稱方法
* @param commit 執行一個mutation方法來修改state
* @param state 當前模塊中的state
* @param rootState 根狀態中的state
* @param dispath 可以調用同級actions中的xxx方法,例如dispath(xxx, '')
*/
updateUserName({ commit, state, rootState, dispath }){
},
xxx(){
//
}
}
export default {
namespaced: true, // 開啟命名空間
state,
mutations,
actions
}
~~~
>[warning] ## 后期補充(該項后期刪除)
vuex頁面刷新后狀態消失,狀態如何保存下來
以上的幾種mapMutations以及之前的mapState 、mapGetter這幾個都可以模塊跟根部狀態混合著寫一起用嗎
- vue 26課
- Vue-cli3.0項目搭建
- Vue-ui 創建cli3.0項目
- Vue-ui 界面詳解
- 項目目錄詳解
- public文件夾
- favicon.ico
- index.html
- src文件夾
- api文件夾
- assets文件夾
- components文件夾
- config文件夾
- directive文件夾
- lib文件夾
- mock文件夾
- mock簡明文檔
- router文件夾
- store文件夾
- views文件夾
- App.vue
- main.js
- .browserslistrc
- .editorconfig
- .eslintrc.js
- .gitignore
- babel.config.js
- package-lock.json
- package.json
- postcss.config.js
- README.en.md
- README.md
- vue.config.js
- Vue Router
- 路由詳解(一)----基礎篇
- 路由詳解(二)----進階篇
- Vuex
- Bus
- Vuex-基礎-state&getter
- Vuex-基礎-mutation&action/module
- Vuex-進階
- Ajax請求
- 解決跨域問題
- 封裝axios
- Mock.js模擬Ajax響應
- 組件封裝
- 從數字漸變組件談第三方JS庫使用
- 從SplitPane組件談Vue中如何【操作】DOM
- 渲染函數和JSX快速掌握
- 遞歸組件的使用
- 登陸/登出以及JWT認證
- 響應式布局
- 可收縮多級菜單的實現
- vue雜項
- vue遞歸組件
- vue-cli3.0多環境打包配置
- Vue+Canvas實現圖片剪切
- vue3系統入門與項目實戰
- Vue語法初探
- 初學編寫 HelloWorld 和 Counter
- 編寫字符串反轉和內容隱藏功能
- 編寫TodoList功能了解循環與雙向綁定
- 組件概念初探,對 TodoList 進行組件代碼拆分
- Vue基礎語法
- Vue 中應用和組件的基礎概念
- 理解 Vue 中的生命周期函數
- 常用模版語法講解
- 數據,方法,計算屬性和偵聽器
- 樣式綁定語法
- 條件渲染
- 列表循環渲染
- 事件綁定
- 表單中雙向綁定指令的使用
- 探索組件的理念
- 組件的定義及復用性,局部組件和全局組件
- 組件間傳值及傳值校驗
- 單向數據流的理解
- Non-Props 屬性是什么
- 父子組件間如何通過事件進行通信
- 組件間雙向綁定高級內容
- 使用匿名插槽和具名插槽解決組件內容傳遞問題
- 作用域插槽
- 動態組件和異步組件
- 基礎語法知識點查缺補漏
- Vue 中的動畫
- 使用 Vue 實現基礎的 CSS 過渡與動畫效果
- 使用 transition 標簽實現單元素組件的過渡和動畫效果
- 組件和元素切換動畫的實現
- 列表動畫
- 狀態動畫
- Vue 中的高級語法
- Mixin 混入的基礎語法
- 開發實現 Vue 中的自定義指令
- Teleport 傳送門功能
- 更加底層的 render 函數
- 插件的定義和使用
- 數據校驗插件開發實例
- Composition API
- Setup 函數的使用
- ref,reactive 響應式引用的用法和原理
- toRef 以及 context 參數
- 使用 Composition API 開發TodoList
- computed方法生成計算屬性
- watch 和 watchEffect 的使用和差異性
- 生命周期函數的新寫法
- Provide,Inject,模版 Ref 的用法
- Vue 項目開發配套工具講解
- VueCLI 的使用和單文件組件
- 使用單文件組件編寫 TodoList
- Vue-Router 路由的理解和使用
- VueX 的語法詳解
- CompositionAPI 中如何使用 VueX
- 使用 axios 發送ajax 請求
- Vue3.0(正式版) + TS
- 你好 Typescript: 進入類型的世界
- 什么是 Typescript
- 為什么要學習 Typescript
- 安裝 Typescript
- 原始數據類型和 Any 類型
- 數組和元組
- Interface- 接口初探
- 函數
- 類型推論 聯合類型和 類型斷言
- class - 類 初次見面
- 類和接口 - 完美搭檔
- 枚舉(Enum)
- 泛型(Generics) 第一部分
- 泛型(Generics) 第二部分 - 約束泛型
- 泛型第三部分 - 泛型在類和接口中的使用
- 類型別名,字面量 和 交叉類型
- 聲明文件
- 內置類型
- 總結