【愚公系列】2022年05月 vue3系列 store的装饰器使用封装(TS版)


前言

1.vuex-module-decorators

vuex-module-decorators官网:https://gitcode.net/mirrors/championswimmer/vuex-module-decorators?utm_source=csdn_github_accelerator

npm安装:

npm install  vuex-module-decorators

1.1 vuex传统方式的使用

const moduleA = {
    
    
  state: {
    
     ... },
  mutations: {
    
     ... },
  actions: {
    
     ... },
  getters: {
    
     ... }
}

const moduleB = {
    
    
  state: {
    
     ... },
  mutations: {
    
     ... },
  actions: {
    
     ... }
}

const store = new Vuex.Store({
    
    
  modules: {
    
    
    a: moduleA,
    b: moduleB
  }
})

1.2 vuex装饰器的使用

import {
    
     Module, VuexModule, Mutation, Action } from 'vuex-module-decorators'

@Module
export default class Counter2 extends VuexModule {
    
    
  count = 0

  @Mutation
  increment(delta: number) {
    
    
    this.count += delta
  }
  @Mutation
  decrement(delta: number) {
    
    
    this.count -= delta
  }
  
  @Action({
    
     commit: 'increment' })
  incr() {
    
    
    return 5
  }

  @Action({
    
     commit: 'decrement' })
  decr() {
    
    
    return 5
  }
}

一、vuex-module-decorators组件

1.state

import {
    
     Module, VuexModule } from 'vuex-module-decorators'
 
@Module
export default class Vehicle extends VuexModule {
    
    
  wheels = 2
}

等同于下面的代码

export default {
    
    
  state: {
    
     wheels: 2 }
}

2.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
  }
}

3.@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
    }
  }
}

4.@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)
    }
  }
}

5.@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('愚公');
    }
}

6.getModule

传统是需要注册到的new Vuex.Store上,然后通过this$store访问,使用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)

动态模块使用

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);
  }

二、完整案例

1.用户权限模块AuthModule

import ApiService from "@/core/services/ApiService";
import JwtService from "@/core/services/JwtService";
import {
    
     Actions, Mutations } from "@/store/enums/StoreEnums";
import {
    
     Module, Action, Mutation, VuexModule } from "vuex-module-decorators";

//用户接口
export interface User {
    
    
  name: string;
  surname: string;
  email: string;
  password: string;
  token: string;
}
//用户权限信息接口
export interface UserAuthInfo {
    
    
  errors: Array<string>;
  user: User;
  isAuthenticated: boolean;
}
//动态创建权限模块
@Module
export default class AuthModule extends VuexModule implements UserAuthInfo {
    
    
  errors = [];
  user = {
    
    } as User;
  isAuthenticated = !!JwtService.getToken();

  /**
   * 获取当前用户对象
   * @returns User
   */
  get currentUser(): User {
    
    
    return this.user;
  }

  /**
   * 验证用户身份验证
   * @returns boolean
   */
  get isUserAuthenticated(): boolean {
    
    
    return this.isAuthenticated;
  }

