美文网首页
vuex-module-decorators详解

vuex-module-decorators详解

作者: darkbluelove | 来源:发表于2021-08-06 17:56 被阅读0次

    参考:
    官方文档
    vuex-module-decorators

    安装 npm install vuex-module-decorators

    安装成功后就可以使用啦,先看一个完整案例

    // store/modules/passenger.ts
    import {Module,VuexModule,Mutation,Action,getModule,} from 'vuex-module-decorators';
    import store from '@/store';
    
    type User = { username: string; password: string; }
    
    // dynamic: true: 动态创建动态模块,即new Vuex.Store({})里面不用注册的.空着就行,
    // store,当前模块注册到store上.也可以写在getModule上,即getModule(PassengerStore,store)
    // namespaced: true, name: 'passenger' 命名空间
    @Module({
      name: 'passenger', dynamic: true, namespaced: true, store,
    })
    export default class PassengerStore extends VuexModule {
      // state => 要public不然外面调用不到
      public loginInfo: User[] = [];
    
      // getter
      get userNumber(): number {
        return this.loginInfo.length;
      }
    
      @Mutation
      USERINFO(user: User): void {
        console.log(user);
        this.loginInfo.push(user);
      }
      // commit的两种调用方式,第一种,Action后面的括号里面添加commit,然后return的结果就是USERINFO的参数
      @Action({ commit: 'USERINFO' })
      getZhangsan(): User {
        return { username: '张三', password: 'zhangsan' };
      }
      // 第二种,直接this.USERINFO调用;
      @Action
      getLisi(): void {
        const user = { username: '李四', password: 'lisi' };
        this.context.commit('USERINFO', user); // commit调用
        // this.USERINFO(user); // 直接调用
      }
    }
    // 使用getModule: 对类型安全的访问
    export const PassengerStoreModule = getModule(PassengerStore);
    
    // sotre/index.ts 
    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    export default new Vuex.Store({ }); // 由于passenger->dynamic: true: 是动态创建动态模块,所以不需要再次注册
    
    
    image.gif

    index.vue页面使用

    <script lang="ts">
    import { Component, Vue } from 'vue-property-decorator';
    import { PassengerStoreModule } from '@/store/modules/passenger';
    
    @Component
    export default class IndexPage extends Vue {
        created() {
            console.log(PassengerStoreModule.loginInfo); // state
            console.log(PassengerStoreModule.userNumber); // getter
            PassengerStoreModule.getZhangsan(); // actions
            PassengerStoreModule.getLisi(); // actions
        }
    }
    </script>
    
    image.gif

    上面的案例是一个,使用了动态注册,下面我们详细说下,具体的使用
    @Component state getter

    @Mutations

    @Actions

    @MutationsActions

    getModule

    动态模块

    state:

    import { Module, VuexModule } from 'vuex-module-decorators'
    
    @Module
    export default class Vehicle extends VuexModule {
      wheels = 2
    }
    
    等同于下面的代码
    
    export default {
      state: { wheels: 2 }
    }
    
    image.gif

    getter

    import { Module, VuexModule } from 'vuex-module-decorators'
    
    @Module
    export default class Vehicle extends VuexModule {
      wheels = 2
      get axles() {
        return this.wheels / 2
      }
    }
    
    等同于下面的代码
    
    export default {
      state: { wheels: 2 },
      getters: {
        axles: (state) => state.wheels / 2
      }
    }
    
    image.gif

    @Mutations

    import { Module, VuexModule, Mutation } from 'vuex-module-decorators'
    
    @Module
    export default class Vehicle extends VuexModule {
      wheels = 2
    
      @Mutation
      puncture(n: number) {
        this.wheels = this.wheels - n
      }
    }
    
    等同于下面的代码
    
    export default {
      state: { wheels: 2 },
      mutations: {
        puncture: (state, payload) => {
          state.wheels = state.wheels - payload
        }
      }
    }
    
    image.gif

    @Actions

    import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators'
    import { get } from 'request'
    
    @Module
    export default class Vehicle extends VuexModule {
      wheels = 2
    
      @Mutation
      addWheel(n: number) {
        this.wheels = this.wheels + n
      }
    
      @Action
      async fetchNewWheels(wheelStore: string) {
        const wheels = await get(wheelStore)
        this.context.commit('addWheel', wheels)
      }
    }
    
    等同于下面的代码
    
    const request = require('request')
    export default {
      state: { wheels: 2 },
      mutations: {
        addWheel: (state, payload) => {
          state.wheels = state.wheels + payload
        }
      },
      actions: {
        fetchNewWheels: async (context, payload) => {
          const wheels = await request.get(payload)
          context.commit('addWheel', wheels)
        }
      }
    }
    
    image.gif

    @MutationAction

    在vuex中是要通过commit来更改state中的数据.在vuex-module-decorators中有MutationAction修饰器,可以直接修改state数据.

    export default class PassengerStore extends VuexModule {
      public username = '';
      public password = '';
    
      //'username'和'password'被返回的对象替换,
      //格式必须为`{username:...,password:...}` 
      @MutationAction({ mutate: ['username', 'password'] })
      async setPassenger(name: string) {
        const response: any = await request(name); // 接口返回 [{name:'张三',password:'123456'}]
        // 此处返回值必须和上面mutate后面的名称保持一致;
        return {
          username: response[0].name,
          password: response[0].password,
        };
      }
    }
    
    // index.vue中使用
    <template>
        <div class="">
            用户名:{{PassengerStoreModule.username}}<br/>
            密码:{{PassengerStoreModule.password}}<br/>
            <button @click="getPassenger()">getPassenger</button>
        </div>
    </template>
    
    ...
    @Component
    export default class IndexPage extends Vue {
        private PassengerStoreModule: any = PassengerStoreModule;
    
        getPassenger() {
            PassengerStoreModule.setPassenger('西施');
        }
    }
    
    // 运行过后,点击getPassenger按钮,用户名和密码会发生变化哦
    
    
    image.gif

    getModule:创建类型安全的访问

    传统是需要注册到的new Vuex.Store上,然后通过thisstore访问,使用getModule访问类型更加安全, 可以再module上使用store模块,然后getModule(模块名) 也可以getModule(模块名,this.store)的形式

    import { Module, VuexModule, getModule } from 'vuex-module-decorators'
    import store from '@/store'
    
    // 1\. module上使用store
    @Module({ dynamic: true, store, name: 'mymod' })
    class MyModule extends VuexModule {
      someField: number = 10
    }
    const myMod = getModule(MyModule)
    myMod.someField //works
    myMod.someOtherField //Typescript will error, as field doesn't exist
    
    // 2\. module上不使用store,  getModule使用store
    @Module({ dynamic: true, name: 'mymod' })
    class MyModule extends VuexModule {
      someField: number = 10
    }
    const myMod = getModule(MyModule,store)
    ...
    
    image.gif

    动态模块

    动态模块:使用getModule获取数据,页面调用的时候,store.state里面才会显示改模块的信息
    非动态模块:页面初始的时候,手动添加到new Vuex.Store({ modules: { user: PassengerStore } }),页面刷新state里面可以直接看到当前模块的变量以及方法。

    我们将上面的passenger.ts改写才非动态模块

    import {Module,VuexModule,Mutation,Action,getModule,} from 'vuex-module-decorators';
    // import store from '@/store'; // 去掉store
    
    type User = { username: string; password: string; }
    
    @Module({name: 'user', namespaced: true,})
    export default class PassengerStore extends VuexModule {
      // ...同上方案例一模一样
    }
    
    // 因为getModule是要对应store的.上面去掉了store,所以也要去掉 getModule,
    // export const PassengerStoreModule = getModule(PassengerStore); 
    
    // store/index.ts
    import Vue from 'vue';
    import Vuex from 'vuex';
    import PassengerStore from './modules/passenger';
    
    Vue.use(Vuex);
    export default new Vuex.Store({
        modules: {
            user: PassengerStore
        },
    });
    
    //index.vue 使用
    import PassengerStore from '@/store/modules/passenger';
    import { getModule } from 'vuex-module-decorators';
    
    ...
    created() {
      const PassengerStoreModule = getModule(PassengerStore, this.$store);
    
      console.log(PassengerStoreModule.loginInfo);
      PassengerStoreModule.getZhangsan();
      PassengerStoreModule.getLisi();
      console.log(PassengerStoreModule.userNumber);
      }
    ...
    
    
    image.gif

    再试运行,发现跟之前的结果没差别.

    命名空间

    const moduleA1 = {
        namespaced: true,
        ...
    };
    const moduleA = {
        namespaced: true,
        modules: {
            a1: moduleA1,
        },
    };
    const moduleB = {
        // no namespaced
        ...
      };
    export default new Vuex.Store({
        ...
        modules: {
            a: moduleA,
            b: moduleB,
        },
    });
    
    image.gif

    上面的例子,store包含了两个模块,a和b,a模块里面包含了a1,
    打个比方a,a1和b的actions里面分别有个getMsgA(),getMsgB(),getMsgA1()方法,
    在页面上用this.store.dispatch调用这些方法. a和a1都有命名空间,所以 this.store.dispatch('a/getMsgA');
    this.store.dispatch('a/a1/getMsgA1'); 由于b没有命名空间,所以this.store.dispatch('b/getMsgB');是会报错的.

    那么如果再a1里面如果查看root的state呢,vux提供了rootState, rootGetters.

    actions: {
          someAction ({ dispatch, commit, getters, rootGetters }) {
            getters.someGetter // -> 'a/someGetter'
            rootGetters.someGetter // -> 'someGetter'
    
            dispatch('someOtherAction') // -> 'a/someOtherAction'
            dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
    
            commit('someMutation') // -> 'a/someMutation'
            commit('someMutation', null, { root: true }) // -> 'someMutation'
          }
    
    image.gif

    demo地址:https://github.com/slailcp/vue-cli3/blob/master/src/pc-project/store/modules/login.ts

    相关文章

      网友评论

          本文标题:vuex-module-decorators详解

          本文链接:https://www.haomeiwen.com/subject/ctumvltx.html