前言
在一个企业级的应用里,状态存储器起着举足轻重的作用。与我们日常的练手项目不同,企业级项目的vuex更专注更集中更便捷。
简单回顾
让我们简单回顾一下vuex这个插件的用法。
Vuex 的状态存储是响应式的。
当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
只能通过mutation改变vuex里面的store。不能直接改变store里面的状态
mutations: {
setViewList(state, list) {
state.viewList = list;
}
}
集中化、显式化地修改stroe里的状态,方便管理方便阅读。
最简单的例子
import { createApp } from 'vue'
import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
state () {
return {
count: 0
}
},
mutations: {
increment (state) {
state.count++
}
}
})
const app = createApp({ /* 根组件 */ })
// 将 store 实例作为插件安装
app.use(store)
vue组件里:
methods: {
update() {
// 修改
this.$store.commit('increment')
// 查看
console.log(this.$store.state.count)
}
}
项目里的应用
我们在项目的src文件夹里创建一个store专门用来放置状态管理相关的逻辑
index.js:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
index是整个状态管理的入口文件,Vue.use(Vuex)会在创建vue实例之前执行。Vue.use的作用想必大家都很清楚了:安装 Vue.js 插件,如果传入的是一个对象,则会执行它的install方法。如果传入的是一个函数,那么他将执行这个函数。
举个例子:
// plugin.js ————src\plugin\plugin.js
export const plugin = {
install() {
alert("我是install内的代码")
},
}
// main.js中引入自定义插件
import Vue from "vue"
import {Plugin} from './plugin/plugin.js'
Vue.use(plugin) // 页面显示"我是install内的代码"
当然啦,index.js会被Vue实例调用
import store from './store';
import router from './router';
import App from './App.vue';
// 初始化Vue
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app');
缕清了最基本的引用思路,我们再回头来仔细琢磨里面的门道。
store/index.js
这个文件是需要抛出一个vuex实例给vue用的。
export default new Vuex.Store({
...
})
这里面仓库和方法等属性都是空的
new Vuex.Store({
state: {},
mutations: {},
actions: {},
strict: true,
...
}
因为我们要借助模块化思想来书写这个状态管理器
import global from './modules/global';
import form from './modules/form';
import formDesign from './modules/form-design';
...
const store = new Vuex.Store({
state: {},
mutations: {},
actions: {},
strict: true,
modules: {
global,
form,
formDesign,
...
},
...
}
此时这个项目结构就很简单清晰啦 ,我们来看看模块的状态管理器长啥样
其实就是和状态管理器一样,有state有mutations ,甚至你喜欢的话,还可以往里面继续嵌套模块module。形成三级、四级、五级等等多层级的模块化状态管理器。
细心的朋友,看到这里有个namespaced啦。如果不了解命名空间的相关知识,请看我这篇推文,否则后面可能会理解不了。
Vuex命名空间及如何获取根模块、兄弟模块状态管理器_AI3D_WebEngineer的博客-CSDN博客https://blog.csdn.net/weixin_42274805/article/details/133269196?spm=1001.2014.3001.5502
优雅书写命名空间
项目使用的是ts+vue。所以借助Vuex-class进行绑定(主要用于Vue2.0+TS使用store的全局变量和方法)
使用方法:
1.安装vuex-class
npm install --save vuex-class
2.全局使用vuex-class的方法:
// store/index.js
export default new Vuex.Store({
state : {
count : -1,
},
mutations: {
addcount(state){
state.count++
}
},
actions: {
change({commit}){
commit("addcount")
}
},
})
// page.vue
//首先引入
import {Action,State} from'vuex-class'
//直接使用装饰器就可以获取到了
@State('count') globalCount
@Action('change') changecount
//然后就是直接调用
create(){
log(`vuex中的count数据为${this.globalCount}`)
}
add(){
//调用一次add()就触发一次
this.changecount()
}
这样子确实能用,但不美观。我们结合命名空间来优雅地书写 。
3.分模块使用
当分模块调用state、mutations、actions、getters时,需要引入namespace,并且调用的时候需要加上@nameSpaceName
先来看日常是怎么写的:
import common from './common'
export default new Vuex.Store({
state:{},
modules: {
// here here!
common
}
})
// common.js
export default {
namespaced: true,
state: {count:0}
mutations: {
ADD_COUNT(state){
state.count++
}
}
}
import {Action, namespace,State} from'vuex-class'
// 获取com模块
const mymodule = namespace('common')
@Component()
export default class HomeView extends Vue {
@mymodule.State('count') stateCount
@mymodule.Mutation('ADD_COUNT') addCount
created() {
console.log(this.stateCount)
this.addCount()
}
}
在项目里这么写肯定是没问题的,但是太繁琐,不工整。我们回归到项目里:
src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import global from './modules/global';
import form from './modules/form';
import formDesign from './modules/form-design';
import application from './modules/application';
import formSetting from './modules/form-setting';
import formPermission from './modules/form-permission';
import formView from './modules/form-view';
import file from './modules/file';
...
Vue.use(Vuex);
const store = new Vuex.Store({
state: {},
mutations: {},
actions: {},
strict: true,
modules: {
global,
form,
formDesign,
application,
formSetting,
file,
...
}
});
export default store;
紧接着,我们创建一个枚举类文件
src/enum/store.js
import { namespace } from 'vuex-class';
export const globalModule = namespace('global');
export const formModule = namespace('form');
export const crossStorageModule = namespace('crossStorage');
export const formDesignModule = namespace('formDesign');
export const formSettingModule = namespace('formSetting');
export const applicationModule = namespace('application');
export const formPermissionModule = namespace('formPermission');
export const formViewModule = namespace('formView');
...
这么写有什么好处?其实就是把所有的命名空间模块枚举出来。实现按需引入。
具体项目文件:不需要再引入import {Action, namespace,State} from'vuex-class'
import { formDesignModule, applicationModule } from '@/enum/store';
...
@Component({
components: {},
})
export default class DashboardDesignLayout extends Vue {
...
@formDesignModule.State form;
@formDesignModule.Action init;
@formDesignModule.Mutation reset;
@applicationModule.Action getApplicationDetail;
@applicationModule.State applicationDetail;
@formDesignModule.Mutation saveForm;
@formDesignModule.Getter isFormStatistics;
@formDesignModule.Getter isApplicationHome;
}
注意一下。比如我们要用这个init方法。项目里应该这么写:
async handleEdit() {
....
await this.init(result.pkId);
}
vuex里应该这么写:
actions: {
async init({ commit }, formId) {
const form = await getFormData(formId);
commit('saveForm', form);
},
}
用{commit, state,getters,dispatch}跟传参区分开来。注意传参如果有多个,最好用对象传参!