vuex实现模块化以及ts支持

当使用组合式API编写Vue组件时,您可能希望useStore返回类型化store。为了useStore能正确返回类型化store,必须执行以下步骤:

  1. 定义类型化的InjectionKey。
  2. 将store安装到Vue应用时提供类型化的Injectionkey。
  3. 将类型化的InjectionKey传给useStore方法。

首先,使用Vue的InjectionKey接口和自己的store类型定义来定义key

官网有提供
https://vuex.vuejs.org/zh/guide/typescript-support.html

在store文件夹中放入modules文件夹和index.ts让入口文件,modules用于放置单独的模块

index.ts

import { createStore, Store, useStore as baseUseStore } from "vuex";
import { InjectionKey } from "vue";
import { tabStore, TabState } from "./modules/tabs";

// 定义一个根模块的接口,引入其他子模块的类型
export interface RootState {
  tabStore: TabState
}

// 定义 injection key (传自己创建的根目录接口即可)
export const key: InjectionKey<Store<RootState>> = Symbol()  //Symbol函数会返回Symbol类型值

// 引入后即可使用了,在main.ts中需引入key值
export const store:Store<RootState> = createStore ({
  modules: {
    tabStore
  }
})

// 自定义组合式函数
export function useStore() {
  return baseUseStore(key)
}

示例模块tabStore
在模块内使用的时候,需要将RootState接口引入

import { Module } from 'vuex'
import { Itab }from '../type'
// 引入根模块的RootState
import { RootState } from '../index'


export interface TabState {
  tabList:Array<Itab>
  contextMenuTabId: string
}

// TabState + RootState 创建子模块的store模板,引入到根模块即可
export const tabStore: Module<TabState, RootState> = {
  namespaced: true,
  state: {
    tabList: [],  //声明tabList是一个数组
    contextMenuTabId: '',  //声明当前路由

  },

  mutations: {  //对tabList的数据进行操作(如添加)
    // 添加tab
    addTab(state:TabState, tab:Itab) {
      // 说明: 不会添加相同的,对添加的值进行判断 
      // some:判断数组中是否存在相同元素,有则返回true
      const isSome = state.tabList.some((item) => item.path == tab.path)
      if (!isSome) {
        state.tabList.push(tab)
      }
    },

    // 删除tab
    closeCurrentTab(state:TabState, targetName:string) {
      // 关闭当前页
      const index = state.tabList.findIndex((item) => item.path == targetName)
      state.tabList.splice(index, 1); //从当前索引位置删除1个
    },

    // 右键打开菜单保存path
    saveCurContextTabId(state:TabState, curtextMenuTabId:string) {
      state.contextMenuTabId = curtextMenuTabId
    },

    // 关闭所有菜单
    closeAllTabs(state:TabState) {
      state.tabList = [];
      // 还需要清空session中存储的数据
      sessionStorage.removeItem('TABS_ROUTES')
    },

    // 关闭其他
    closeOtherTabs(state:TabState, flag:string) {
      const curIndex = state.tabList.findIndex((item) => item.path == state.contextMenuTabId)
      if (flag == 'other') { // 关闭其他
        state.tabList = state.tabList.filter((item) => item.path == state.contextMenuTabId)
      } else if (flag == 'left') {
        state.tabList.splice(0, curIndex)
      } else if (flag == 'right'){
        state.tabList.splice(curIndex + 1)

      }
    }

    
  },
  getters: {
    // 将添加完成之后的数据返回
    getAddTab(state:TabState) {
      return state.tabList; //将数据,实时返回
    }
  }
}

全局文件引入,将上述injectionKey传入useStore方法可以获取类型化的store。

import { createApp } from 'vue'
// import './style.css'
import App from './App.vue'
import router from './router'   //引入路由
import {store, key} from './store'    //引入状态存储(引入key)
import * as ElIcons from '@element-plus/icons'
const app = createApp(App)
for(const name in ElIcons) {  //将每一个节点挂载在app上
  app.component(name,(ElIcons as any)[name])
}

// 使用use(router),进行挂载
app.use(router).use(store, key).mount('#app')

在vuex+typescript下使用方法

// 将引入路径由 import { useStore } from 'vuex'; 改为以下
import { useStore } from '@/store/index';  

// state (当然原来也是这么访问的)
store.state.tabState.tabSList

// getters
store.getters['tabStore/getAddTab'];   //将vuex中创建的值返回 

// mutations
store.commit('tabStore/addTab', tab)  //提交到tabList中

//actions
store.dispatch('tabStore/incrementAction')
posted @ 2023-02-26 16:49  小鱼儿-xy  阅读(342)  评论(0)    收藏  举报