深入理解vuex2.0 之 modules
什么是module?
背景:在Vue中State使用是單一狀態(tài)樹結(jié)構(gòu),應(yīng)該的所有的狀態(tài)都放在state里面,如果項目比較復(fù)雜,那state是一個很大的對象,store對象也將對變得非常大,難于管理。
module:可以讓每一個模塊擁有自己的state、mutation、action、getters,使得結(jié)構(gòu)非常清晰,方便管理。
怎么用module?
一般結(jié)構(gòu)
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB})
模塊內(nèi)部的數(shù)據(jù):①內(nèi)部state,模塊內(nèi)部的state是局部的,也就是模塊私有的,比如是car.js模塊state中的list數(shù)據(jù),我們要通過this.$store.state.car.list獲?。虎趦?nèi)部getter、mutation和action,仍然注冊在全局命名空間內(nèi),這是為了多模塊可以同時響應(yīng)同一mutation;this.$store.state.car.carGetter的結(jié)結(jié)果是undefined,而通過this.$store.state.carGetter則可以拿到。
傳參:getters====({state(局部狀態(tài)),getters(全局getters對象),roosState(根狀態(tài))});actions====({state(局部狀態(tài)),commit,roosState(根狀態(tài))}).
新建一個項目體驗一下,通過vue –cli新建一個項目vuemodule, 不要忘記安裝vuex.
1, 在src 目錄下新一個login文件夾,在里面新建index.js 用于存放login 模塊的狀態(tài)。 為了簡單起見,我把模塊下的state, actions,mutations, getters 全放在index.js文件中。
先簡單給它增加一個狀態(tài),userName: “sam”
const state = { useName: "sam" }; const mutations = { }; const actions = { }; const getters = { }; // 不要忘記把state, mutations等暴露出去。 export default { state, mutations, actions, getters }
2,在src 目錄下,再新建一個 store.js 這是根store, 它通過modules 屬性引入 login模塊。
import Vue from "vue"; import Vuex from "Vuex"; Vue.use(Vuex); // 引入login 模塊 import login from "./login" export default new Vuex.Store({ // 通過modules屬性引入login 模塊。 modules: { login: login } })
3, 在main.js中引入store, 并注入到vue 根實例中。
import Vue from 'vue' import App from './App.vue' // 引入store import store from "./store" new Vue({ el: '#app', store, // 注入到根實例中。 render: h => h(App) })
4,在 app.vue 中通過computed屬性獲取到login下的state. 這里要注意,在沒有modules 的情況下,組件中通過 this.$store.state.屬性名 可以獲取到,但是有modules 之后,state 被限制到login 的命名空間(模塊)下,所以屬性名前面必須加模塊名(命名空間),組件中通過 this.$store.state.模塊名.屬性名,在這里是 this.$store.state.login.userName
<template> <div id="app"> <img src="./assets/logo.png"> <h1>{{useName}}</h1> </div> </template> <script> export default { // computed屬性,從store 中獲取狀態(tài)state,不要忘記login命名空間。 computed: { useName: function() { return this.$store.state.login.useName } } } </script>
組件中成功獲取到狀態(tài)。項目目錄和展示如下
4 ,通過actions, mutations 改變名字, 這就涉及到dispatch action, commit mutations, mutations 改變state.
先在login 文件夾 index.js中添加changeName action 和 CHANGE_NAME mutations.
const mutations = { CHANGE_NAME (state, anotherName) { state.useName = anotherName; } }; const actions = { changeName ({commit},anotherName) { commit("CHANGE_NAME", anotherName) } };
在app.vue 中添加一個按鈕:<button> change to json</button>, 點擊時,dispatch 一個 action. 那在組件中怎么dispatch actions 呢?
在模塊中,state 是被限制到模塊的命名空間下,需要命名空間才能訪問。 但actions 和mutations, 其實還有 getters 卻沒有被限制,在默認情況下,它們是注冊到全局命名空間下的,所謂的注冊到全局命名空間下,其實就是我們訪問它們的方式和原來沒有module 的時候是一樣的。比如沒有module 的時候,this.$store.dispatch(“actions”), 現(xiàn)在有了modules, actions 也寫在了module 下面(changeName 寫到了login目錄下的index.js中),我們?nèi)匀豢梢赃@么寫,this.$store.dispatch(“changeName”), 組件中的getters, 也是通過 this.$store.getters.module中g(shù)etters 來獲取。
<template> <div id="app"> <img src="./assets/logo.png"> <h1>{{useName}}</h1> <!-- 添加按鈕 --> <div> <button @click="changeName"> change to json</button> </div> </div> </template> <script> export default { // computed屬性,從store 中獲取狀態(tài)state,不要忘記login命名空間。 computed: { useName: function() { return this.$store.state.login.useName } }, methods: { // 和沒有modules的時候一樣,同樣的方式dispatch action changeName() { this.$store.dispatch("changeName", "Jason") } } }
5, 局部參數(shù)
雖然dispatch action和 commit mutations 可以全局使用,但是寫在module 中的actions, mutations 和getters, 它們獲得的默認參數(shù)卻不是全局的,都是局部的,被限定在它們所在的模塊中的。比如mutations和getters 會獲得state 作為第一個默認參數(shù),這個state參數(shù),就是限定在mutations 和getters 所在模塊的state對象,login 文件夾下的mutations 和getters 只會獲取到當前index.js 中的 state 作為參數(shù) 。 actions 會獲得一個context 對象作為參數(shù),這個context 對象就是當前module 的實例,module 相當于一個小store.
那么怎樣才能獲取到根store 中的state 和 getters 呢? Vuex 提供了 rootState, rootGetters 作為module 中 getters 中默認參數(shù), actions中context 對象,也會多了兩個屬性,context.getters, context. rootState, 這些全局的默認參數(shù),都排在局部參數(shù)的后面。
我們在store.js中添加 state, getters:
export default new Vuex.Store({ // 通過modules屬性引入login 模塊。 modules: { login: login }, // 新增state, getters state: { job: "web" }, getters: { jobTitle (state){ return state.job + "developer" } } })
login 目錄下的 index.js
const actions = { // actions 中的context參數(shù)對象多了 rootState 參數(shù) changeName ({commit, rootState},anotherName) { if(rootState.job =="web") { commit("CHANGE_NAME", anotherName) } } }; const getters = { // getters 獲取到 rootState, rootGetters 作為參數(shù)。 // rootState和 rootGetter參數(shù)順序不要寫反,一定是state在前,getter在后面,這是vuex的默認參數(shù)傳遞順序, 可以打印出來看一下。 localJobTitle (state,getters,rootState,rootGetters) { console.log(rootState); console.log(rootGetters); return rootGetters.jobTitle + " aka " + rootState.job } };
app.vue 增加h2 展示 loacaJobTitle, 這個同時證明了getters 也是被注冊到全局中的。
<template> <div id="app"> <img src="./assets/logo.png"> <h1>{{useName}}</h1> <!-- 增加h2 展示 localJobTitle --> <h2>{{localJobTitle}}</h2> <!-- 添加按鈕 --> <div> <button @click="changeName"> change to json</button> </div> </div> </template> <script> import {mapActions, mapState,mapGetters} from "vuex"; export default { // computed屬性,從store 中獲取狀態(tài)state,不要忘記login命名空間。 computed: { ...mapState({ useName: state => state.login.useName }), // mapGeter 直接獲得全局注冊的getters ...mapGetters(["localJobTitle"]) }, methods: { changeName() { this.$store.dispatch("changeName", "Jason") } } } </script>
6, 其實actions, mutations, getters, 也可以限定在當前模塊的命名空間中。只要給我們的模塊加一個namespaced 屬性:
const state = { useName: "sam" }; const mutations = { CHANGE_NAME (state, anotherName) { state.useName = anotherName; } }; const actions = { changeName ({commit, rootState},anotherName) { if(rootState.job =="web") { commit("CHANGE_NAME", anotherName) } }, alertName({state}) { alert(state.useName) } }; const getters = { localJobTitle (state,getters,rootState,rootGetters) { return rootGetters.jobTitle + " aka " + rootState.job } }; // namespaced 屬性,限定命名空間 export default { namespaced:true, state, mutations, actions, getters }
當所有的actions, mutations, getters 都被限定到模塊的命名空間下,我們dispatch actions, commit mutations 都需要用到命名空間。如 dispacth("changeName"), 就要變成 dispatch("login/changeName"); getters.localJobTitle 就要變成 getters["login/localJobTitle"]
app.vue 如下:
<template> <div id="app"> <img src="./assets/logo.png"> <h1 @click ="alertName">{{useName}}</h1> <!-- 增加h2 展示 localJobTitle --> <h2>{{localJobTitle}}</h2> <!-- 添加按鈕 --> <div> <button @click="changeName"> change to json</button> </div> </div> </template> <script> import {mapActions, mapState,mapGetters} from "vuex"; export default { // computed屬性,從store 中獲取狀態(tài)state,不要忘記login命名空間。 computed: { ...mapState("login",{ useName: state => state.useName }), localJobTitle() { return this.$store.getters["login/localJobTitle"] } }, methods: { changeName() { this.$store.dispatch("login/changeName", "Jason") }, alertName() { this.$store.dispatch("login/alertName") } } } </script>
有了命名空間之后,mapState, mapGetters, mapActions 函數(shù)也都有了一個參數(shù),用于限定命名空間,每二個參數(shù)對象或數(shù)組中的屬性,都映射到了當前命名空間中。
<script> import {mapActions, mapState,mapGetters} from "vuex"; export default { computed: { // 對象中的state 和數(shù)組中的localJobTitle 都是和login中的參數(shù)一一對應(yīng)。 ...mapState("login",{ useName: state => state.useName }), ...mapGetters("login", ["localJobTitle"]) }, methods: { changeName() { this.$store.dispatch("login/changeName", "Jason") }, ...mapActions('login', ['alertName']) } } </script>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
探秘Vue異步更新機制中nextTick的原理與實現(xiàn)
nextTick?是?Vue?提供的一個重要工具,它的作用主要體現(xiàn)在幫助我們更好地處理異步操作,下面就跟隨小編一起來探索一下nextTick的原理與實現(xiàn)吧2024-02-02Vue Element-ui實現(xiàn)樹形控件節(jié)點添加圖標詳解
這篇文章主要為大家介紹了Element-ui實現(xiàn)樹形控件節(jié)點添加圖標,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-11-11Ant?Design?Vue中的table與pagination的聯(lián)合使用方式
這篇文章主要介紹了Ant?Design?Vue中的table與pagination的聯(lián)合使用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10