基础封装
- 初始化数据,如果
localStorage
中已有对应的数据则使用localStorage
的值 - 使用
onMounted
来确保组件已经挂载后再执行操作 - 为
data
添加一个监听器 - 监听
data
的变化,并将新值保存到localStorage
js
import { ref, onMounted, watchEffect } from 'vue';
function useLocalStorage(key, defaultValue) {
const data = ref(localStorage.getItem(key) || defaultValue);
onMounted(() => {
const localStorageUpdate = () => {
localStorage.setItem(key, data.value);
};
watchEffect(localStorageUpdate);
});
return data;
}
export default useLocalStorage;
使用
每当输入框的值发生变化时,它会自动更新localStorage,并且如果你刷新页面,它会保留之前的值。
js
<template>
<el-input v-model="text" />
{{ text }}
</template>
<script lang="ts" setup>
import { ref } from "vue";
import useLocalStorage from "../hooks/useLocalStorage.js";
const text = useLocalStorage("myText", "Default Text");
</script>
支持更多数据类型
因为localStorage只能存储字符串,当涉及到存储函数(function类型)或其他非字符串/JSON类型数据时,需要特殊处理。在存储和检索函数时,将其序列化为字符串,然后在检索时反序列化。
js
import { ref, onMounted, watchEffect } from "vue";
function useLocalStorage(key, defaultValue) {
const storedValue = localStorage.getItem(key);
const data = ref(storedValue ? deserialize(storedValue) : defaultValue);
onMounted(() => {
const localStorageUpdate = () => {
localStorage.setItem(key, serialize(data.value));
};
watchEffect(localStorageUpdate);
});
// 反序列化数据
function deserialize(value) {
try {
const deserialized = JSON.parse(value);
if (typeof deserialized === "object" && deserialized !== null) {
return deserialized;
} else if (typeof deserialized === "function") {
return new Function(`return ${deserialized}`)();
} else {
return deserialized;
}
} catch (e) {
return value;
}
}
// 序列化数据
function serialize(value) {
if (typeof value === "function") {
return value.toString();
} else if (Array.isArray(value)) {
return JSON.stringify(value);
} else if (typeof value === "object" && value !== null) {
return JSON.stringify(value);
} else {
return value;
}
}
return data;
}
export default useLocalStorage;
到期删除
在现有的自定义useLocalStorage
hook 中增加一个配置项,以控制数据的有效期。
onMounted
,向 localStorage
中设置时间戳
js
localStorage.setItem(`${key}_timestamp`, Date.now().toString());
使用 setInterval
,在组件的生命周期内定期检查数据是否过期,然后在过期时手动删除它。
js
onMounted(() => {
localStorage.setItem(`${key}_timestamp`, Date.now().toString());
//....
const checkExpiration = () => {
if (
expiration &&
storedTimestamp &&
Date.now() - parseInt(storedTimestamp) > expiration
) {
localStorage.removeItem(key);
localStorage.removeItem(`${key}_timestamp`);
}
};
setInterval(checkExpiration, 1000);
});
完整代码:
js
import { ref, onMounted, watchEffect } from "vue";
function useLocalStorage(key, defaultValue, expiration) {
const storedValue = localStorage.getItem(key);
const storedTimestamp = localStorage.getItem(`${key}_timestamp`);
const data = ref(storedValue ? deserialize(storedValue) : defaultValue);
onMounted(() => {
localStorage.setItem(`${key}_timestamp`, Date.now().toString());
const localStorageUpdate = () => {
localStorage.setItem(key, serialize(data.value));
};
watchEffect(localStorageUpdate);
const checkExpiration = () => {
if (
expiration &&
storedTimestamp &&
Date.now() - parseInt(storedTimestamp) > expiration
) {
localStorage.removeItem(key);
localStorage.removeItem(`${key}_timestamp`);
}
};
setInterval(checkExpiration, 1000);
});
// 反序列化数据
function deserialize(value) {
try {
const deserialized = JSON.parse(value);
if (typeof deserialized === "object" && deserialized !== null) {
return deserialized;
} else if (typeof deserialized === "function") {
return new Function(`return ${deserialized}`)();
} else {
return deserialized;
}
} catch (e) {
return value;
}
}
// 序列化数据
function serialize(value) {
if (typeof value === "function") {
return value.toString();
} else if (
Array.isArray(value) ||
(typeof value === "object" && value !== null)
) {
return JSON.stringify(value);
} else {
return value;
}
}
return data;
}
export default useLocalStorage;