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;

}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