vuex-module-decorators
安装
npm install vuex-module-decorators
# or
yarn add vuex-module-decorators
字面意思理解就是 vuex的模块装饰器,一般结合TypeScript使用,使用这个库,可以以另一种方式编写模块。
主要功能就是用装饰器和Typescript来写vuex。好处多了类型提示
初体验
// /store/modules/foods.ts
import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'
import get from 'axios'
interface FoodEntity {
name: string
weight: number,
comments: string[]
}
@Module
export default class Food extends VuexModule {
foods: Array<FoodEntity> = []
get totalFoods(): number {
return this.foods
.filter(food => {
return food.comments && food.comments.length
})
.reduce((total, food) => {
return total + food.comments.length
}, 0)
}
@Mutation
updateFoods(foods: FoodEntity[]): void {
this.foods = foods
}
@Action({ commit: 'updateFoods' })
async fetchFoods(): Promise<any> {
return get('https://jsonplaceholder.typicode.com/comments')
}
}
输出为:/store/modules/foods.ts
// /store/modules/foods.js
module.exports = {
state: {
foods: []
},
getters: {
totalFoods: (state) => {
return state.foods
.filter(food => {
return food.comments && food.comments.length
})
.reduce((total, food) => {
return total + food.comments.length
}, 0)
}
},
mutations: {
updateFoods: (state, foods) => {
state.foods = foods
}
},
actions: {
fetchFoods: async (context) => {
const payload = await get('https://jsonplaceholder.typicode.com/comments')
context.commit('updateFoods', payload)
}
}
}
简单入门
定义一个模块
如果要定义一个模块的话,先创建一个扩展自装饰器的类,VuexModule
必须使用装饰器进行 Module
装饰
// /store/modules/foods.ts
import { VuexModule, Module } from 'vuex-module-decorators'
@module
export default class Food extends VuexModule {
someField: string = 'something'
}
store中使用
store
中注入 module
import Vue from 'vue'
import Vuex from 'vuex'
import Food from './modules/foods'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
myFood: Food
}
})
访问state
方式一:导入store
import store from '@/store'
store.state.myFood.someField
方式二:在组件中使用 this.$store
this.$store.state.myFood.someField
方式三:使用 getModule()
getModule()
创建类型安全的访问器
传统的模块需要先注册到 new Vuex.Store
的 modules
中,再使用 this.$store
访问。
使用 getModule()
访问,TypeScript可以在编写vuex中不存在内容时自动错误提示。可以在 @Module
上使用 store
模块,然后getModule(模块名)
;或者使用 getModule(模块名, store)
的方式(这种方式暂时报错,未理解)。
// /store/modules/foods.ts
import { VuexModule, Module } from 'vuex-module-decorators'
import store from '..'
@module({ dynamic:true, store, name: 'myFood' })
class MyFood extends VuexModule {
someField: string = 'something'
}
const Food = getModule(MyFood, store)
export default Food
// About.vue
import { Component, Vue } from "vue-property-decorator";
import Food from '../store/modules/foods'
@Component
export default class About extends Vue {
created(): void {
console.log(Food.foods)
console.log(Food.time) // Property 'time' does not exist on type 'MyFood'
}
}
命名空间模块
如果想以命名空间的方式使用模块,需要在@Module
装饰器中指定 namespaced: true
@Module({ namespaced: true, name: 'mm' })
class MyModule extends VuexModule {
wheels = 2
@Mutation
incrWheels(extra: number) {
this.wheels += extra
}
get axles() {
return this.wheels / 2
}
}
const store = new Vuex.Store({
modules: {
mm: MyModule
}
})
// 使用
this.$store.commit('mm/incrWheels', 3)
this.$store.dispatch('mm/action')
@Module
中的name
值,必须要和 new Vuex.Store
中的 modules
中注册的名称一致;
this.$store.dispatch('action')
调用需要转换为 this.$store.dispatch('na,e/action')
在命名空间模块中注册全局操作
为了能在全局范围内注册命名空间模块的操作,将参数 root: true
添加到修饰方法 @Action, @MutationAction
中
@Module({ namespaced: true, name: 'mm' })
class MyModule extends VuexModule {
wheels = 2
@Mutation
setWheels(wheels: number) {
this.wheels = wheels
}
@Action({ root: true, commit: 'setWheels' })
clear() {
return 0
}
get axles() {
return this.wheels / 2
}
}
const store = new Vuex.Store({
modules: {
mm: MyModule
}
})
// 使用(当全局注册一个动作后,不能被命名空间的名字调用)
this.$store.dispatch('clear')
动态模块
将特定属性传递给 @Module
装饰器即可动态注册模块。需要先创建 store,然后将 store 传递给模块
// @/store/index.ts
import Vuex from 'vuex'
const store = new Vuex.Store({
/*
...
*/
})
创建动态模块
// @/store/modules/MyModule.ts
import store from '@/store'
import {Module, VuexModule} from 'vuex-module-decorators'
@Module({dynamic: true, store, name: 'mm'})
export default class MyModule extends VuexModule {
/*
Your module definition as usual
*/
}
暂不支持动态+嵌套模块