Vue3中全局混入Vuex TypeScript + composition-api版(支持数据持久化)

子成君 539 0

预期效果

通过 this.$m.vuex(name,value)的方式set,通过 this.vuex_name的方式get

前言

js版本的请看这里: uView简化Vuex写法的基本原理

ts核心代码出自这篇博客文章:https://www.imsle.com/archives/105.html  下文中有较大改动,看原版请移步

不推荐大型项目使用该方式,大型项目中全局混入有严重性能问题(如果页面组件超过1000个可能导致页面加载过慢,因为该页面1000个组件都混入了store)

正文

在 store 目录下的 index.ts 内加入如下代码

import { createStore } from 'vuex'
import router from "@renderer/router";

const userData = [ // 示例数据 与用户登录态和权限相关的数据
    {name:'vuex_user',value:{}},
    {name:'vuex_token',value:''},
]
export default createStore({
    state: { // 示例数据
        vuex_user: {},
        vuex_token: '',
        vuex_version: '',
    },
    mutations: {
        $clearUserData(state: any){ // 示例方法 不需要请删除 清除用户登录态 
            let data = JSON.parse(localStorage.getItem('store'))
            userData.forEach(saveKey =>{
                state[saveKey.name] = saveKey.value
                data[saveKey.name] = saveKey.value
            })
            setTimeout(()=>{
                console.log('跳转登录')
                localStorage.setItem("store", JSON.stringify(data));
                router.push('/login')// 跳转至你的登录页
            },300)
        },
        $changeStore(state: any,payload: any){
            // 判断是否为多层级调用,state中为对象存在的情况,诸如user.info.name = 'xxx'
            const nameArr = payload.name.split('.');
            const len = nameArr.length;
            if (len >= 2){
                let obj = state[nameArr[0]];
                for (let i = 1 ; i < len - 1 ; i++){
                    obj = obj[nameArr[i]];
                }
                obj[nameArr[len-1]] = payload.value;
            }else {
                state[payload.name] = payload.value;
            }
            localStorage.setItem("store", JSON.stringify(state));
        }
    }
})

之后在 store 目录下创建 maxVuex.mixin.ts ,使用Vue中的一个特性 Mixin(混入), 使用的详细方法已在下面写出

/**
 * @创建: zhaozc
 * @时间: 2021/5/27
 * @说明: Vue 全局混入
 */
import {mapState} from "vuex";
import store from "./index"
import {App, getCurrentInstance} from 'vue'

// 将定义的state变量key全部加载到全局变量中
const $mStoreKey = store.state ? Object.keys(store.state) : [];
export class MaxVuex{
    vuex = (name: string, value: any): void=>{
        store.commit('$changeStore', {
            name, value
        })
    }
}

// 大型项目不推荐这种方式 QAQ
export default<T> (app: App<T>) => {
    // 进行全局混入
    // 将vuex方法挂载到$m中
    /* 使用方法为:
    1.如果要修改vuex的state中的"vuex_xxx"变量为"x" => this.$m.vuex('vuex_xxx','x')
    2.在composition-api中使用:
    写:
    import { getCurrentInstance } from 'vue'
    const { proxy }: any = getCurrentInstance()
    const { $m } = getCurrentInstance().appContext.config.globalProperties
    $m.vuex('vuex_xxx','x')
    读:
    页面上无需任务引入直接{{ vuex_xxx }}即可
    js中引入useStore读取
    import { useStore } from 'vuex'
    const store = useStore()
    store.state.vuex_xxx
    */
    app.config.globalProperties.$m = new MaxVuex();
    app.mixin({
        computed: {
            // 将vuex的state中的所有变量,解构到全局混入的mixin中
            ...mapState($mStoreKey)
        }
    })
}

建议是在 vuex 中变量前加上 vuex_ 来进行声明变量,让人一目了然。

之后我们就需要在 main.ts 中进行初始化了。

import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
import installMaxVueStore, {MaxVuex} from './store/maxVuex.mixin'
...

// 声明全局组件 防止需要this调用时不能识别类型 这一步建议单独创建个ts文件去声明
declare module '@vue/runtime-core' {
    interface ComponentCustomProperties {
        $m: MaxVuex;  // 声明全局方法
    }
}
...
const app = createApp(App)
installMaxVueStore(app) // 全局混入vuex
app.use(store).mount('#app')

最后进行Vuex 数据持久化的处理(防止F5之后数据消失)

在 store 目录下创建store.persistence.ts

/**
 * @创建: zhaozc
 * @时间: 2021/5/27
 * @说明: vuex数据持久化
 */
import {Store} from "vuex";

export default<T> (store: Store<T>): void=>{
    // 数据存入localStorage
    if (localStorage.getItem('store')){
        store.replaceState(
            // 将刷新前存下的缓存数据同步到store
            Object.assign(
                {},
                store.state,
                JSON.parse(localStorage.getItem('store') as string)
            )
        );
    }
}

需要在入口文件main.ts中追加:

...
import initStorePersistence from './store/store.persistence'
...

initStorePersistence(store) // 初始化持久化vuex
....
app.use(store).mount('#app')

发表评论 取消回复
OwO 图片 链接 代码

分享