前言
我們都知道,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
內加入如下程式碼(在這裡參考了 uview 封裝的 vuex 方法 )
import { createStore } from 'vuex'
export default createStore({
state: {
vuexIsLogin: false, // 當前的登入狀態
vuexTestVar: "這是vuex全域性混入的測試變數",
vuexUser:{
test: 1,
name: "測試名字"
}
},
mutations: {
$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;
}
}
}
})
之後我們在 store 目錄下建立一個 ts 指令碼檔案,在我的專案中我命名為 maxer.mixin.ts
,在這裡,我們就需要使用Vue中的一個特性 Mixin(混入)「不明白的同學可以去官方文件查一查,Vue3的官方中文版已經推出了」
/**
* @作者: Seale
* @時間: 2021/1/23
* @版本: V1.0
* @說明: maxer Vue 全域性混入
* @網站: https://www.imsle.com
*/
import {mapState} from "vuex";
import store from '@/store/index.ts'
import {App} from 'vue'
// 將定義的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中
// 使用方法為:如果要修改vuex的state中的user.name變數為"x" => 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 中變數前加上 vuex_
prefix ,或者類似 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) // 全域性混入vuex
app.use(store).mount('#app')
之後我們就可以愉快地使用 vuex 了(在注意變數命名的情況下)。
Vuex 資料持久化
這個時候或許你會發現,當頁面進行重新整理的時候,vuex 的資料會進行初始化(回到最初的狀態),這個是由於 vuex 是執行在記憶體中的,同樣的,它的資料也是儲存在記憶體中,當使用者進行重新整理頁面的操作,所以記憶體資料會重新進行初始化。
那麼我們就可以透過 sessionStorage / localStorage / cookie 來進行資料的持久化儲存。
頁面載入的時候先讀取域中的快取資料,如果有則覆寫。當頁面將要重新整理前,我們將 vuex 的資料儲存到域中。
這裡建議使用 sessionStorage ,對於需要長時間持久化的資料再使用 localStorage 或者 cookie。
同樣我們在 store 目錄下新建一個 ts 指令碼。
/**
* @作者: Seale
* @時間: 2021/1/24
* @版本: V1.0
* @說明: vuex資料持久化,防止F5之後資料消失
* @網站: https://www.imsle.com
*/
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')
本作品採用《CC 協議》,轉載必須註明作者和本文連結