Vue3 的 useLocalStorage 📦

基础封装

  1. 初始化数据,如果 localStorage 中已有对应的数据则使用 localStorage 的值
  2. 使用 onMounted 来确保组件已经挂载后再执行操作
  3. 为 data 添加一个监听器
  4. 监听 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;
相关推荐
ym hyd 1117 小时前
试题库管理系统源码 Java+SpringBoot+Vue3 前后分离
java·vue.js·spring boot·毕设
雪芽蓝域zzs12 小时前
第4节:el-select 弹窗事件控制(打开 / 关闭、选中事件、弹窗滚动事件)
vue.js·elementui
PYB312 小时前
【Web·JS·基础】函数的使用和展运算符...objs
前端·javascript
默_笙13 小时前
🚥 给 RAG 装一台心电监护仪:LangSmith 全链路观测(上)
前端·javascript
变与不变80615 小时前
js同步和异步难点重点详解
开发语言·javascript·ecmascript
Dovis(誓平步青云)15 小时前
多个链接不等于多份证据,新闻核验看板怎样合并来源
java·服务器·前端·javascript·人工智能·pdf·电脑
Dovis(誓平步青云)16 小时前
几个方案来回选不定?做一个随时切换的候选推荐页
android·java·服务器·开发语言·javascript·数据库·智能化
可乐鸡翅yeah_17 小时前
fmp4 碎片 MP4 格式 HLS 流,和传统 TS 分片有什么不一样
开发语言·javascript·ios·音视频·safari·m3u8·m3u8在线播放
ss27318 小时前
AI全栈实战 | 2.3-01 组件库实战:Element Plus 怎么搭出专业界面,过度封装为什么成维护负担
前端·javascript·elementui·vue
福兮说19 小时前
URL 编码的七个坑:c++ 传到后端变空格、%25 套娃、截断 emoji 直接报错
开发语言·前端·javascript·node.js·url