浏览器的本地存储技术:从 `localStorage` 到 `IndexedDB`

前言

随着Web应用的发展,存储用户数据的需求变得越来越重要。现代浏览器提供了多种客户端存储方案,包括 localStorage, sessionStorage, Cookies, 已经被废弃的 Web SQL,以及功能强大的 IndexedDB。本文将详细介绍这些技术的基本概念和使用方法。

正文

1. localStorage:简单的键值对存储

localStorage 是一种允许网站在用户的浏览器中存储数据的技术,它提供了持久化的存储能力,除非用户主动清除浏览器缓存,否则数据不会丢失。localStorage 以字符串的形式存储数据,每个域名下大约有5MB的存储空间。

示例代码

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="save">保存</button>
  <button id="get">读取</button>
  <button id="del">删除</button>
  <button id="clear">清空</button>

  <script>
    const user = {
      name: '剑哥',
      age: 18
    }

    document.getElementById('save').addEventListener('click', () => {
      // 将对象转换为JSON字符串并保存
      localStorage.setItem('userInfo', JSON.stringify(user))
    })

    document.getElementById('get').addEventListener('click', () => {
      // 从localStorage中获取数据并解析为对象
      console.log(JSON.parse(localStorage.getItem('userInfo')));
    })

    document.getElementById('del').addEventListener('click', () => {
      // 删除指定的键值对
      localStorage.removeItem('userInfo')
    })
    document.getElementById('clear').addEventListener('click', () => {
      // 清空所有数据
      localStorage.clear()
    })
  </script>
</body>
</html>

基本操作

  • 保存数据localStorage.setItem('key', 'value')
  • 读取数据localStorage.getItem('key')
  • 删除数据localStorage.removeItem('key')
  • 清空所有数据localStorage.clear()

注意