  /**
   * 获取身份验证错误
   * @returns array
   */
  get getErrors(): Array<string> {
    
    
    return this.errors;
  }
  /**
   * 设置错误信息
   * @param error string
   */
  @Mutation
  [Mutations.SET_ERROR](error) {
    
    
    this.errors = error;
  }
  /**
   * 设置令牌
   * @param user 用户信息
   */
  @Mutation
  [Mutations.SET_AUTH](user) {
    
    
    this.isAuthenticated = true;
    this.user = user;
    this.errors = [];
    JwtService.saveToken(this.user.token);
  }
  /**
   * 设置用户
   * @param use 用户信息
   */
  @Mutation
  [Mutations.SET_USER](user) {
    
    
    this.user = user;
  }
  /**
   * 设置密码
   * @param password 密码
   */
  @Mutation
  [Mutations.SET_PASSWORD](password) {
    
    
    this.user.password = password;
  }
  /**
   * 删除令牌
   */
  @Mutation
  [Mutations.PURGE_AUTH]() {
    
    
    this.isAuthenticated = false;
    this.user = {
    
    } as User;
    this.errors = [];
    JwtService.destroyToken();
  }
  /**
   * 用户登录
   * @param credentials 登录信息
   * @returns 返回登录状态
   */
  @Action
  [Actions.LOGIN](credentials) {
    
    
    return new Promise<void>((resolve, reject) => {
    
    
      ApiService.post("login", credentials)
        .then(({
     
      data }) => {
    
    
          this.context.commit(Mutations.SET_AUTH, data);
          resolve();
        })
        .catch(({
     
      response }) => {
    
    
          this.context.commit(Mutations.SET_ERROR, response.data.errors);
          reject();
        });
    });
  }
  /**
   * 用户退出
   */
  @Action
  [Actions.LOGOUT]() {
    
    
    this.context.commit(Mutations.PURGE_AUTH);
  }
  /**
   * 用户注册
   * @param credentials 用户注册信息
   * @returns 
   */
  @Action
  [Actions.REGISTER](credentials) {
    
    
    return new Promise<void>((resolve, reject) => {
    
    
      ApiService.post("registration", credentials)
        .then(({
     
      data }) => {
    
    
          this.context.commit(Mutations.SET_AUTH, data);
          resolve();
        })
        .catch(({
     
      response }) => {
    
    
          this.context.commit(Mutations.SET_ERROR, response.data.errors);
          reject();
        });
    });
  }
  /**
   * 设置密码
   * @param payload 用户信息
   * @returns 
   */
  @Action
  [Actions.FORGOT_PASSWORD](payload) {
    
    
    return new Promise<void>((resolve, reject) => {
    
    
      ApiService.post("forgot_password", payload)
        .then(({
     
      data }) => {
    
    
          this.context.commit(Mutations.SET_AUTH, data);
          resolve();
        })
        .catch(({
     
      response }) => {
    
    
          console.log(response.data.errors);
          this.context.commit(Mutations.SET_ERROR, response.data.errors);
          reject();
        });
    });
  }
  /**
   * 校验权限
   */
  @Action
  [Actions.VERIFY_AUTH]() {
    
    
    if (JwtService.getToken()) {
    
    
      ApiService.setHeader();
      ApiService.get("verify")
        .then(({
     
      data }) => {
    
    
          this.context.commit(Mutations.SET_AUTH, data);
        })
        .catch(({
     
      response }) => {
    
    
          this.context.commit(Mutations.SET_ERROR, response.data.errors);
        });
    } else {
    
    
      this.context.commit(Mutations.PURGE_AUTH);
    }
  }
  /**
   * 更新用户信息
   * @param payload 用户信息
   * @returns 返回结果
   */
  @Action
  [Actions.UPDATE_USER](payload) {
    
    
    ApiService.setHeader();
    return new Promise<void>((resolve, reject) => {
    
    
      ApiService.post("update_user", payload)
        .then(({
     
      data }) => {
    
    
          this.context.commit(Mutations.SET_USER, data);
          resolve();
        })
        .catch(({
     
      response }) => {
    
    
          this.context.commit(Mutations.SET_ERROR, response.data.errors);
          reject();
        });
    });
  }
}

2.StoreEnums

enum Actions {
    
    
  // action types
  ADD_BODY_CLASSNAME = "addBodyClassName",
  REMOVE_BODY_CLASSNAME = "removeBodyClassName",
  ADD_BODY_ATTRIBUTE = "addBodyAttribute",
  REMOVE_BODY_ATTRIBUTE = "removeBodyAttribute",
  ADD_CLASSNAME = "addClassName",
  VERIFY_AUTH = "verifyAuth",
  LOGIN = "login",
  LOGOUT = "logout",
  REGISTER = "register",
  UPDATE_USER = "updateUser",
  FORGOT_PASSWORD = "forgotPassword",
  SET_BREADCRUMB_ACTION = "setBreadcrumbAction"
}

