vuex-persistedstate 插件源码解读
js
// 一个合并数据的库
import merge from "deepmerge";
// 通过 'a.b.c' 设置对象的 key
import * as shvl from "shvl";
export default function(options, storage, key) {
// 用户传入的选项
options = options || {};
// 优先使用 options.storage。用户未定义就使用 window.localStorage。
storage = options.storage || (window && window.localStorage);
// 设置存储时的 key 值。
key = options.key || "vuex";
// 测试是否能写入
function canWriteStorage(storage) {
try {
storage.setItem("@@", 1);
storage.removeItem("@@");
return true;
} catch (e) {}
return false;
}
// storage.getItem(key) 获取到值后,再 JSON.parse 进行解析。
function getState(key, storage, value) {
try {
return (value = storage.getItem(key)) && typeof value !== "undefined"
? JSON.parse(value)
: undefined;
} catch (err) {}
return undefined;
}
// 全部通过筛选
function filter() {
return true;
}
// storage.setItem(key, state) 保存值。
function setState(key, state, storage) {
return storage.setItem(key, JSON.stringify(state));
}
// 如果 paths 是一个空数组,就返回整个 state
// 不是一个空数组,就返回一个对象。
// 数组比如 ['a.b.c']
// 返回的对象为 {a:{b:{c:'xxx'}}}
function reducer(state, paths) {
return paths.length === 0
? state
: paths.reduce(function(substate, path) {
return shvl.set(substate, path, shvl.get(state, path));
}, {});
}
// 可以连续使用两次小括号,来进行传参。
function subscriber(store) {
return function(handler) {
// 每次 store 触发 mutation 时,store.subscribe 都会调用 handler。
return store.subscribe(handler);
};
}
// 如果不能写入,抛出异常
if (!canWriteStorage(storage)) {
throw new Error("Invalid storage instance given");
}
// 获取本地保存的数据
const fetchSavedState = () =>
shvl.get(options, "getState", getState)(key, storage);
const savedState = fetchSavedState();
return function(store) {
// 如果有保存的数据
if (typeof savedState === "object" && savedState !== null) {
// 调用 store.replaceState 进行合并数据
store.replaceState(
// 合并数据
merge(store.state, savedState, {
arrayMerge:
options.arrayMerger ||
// 如果合并数组类型的数据?
// 直接替换掉
function(store, saved) {
return saved;
},
clone: false
})
);
// 对于非 nuxt 项目而言,没有作用。
(options.rehydrated || function() {})(store);
}
// 优先使用用户传入的配置,否则就使用默认的。
// 使用到高阶函数
(options.subscriber || subscriber)(store)(function(mutation, state) {
if ((options.filter || filter)(mutation)) {
// 直接将整个 store 的 state 进行存储。
(options.setState || setState)(
key,
(options.reducer || reducer)(state, options.paths || []),
storage
);
}
});
};
}