一、插件的使用
Vuex 不仅提供了全局状态管理能力,还进一步提供了插件机制,便于开发者对 Vuex 插件进行增强;
Vuex 插件的使用方式:通过 Store 类提供的 plugin 数组进行 Vuex 插件注册:
export default createStore({
plugins:[ //插件会按照注册的顺序依次执行插件,执行的时候会把store传递给你
customlugin
],
...})
二、vuex持久化插件开发
1、customlugin插件介绍
在使用 Vuex 插件进行状态管理时,一定会遇到一个问题:当页面刷新时(如使用 F5 进行刷新),将导致页面状态丢失
为了防止vuex的数据,开发customlugin插件
2、customlugin插件实现
(1)vuex插件实现
- 创建一个 Vuex 插件,最终导出一个高阶函数(在 plugin 数组中进行插件注册);
store.subscribe
:订阅方法,当 mutation 方法触发时会触发这个方法store.replaceState
:替换方法,可以不通过mutation更新state的值
(2)customlugin实现原理
- 创建一个函数:customPlugin,vuex初始化时,对插件进行注册和初始化操作
- 使用 store.subscribe 订阅方法:当 mutation 方法触发时,将当前状态保存到本地
- 当页面刷新时,状态将会丢失,同时 Vuex 插件重新初始化,此时重新读取本地状态,并通过store.replaceState将本地状态(即刷新丢失的状态)替换到 Vuex 状态,实现状态的持久化效果;
import { createStore } from '@/vuex' // new Store
function customPlugin(store) {
let local = localStorage.getItem('VUEX:STATE');
//如果localstorage中存在VUEX:STATE,则取出给vuex赋值
if (local) {
store.replaceState(JSON.parse(local))
}
store.subscribe((mutation, state) => { // 每当状态发生变化 (调用了mutation的时候 就会执行此回调)
localStorage.setItem('VUEX:STATE', JSON.stringify(state))
})
}
const store = createStore({
plugins: [ // 会按照注册的顺序依次执行插件,执行的时候会把store传递给你
customPlugin
],
...
})
三、实现插件机制
1、注册plugin
- 在store中的数据和方法定义完成后,挨个初始化plugin中的方法
- 收集 Vuex 插件中,通过 store.subscribe 订阅状态变化事件的回调函数 fn 保存到 _subscribes 数组中;
export default class Store {
...
constructor(options) {
// 定义状态
const state = store._modules.root.state; // 根状态
installModule(store, state, [], store._modules.root);
resetStoreState(store, state);
store._subscribes = [];
options.plugins.forEach(plugin => plugin(store));
}
// 将回调统计到_subscribes数组中
subscribe(fn) {
this._subscribes.push(fn);
}
}
2、subscribe 状态订阅实现
当mutations方法执行时,依次执行_subscribes中的方法,将当前的mutation方法和state一起传递过去,执行当时定义的将数据存在localStorage的方法
commit = (type, payload) => {
const entry = this._mutations[type] || [];
this._withCommit(() => {
entry.forEach((handler) => handler(payload));
});
this._subscribes.forEach((sub) => sub({ type, payload }, this.state));
};
3、replaceState 状态替换实现
replaceState 传入的是本地存储中的state,由于在严格模式下不通过mutation给state赋值会报错,所以在这里借助_withCommit方法,mutation中为了防止异步和其余方法该值也是通过这个进行判断的
replaceState(newState) {
// 严格模式下不能直接更改状态
this._withCommit(() => {
this._state.data = newState;
});
}