enum Mutations {
    
    
  // mutation types
  SET_CLASSNAME_BY_POSITION = "appendBreadcrumb",
  PURGE_AUTH = "logOut",
  SET_AUTH = "setAuth",
  SET_USER = "setUser",
  SET_PASSWORD = "setPassword",
  SET_ERROR = "setError",
  SET_BREADCRUMB_MUTATION = "setBreadcrumbMutation",
  SET_LAYOUT_CONFIG = "setLayoutConfig",
  RESET_LAYOUT_CONFIG = "resetLayoutConfig",
  OVERRIDE_LAYOUT_CONFIG = "overrideLayoutConfig",
  OVERRIDE_PAGE_LAYOUT_CONFIG = "overridePageLayoutConfig"
}

export {
    
     Actions, Mutations };

3.index

import {
    
     createStore } from "vuex";
import {
    
     config } from "vuex-module-decorators";

import AuthModule from "@/store/modules/AuthModule";

config.rawError = true;

const store = createStore({
    
    
  modules: {
    
    
    AuthModule
  }
});

export default store;

4.main

import {
    
     createApp } from "vue";
import App from "./App.vue";

/*
TIP: To get started with clean router change path to @/router/clean.ts.
 */
import router from "./router";
import store from "./store";
import ElementPlus from "element-plus";
import i18n from "@/core/plugins/i18n";

//imports for app initialization
import MockAdapter from "@/core/mock/MockService";
import ApiService from "@/core/services/ApiService";
import {
    
     initApexCharts } from "@/core/plugins/apexcharts";
import {
    
     initInlineSvg } from "@/core/plugins/inline-svg";
import {
    
     initVeeValidate } from "@/core/plugins/vee-validate";

import "@/core/plugins/keenthemes";
import "@/core/plugins/prismjs";
import "bootstrap";

const app = createApp(App);

app.use(store);
app.use(router);
app.use(ElementPlus);

ApiService.init(app);
MockAdapter.init(app);
initApexCharts(app);
initInlineSvg(app);
initVeeValidate();

app.use(i18n);

app.mount("#app");

5.在vue中使用

<script lang="ts">
import {
    
     defineComponent, ref } from "vue";
import {
    
     ErrorMessage, Field, Form } from "vee-validate";
import {
    
     Actions } from "@/store/enums/StoreEnums";
import {
    
     useStore } from "vuex";
import {
    
     useRouter } from "vue-router";
import Swal from "sweetalert2/dist/sweetalert2.min.js";
import * as Yup from "yup";

export default defineComponent({
    
    
  name: "sign-in",
  components: {
    
    
    Field,
    Form,
    ErrorMessage
  },
  setup() {
    
    
    const store = useStore();
    const router = useRouter();

    const submitButton = ref<HTMLElement | null>(null);

    //创建表单验证对象
    const login = Yup.object().shape({
    
    
      email: Yup.string()
        .email()
        .required()
        .label("Email"),
      password: Yup.string()
        .min(4)
        .required()
        .label("Password")
    });

    //表单提交功能
    const onSubmitLogin = values => {
    
    
      // 清除现有错误
      store.dispatch(Actions.LOGOUT);

      setTimeout(() => {
    
    
        store
          .dispatch(Actions.LOGIN, values)
          .then(() => {
    
    
            Swal.fire({
    
    
              text: "All is cool! Now you submit this form",
              icon: "success",
              buttonsStyling: false,
              confirmButtonText: "Ok, got it!",
              customClass: {
    
    
                confirmButton: "btn fw-bold btn-light-primary"
              }
            }).then(function() {
    
    
              router.push({
    
     name: "dashboard" });
            });
          })
          .catch(() => {
    
    
            Swal.fire({
    
    
              text: store.getters.getErrors[0],
              icon: "error",
              buttonsStyling: false,
              confirmButtonText: "Try again!",
              customClass: {
    
    
                confirmButton: "btn fw-bold btn-light-danger"
              }
            });
          });
      }, 2000);
    };

    return {
    
    
      onSubmitLogin,
      login,
      submitButton
    };
  }
});
</script>

猜你喜欢

转载自blog.csdn.net/aa2528877987/article/details/124863953
今日推荐