vuex实现模块化以及ts支持
当使用组合式API编写Vue组件时,您可能希望useStore返回类型化store。为了useStore能正确返回类型化store,必须执行以下步骤:
- 定义类型化的InjectionKey。
- 将store安装到Vue应用时提供类型化的Injectionkey。
- 将类型化的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')