localStorage 的数据是基于域名(即协议 + 域名 + 端口)进行隔离的。这意味着以下几点:

  1. 相同域名 :如果两个页面属于同一个域名,它们可以访问相同的 localStorage 数据。
  2. 不同子域名 :如果两个页面属于同一个顶级域名的不同子域名(例如 a.example.comb.example.com),它们不能直接访问对方的 localStorage 数据。不过,可以通过设置文档的 document.domain 属性来实现跨子域共享 localStorage
  3. 不同协议 :如果两个页面的协议不同(例如 http://example.comhttps://example.com),它们被视为不同的域名,不能共享 localStorage 数据。
  4. 不同端口 :如果两个页面的端口不同(例如 http://example.com:8080http://example.com:8081),它们也被视为不同的域名,不能共享 localStorage 数据。

2. sessionStorage:会话级别的存储

sessionStoragelocalStorage 类似,也是用于存储字符串形式的数据。不同之处在于,sessionStorage 存储的数据仅在当前会话期间可用,当浏览器窗口关闭时,数据会被清除。

示例代码

依旧是这个例子:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="save">保存</button>
  <button id="get">读取</button>
  <button id="del">删除</button>
  <button id="clear">清空</button>

  <script>
    const user = {
      name: '剑哥',
      age: 18
    }

    document.getElementById('save').addEventListener('click', () => {
      sessionStorage.setItem('key', JSON.stringify(user))
    })

    document.getElementById('get').addEventListener('click', () => {
      console.log(sessionStorage.getItem('key'));
    })

    document.getElementById('del').addEventListener('click', () => {
      sessionStorage.removeItem('key')
    })
    document.getElementById('clear').addEventListener('click', () => {
      sessionStorage.clear()
    })
  </script>
</body>
</html>

跟localStorage用法类似

3.Cookies

Cookies是不受前端掌控的,由后端控制,它是一种在用户浏览器上存储信息的方法,主要用于跟踪用户活动和保持用户登录状态等目的。与 localStoragesessionStorage 不同,它是由服务器发送给用户的,通常包含在 HTTP 响应头中。用户浏览器会将这些 Cookies 保存起来,并在后续请求同一服务器时自动将其包含在 HTTP 请求头中返回给服务器。

特点

  • 自动发送:浏览器会自动将相关 Cookies 发送到对应的服务器,无需额外编程。
  • 大小限制:每个域名下的 Cookies 总量有限制,通常是 4KB 左右。
  • 安全性 :可以通过设置 HttpOnly 标志来防止 JavaScript 访问 Cookies,从而减少 XSS 攻击的风险。
  • 过期时间 :可以通过设置 ExpiresMax-Age 属性来控制 Cookie 的有效期。
  • 路径和域 :可以设置 PathDomain 属性来限制 Cookie 的适用范围。

4. IndexedDB:高级的本地数据库

IndexedDB 是是浏览器本地的数据库,支持事务处理、异步操作等特性,支持使用js 编写逻辑来创建,适合存储大量结构化数据,并提供搜索功能。与 localStoragesessionStorage 相比,IndexedDB 的存储量更大,没有明确的大小限制,也是永久存储的。

示例代码

HTML 部分

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>IndexedDB Example</title>
  <style>
    /* 一些简单的样式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    th, td {
      border: 1px solid black;
      padding: 8px;
      text-align: left;
    }
    th {
      background-color: #f2f2f2;
    }
  </style>
</head>
<body>
  <!-- 按钮用于触发不同的数据库操作 -->
  <button onclick="openDB()">连接、新建数据库</button>
  <button onclick="insertOneDB()">插入一条数据</button>
  <button onclick="insertMultiDB()">插入多条数据</button>
  <button onclick="queryDB()">查询数据</button>
  <button onclick="updateDB()">更新数据</button>
  <button onclick="deleteDB()">删除数据</button>

  <script>
  // JavaScript 代码部分
  </script>
</body>
</html>

JavaScript 部分

定义常量和变量

ini 复制代码
const dbName = 'users'; // 数据库名称
const dbVersion = 1.0; // 数据库版本
let db = null; // 用于存储数据库实例

连接、新建数据库

javascript 复制代码
function openDB() {
  const request = indexedDB.open(dbName, dbVersion); // 打开或创建数据库

  request.onerror = function(event) {
    console.error('无法打开数据库', event.target.error); // 错误处理
  };

  request.onupgradeneeded = function(event) {
    db = event.target.result; // 获取数据库实例
    // 如果不存在名为 'sex' 的对象存储,则创建它
    if (!db.objectStoreNames.contains('sex')) {
      const objectStore = db.createObjectStore('sex', { keyPath: 'id' });
      objectStore.createIndex('title', 'title', { unique: true }); // 创建唯一索引
    }
  };

  request.onsuccess = function(event) {
    db = event.target.result;
    console.log(`数据库${db.name}已经开启`); // 成功打开数据库
  };
}
基本操作
  • indexedDB.open(dbName, dbVersion): 打开或创建数据库。
  • db.createObjectStore(storeName, options): 创建对象存储。
  • objectStore.createIndex(indexName, keyPath, options): 创建索引。

插入一条数据

javascript 复制代码
function insertOneDB() {
  const transaction = db.transaction(['sex'], 'readwrite'); // 开启事务
  const objectStore = transaction.objectStore('sex'); // 获取对象存储
  const data = { id: 1, title: '男生', author: '张三', createAt: Date.now() }; // 要插入的数据

  const request = objectStore.add(data); // 插入数据

  request.onerror = function(event) {
    console.error('数据写入失败', event.target.error); // 错误处理
  };

  request.onsuccess = function() {
    console.log('数据写入成功'); // 成功插入数据
  };
}
基本操作
  • db.transaction([storeName], mode): 开启事务。
  • transaction.objectStore(storeName): 获取对象存储。
  • objectStore.add(data): 插入数据。

插入多条数据

javascript 复制代码
function insertMultiDB() {
  const data = [
    { id: 2, title: '男生1', author: '李四', createAt: Date.now() },
    { id: 3, title: '男生2', author: '王二', createAt: Date.now() },
    { id: 4, title: '女生', author: '柳如烟', createAt: Date.now() }
  ];

  const transaction = db.transaction(['sex'], 'readwrite'); // 开启事务
  const objectStore = transaction.objectStore('sex'); // 获取对象存储

  data.forEach((item) => {
    const request = objectStore.add(item); // 插入每条数据
    request.onsuccess = function() {
      console.log('数据已添加'); // 成功插入数据
    }
  });

  transaction.oncomplete = function() {
    console.log('所有数据写入完成'); // 所有数据插入完成
  };
}
基本操作
  • db.transaction([storeName], mode): 开启事务。
  • transaction.objectStore(storeName): 获取对象存储。
  • objectStore.add(data): 插入数据。
  • transaction.oncomplete: 事务完成时的回调。

查询数据

ini 复制代码
function queryDB() {
  const transaction = db.transaction(['sex'], 'readonly'); // 开启只读事务
  const objectStore = transaction.objectStore('sex'); // 获取对象存储
  const index = objectStore.index('title'); // 获取索引

  const range = IDBKeyRange.only('女生'); // 创建范围,只查询标题为 '女生' 的数据
  const request = index.openCursor(range); // 打开游标

  request.onsuccess = function(event) {
    const cursor = event.target.result;
    if (cursor) {
      console.log(cursor.value); // 输出匹配的数据
      cursor.continue(); // 继续遍历
    }
  };

  const req = objectStore.get(1); // 通过 ID 查询数据
  req.onerror = function() {
    console.log('查找失败'); // 错误处理
  };

  req.onsuccess = function() {
    console.log(req.result); // 输出查询结果
  };
}
基本操作
  • db.transaction([storeName], mode): 开启事务。
  • transaction.objectStore(storeName): 获取对象存储。
  • objectStore.index(indexName): 获取索引。
  • IDBKeyRange.only(key): 创建一个范围,只包含指定的键。
  • index.openCursor(range): 打开游标。
  • objectStore.get(key): 通过键获取数据。

更新数据

javascript 复制代码
function updateDB() {
  const transaction = db.transaction(['sex'], 'readwrite'); // 开启事务
  const objectStore = transaction.objectStore('sex'); // 获取对象存储
  const data = { id: 1, title: '男生更新', author: '张三', createAt: Date.now() }; // 要更新的数据

  const request = objectStore.put(data); // 更新数据

  request.onerror = function(event) {
    console.error('数据更新失败', event.target.error); // 错误处理
  };

  request.onsuccess = function() {
    console.log('数据更新成功'); // 成功更新数据
  };
}
基本操作
  • db.transaction([storeName], mode): 开启事务。
  • transaction.objectStore(storeName): 获取对象存储。
  • objectStore.put(data): 更新数据。

删除数据

ini 复制代码
function deleteDB() {
  const transaction = db.transaction(['sex'], 'readwrite'); // 开启事务
  const objectStore = transaction.objectStore('sex'); // 获取对象存储
  const idToDelete = 1; // 要删除的 ID

  const request = objectStore.delete(idToDelete); // 删除数据

  request.onerror = function(event) {
    console.error('数据删除失败', event.target.error); // 错误处理
  };

  request.onsuccess = function() {
    console.log('数据删除成功'); // 成功删除数据
  };
}
基本操作
  • db.transaction([storeName], mode): 开启事务。
  • transaction.objectStore(storeName): 获取对象存储。
  • objectStore.delete(key): 删除数据。

效果:


总结

通过上述示例,我们介绍了 localStorage, sessionStorage, Cookies和 IndexedDB 的,localStoragesessionStorage适用于简单的键值对存储,而IndexedDB则提供了更强大的功能,适合存储大量结构化数据。希望本文能帮助你更好地理解和使用这些浏览器本地存储技术,感谢你的阅读!

相关推荐
LOVE️YOU几秒前
HTML&CSS&JavaScript&DOM 之间的关系?
前端·javascript·css·html
胡西风_foxww1 分钟前
【es6复习笔记】集合Set(13)
前端·笔记·es6·set·集合
m0_7482449611 分钟前
VUE前端实现天爱滑块验证码--详细教程
前端·javascript·vue.js
叫我菜菜就好1 小时前
【Flutter_Web】Flutter编译Web第三篇(网络请求篇):dio如何改造方法,变成web之后数据如何处理
前端·网络·flutter
NoneCoder1 小时前
CSS系列(26)-- 动画性能优化详解
前端·css·性能优化
滚雪球~1 小时前
@vue/cli启动异常:ENOENT: no such file or directory, scandir
前端·javascript·vue.js
GDAL1 小时前
vue3入门教程:ref函数
前端·vue.js·elementui
GISer_Jing1 小时前
Vue3状态管理——Pinia
前端·javascript·vue.js
好开心331 小时前
axios的使用
开发语言·前端·javascript·前端框架·html
Domain-zhuo2 小时前
Git常用命令
前端·git·gitee·github·gitea·gitcode