Hook使用方式:
import {useLocalStore} from "../js/hooks"const aa=useLocalStore("aa",1)
需求一:
通过window.localStorage.setItem可以更改本地存储是,还可以更新aa的值
window.localStorage.setItem("aa",100)
需求二:
通过aa.value++;既可以更改js的数据修改试图,还有更新本地存储
需求三:
支持数组,对象,和普通类型数据
实现思路
对于需求一,原生的window.localStorage.setItem肯定无法实现数据响应式所以需要从写改函数
对于需求二,需用用到watch来监听数据的变化
对于上面2个需求的代码实现都封装在useLocalStore函数内部,在内部定义一个响应式的ref数据,然后返回改声明的数据,如下:
import { ref } from 'vue';export const useLocalStore=(key,defaultValue)=>{
const refVal=ref(null);
//省略部分代码….
return ref Val;
}
重写元素localStorage的代码如下:
const nativeLocalStorage = window.localStorage;
window.nativeLocalStorage = nativeLocalStorage; // 保留原生的使用
/*** 没有keyStr时候所有都清空* @param {*} keyStr */class MyLocalStorage {setItem(key, value) {console.log("set key", key, "value", value)nativeLocalStorage.getItem(key, value);if (storeItemSubscribers[key]) {storeItemSubscribers[key].forEach((dep) => {dep.value = value;});}}getItem(key) {//getItem不需要做响应式nativeLocalStorage.getItem(key);}removeItem(key) {if (storeItemSubscribers[key]) {storeItemSubscribers[key].forEach((dep) => {dep.value = null;});}nativeLocalStorage.removeItem(key);}clear() {nativeLocalStorage.clear();for(let key in storeItemSubscribers){if (storeItemSubscribers[key]) {storeItemSubscribers[key].forEach((dep) => {dep.value = null;});}}}
}const myLocalStorage = new MyLocalStorage();
// 将新创建的实例赋值给localStorage
Object.defineProperty(window, 'localStorage', {value: myLocalStorage,writable: true,
});
此外,还需要对默认参数进行判断,区分对象类型和普通类型
在组件销毁前也需要移除依赖收集
整体js
import { onBeforeUnmount, ref, watch } from 'vue';const nativeLocalStorage = window.localStorage;window.nativeLocalStorage = nativeLocalStorage; // 保留原生的使用class MyLocalStorage {setItem(key, value, noUpdate) {console.log("set key", key, "value", value)nativeLocalStorage.getItem(key, value);if (storeItemSubscribers[key]) {storeItemSubscribers[key].forEach((dep) => {dep.value = value;});}}getItem(key) {//getItem不需要做响应式nativeLocalStorage.getItem(key);}removeItem(key) {if (storeItemSubscribers[key]) {storeItemSubscribers[key].forEach((dep) => {dep.value = null;});}nativeLocalStorage.removeItem(key);}clear() {nativeLocalStorage.clear();for(let key in storeItemSubscribers){if (storeItemSubscribers[key]) {storeItemSubscribers[key].forEach((dep) => {dep.value = null;});}}}}const myLocalStorage = new MyLocalStorage();// 将新创建的实例赋值给localStorageObject.defineProperty(window, 'localStorage', {value: myLocalStorage,writable: true,});// LocalStorage项目键与依赖它的Vue实例列表之间的映射const storeItemSubscribers = {};export const useLocalStore = (key, defaultValue) => {const refVal = ref(null);let StringDefaultValue = null;if (typeof defaultValue == "object") {try {StringDefaultValue = JSON.stringify(defaultValue);} catch (e) { }}if (defaultValue != undefined && defaultValue != null) {if (StringDefaultValue) {window.localStorage.setItem(key, StringDefaultValue)}else {window.localStorage.setItem(key, defaultValue)}refVal.value = defaultValue;}const stopWatch = watch(() => refVal.value, () => {let toString = refVal.value;if (typeof defaultValue == "object") {try {toString = JSON.stringify(refVal.value);} catch (e) { }}console.log("触发变化")window.localStorage.setItem(key, toString,true)}, {deep: true,immediate: true})onBeforeUnmount(() => {for (let i = 0; i < storeItemSubscribers[key].length; i++) {if (storeItemSubscribers[key] == refVal) {storeItemSubscribers.splice(i, 1);stopWatch();console.log("组件销毁", i, "storeItemSubscribers.length", storeItemSubscribers.length)break;}}})// 收集依赖的Vue实例if (!storeItemSubscribers[key]) storeItemSubscribers[key] = [];storeItemSubscribers[key].push(refVal)return refVal;}