Vue3 让localstorage变响应式
原生的window.localStorage.setItem肯定无法实现数据响应式所以需要从写改函数。通过window.localStorage.setItem可以更改本地存储是,还可以更新aa的值。通过aa.value++;既可以更改js的数据修改试图,还有更新本地存储。,需用用到watch来监听数据的变化。此外,还需要对默认参数进行判断,支持数组,对象,和普通类型数据。在组件销毁前也需要移除依
·
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();
// 将新创建的实例赋值给localStorage
Object.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;
}
更多推荐
所有评论(0)