高效的在Vue3中使用Vuex

前言

我们都知道,vuex 的使用在项目中颇为繁琐,因为它有几大概念使得它不能像普通 ref 或者 data 对象一样直接被我们使用,在我们想要更改 vuex 中的数据时,我们需要通过 mutation 来进行提交,获取 vuex 中存储的变量的时候,我们又需要通过 computed 属性来进行声明,试想,如果项目足够庞大,那么我们使用 vuex 的负担就过于重了,这违背了我们使用状态管理的本意。

问题的提出

首先,我们需要明确,我们想要怎么快捷便利地来使用 vuex ,如果你的想法和我如下所示相同,那么恭喜你,或许本文提出的解决方案适合你。

存储

对于 vuex 的存储我们想要实现的类似如下:

this.$m.vuex(name,value);

我们可以在各个组件或者视图内,通过 this 来直接使用 vuex 进行存储。

读取

对于 vuex 中数据的读取我们想要实现的类似如下:

<template>
<div>{{ vuexUser.name }}</div>
</template>


<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
    ...
    methods:{
          // 业务方法
          xxxxx(){
            const flag = this.vuexUser.name? true : false;
            .....
          }
  }
})
</script>

我们能够在模板或者业务逻辑中直接通过 this 直接访问。

解决方案

首先,我们需要在 store 目录下的 index.ts 内加入如下代码

import { createStore } from 'vuex'

export default createStore({
  state: {
    vuexIsLogin: false,        // 当前的登录状态
    vuexTestVar: "测试变量",
    vuexUser:{
      test: 1,
      name: "WuYunLong"
    }
  },
  mutations: {
    $changeStore(state: any, payload: any){
      // 判断是否为多层级调用
      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;
      }
    }
  }
})

之后我们在 store 目录下创建一个 ts 脚本文件,在我的项目中我命名为 maxer.mixin.ts ,在这里,我们就需要使用 Vue 中的一个特性 Mixin(混入)「不明白的同学可以去官方文档查一查,Vue3 的官方中文版已经推出了」

/**
 * @作者: WuYunlong
 * @时间: 2021/06/22
 * @版本: V1.0
 * @说明: maxer Vue 全局混入
 */

import { App } from 'vue'
import { mapState } from "vuex";
import store from '@/store/index.ts'

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

export default<T> (app: App<T>) => {
    // 进行全局混入
    // 将vuex方法挂载到$m中
    // 使用方法为: this.$m.vuex('user.name', 'x')
    app.config.globalProperties.$m = new Maxer();
    app.mixin({
        computed: {
            // 将vuex的state中的所有变量,解构到全局混入的mixin中
            ...mapState($mStoreKey)
        }
    })
}

在这里我们使用全局混入,将 vuex 的 state 混入到计算属性中,我们就可以通过类似 this.vuexName 来进行调用,还有一点建议就是,由于采用全局混入的模式将 vuex 中的数据进行混入,所以我们应该用特定的字符来进行标识 vuex 中的数据,我的建议是在 vuex 中变量前加上特殊前缀 ,或者类似 vuexVar:'xxx' 来进行声明变量。

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

import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
import installMaxerStore, { Maxer } from './store/maxer.mixin'
...

// 声明全局组件 防止需要this调用时不能识别类型
declare module '@vue/runtime-core' {
    interface ComponentCustomProperties {
        $m: Maxer;  // 声明全局方法
    }
}
...
const app = createApp(App)
installMaxerStore(app)
app.use(store).mount('#app')

之后我们就可以愉快地使用 vuex 了(在注意变量命名的情况下)。

Vuex 数据持久化

这个时候或许你会发现,当页面进行刷新的时候,vuex 的数据会进行初始化(回到最初的状态),这个是由于 vuex 是运行在内存中的,同样的,它的数据也是存储在内存中,当用户进行刷新页面的操作,所以内存数据会重新进行初始化。

那么我们就可以通过 sessionStorage /localStorage/cookie 来进行数据的持久化存储。

页面加载的时候先读取域中的缓存数据,如果有则覆写。当页面将要刷新前,我们将 vuex 的数据存储到域中。

这里建议使用 sessionStorage ,对于需要长时间持久化的数据再使用 localStorage 或者 cookie。

同样我们在 store 目录下新建一个 ts 脚本。

/**
 * @作者: WuYunlong
 * @时间: 2021/6/22
 * @版本: V1.0
 * @说明: vuex数据持久化,防止F5之后数据消失
 */
import {Store} from "vuex";

export default<T> (store: Store<T>): void=>{
    // 不需要持久化的数据存入sessionStorage
    if (sessionStorage.getItem('store')){
        store.replaceState(
            Object.assign(
                {},
                store.state,
                JSON.parse(sessionStorage.getItem('store') as string)
            )
        );
        // 移除sessionStorage中的数据
        sessionStorage.removeItem("store");
    }
    // 页面刷新的时候进行持久化
    window.addEventListener('beforeunload',()=>{
        sessionStorage.setItem("store", JSON.stringify(store.state));
    })
}

对于需要长时间持久化的数据建议自行定义规则进行封装。

之后我们需要在入口文件中进行声明

import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
import installMaxerStore, {Maxer} from './store/maxer.mixin'
import initStorePersistence from './store/store.persistence'
...

// 声明全局组件
declare module '@vue/runtime-core' {
    interface ComponentCustomProperties {
        $m: Maxer;  // 声明全局方法
    }
}
...
const app = createApp(App)
installMaxerStore(app) // 全局混入vuex
initStorePersistence(store) // 初始化持久化vuex
app.use(store).mount('#app')

版权说明

本文章转载自网络,如果侵犯了您的权利起联系删除。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容