前言

最近魔改了一下主题,将首页右侧卡片改成了CMD打字机的效果,但是网站啊又是pjax加载的,所以每次访问文章再返回首页进度就会重置。

所以就想要用浏览器的localStorage功能来存储进度。当然一切还是靠AI的帮助。

什么是localStorage

localStorage 是 Web Storage API 的一部分,提供了在浏览器中存储键值对数据的能力。与 sessionStorage 不同,localStorage 中的数据没有过期时间,即使关闭浏览器后重新打开,数据依然存在。

主要特点

  • 持久化存储:数据保存在浏览器本地,关闭标签页或浏览器后仍然存在
  • 同源策略:只有相同协议、域名和端口的页面才能访问相同的数据
  • 容量较大:一般支持 5-10MB 的存储空间(因浏览器而异)
  • 仅支持字符串:只能存储字符串类型的数据,对象需要序列化

基本使用方法

存储数据

// 存储字符串
localStorage.setItem('username', '张三');

// 存储对象(需要序列化)
const user = { name: '张三', age: 25 };
localStorage.setItem('user', JSON.stringify(user));

// 存储数组
const todos = ['任务1', '任务2', '任务3'];
localStorage.setItem('todos', JSON.stringify(todos));

读取数据

// 读取字符串
const username = localStorage.getItem('username');
console.log(username); // 输出: 张三

// 读取对象(需要反序列化)
const user = JSON.parse(localStorage.getItem('user'));
console.log(user.name); // 输出: 张三

// 读取数组
const todos = JSON.parse(localStorage.getItem('todos'));
console.log(todos); // 输出: ['任务1', '任务2', '任务3']

删除数据

// 删除单个键值
localStorage.removeItem('username');

// 清空所有数据
localStorage.clear();

检查数据是否存在

// 检查键是否存在
if (localStorage.getItem('username')) {
  console.log('用户名已存在');
} else {
  console.log('用户名不存在');
}

实际应用场景

1. 用户偏好设置

// 保存主题偏好
function saveThemePreference(theme) {
  localStorage.setItem('theme', theme);
}

// 读取主题偏好
function getThemePreference() {
  return localStorage.getItem('theme') || 'light';
}

// 应用主题
const currentTheme = getThemePreference();
document.body.className = currentTheme;

2. 表单数据自动保存

// 监听输入变化,自动保存
const formInputs = document.querySelectorAll('input, textarea');
formInputs.forEach(input => {
  input.addEventListener('input', function() {
    localStorage.setItem(`form_${this.name}`, this.value);
  });
  
  // 页面加载时恢复数据
  const savedValue = localStorage.getItem(`form_${input.name}`);
  if (savedValue) {
    input.value = savedValue;
  }
});

3. 记住用户操作状态

// 保存侧边栏展开状态
function saveSidebarState(isCollapsed) {
  localStorage.setItem('sidebar_collapsed', isCollapsed);
}

// 读取侧边栏状态
function getSidebarState() {
  return localStorage.getItem('sidebar_collapsed') === 'true';
}

// 应用侧边栏状态
const sidebarCollapsed = getSidebarState();
if (sidebarCollapsed) {
  document.querySelector('.sidebar').classList.add('collapsed');
}

4. 数据缓存

// 缓存API响应数据
async function fetchDataWithCache(url) {
  const cacheKey = `cache_${url}`;
  const cachedData = localStorage.getItem(cacheKey);
  
  if (cachedData) {
    const { data, timestamp } = JSON.parse(cachedData);
    const cacheAge = Date.now() - timestamp;
    
    // 如果缓存时间小于1小时,使用缓存数据
    if (cacheAge < 60 * 60 * 1000) {
      return data;
    }
  }
  
  // 获取新数据并缓存
  const response = await fetch(url);
  const data = await response.json();
  
  localStorage.setItem(cacheKey, JSON.stringify({
    data: data,
    timestamp: Date.now()
  }));
  
  return data;
}

注意事项和最佳实践

1. 错误处理

function safeLocalStorageGet(key) {
  try {
    return localStorage.getItem(key);
  } catch (e) {
    console.warn('localStorage 读取失败:', e);
    return null;
  }
}

function safeLocalStorageSet(key, value) {
  try {
    localStorage.setItem(key, value);
    return true;
  } catch (e) {
    console.warn('localStorage 写入失败:', e);
    return false;
  }
}

2. 存储空间检查

function checkLocalStorageSpace() {
  try {
    const testKey = '__storage_test__';
    localStorage.setItem(testKey, 'test');
    localStorage.removeItem(testKey);
    return true;
  } catch (e) {
    return e instanceof DOMException && (
      e.code === 22 || // Chrome
      e.code === 1014 || // Firefox
      e.name === 'QuotaExceededError' || // Safari
      e.name === 'NS_ERROR_DOM_QUOTA_REACHED'
    );
  }
}

3. 数据版本管理

// 存储带版本号的数据
function saveVersionedData(key, data, version = '1.0') {
  const storageData = {
    version: version,
    data: data,
    timestamp: Date.now()
  };
  localStorage.setItem(key, JSON.stringify(storageData));
}

// 读取带版本号的数据
function loadVersionedData(key, currentVersion = '1.0') {
  const saved = localStorage.getItem(key);
  if (!saved) return null;
  
  try {
    const parsed = JSON.parse(saved);
    if (parsed.version === currentVersion) {
      return parsed.data;
    }
    // 版本不匹配,删除旧数据
    localStorage.removeItem(key);
    return null;
  } catch (e) {
    localStorage.removeItem(key);
    return null;
  }
}

4. 隐私和安全考虑

  • 不要存储敏感信息:如密码、token、个人身份信息等
  • 数据加密:如果必须存储敏感数据,考虑使用加密
  • 同源策略:注意不同子域名间的数据隔离
  • 用户同意:在存储用户数据前获得明确同意

浏览器兼容性

浏览器最低版本备注
Chrome4完全支持
Firefox3.5完全支持
Safari4完全支持
IE8部分支持,需要 polyfill
Edge12完全支持

总结

localStorage 是一个简单但功能强大的浏览器存储解决方案,适用于各种需要持久化存储的场景。通过合理使用 localStorage,可以显著提升用户体验,减少不必要的服务器请求,实现离线功能等。

在实际应用中,要注意错误处理、存储限制和数据安全,确保为用户提供可靠的服务。