通过项目中的实际例子,介绍 LocalStorage 在 Angular 开发中的使用场景

笔者之前在掘金社区的技术文章,介绍过自己项目组中负责开发的一款基于 Angular 的电商 SDK:

本文笔者会分享自己项目过程中,在设计这款 SDK 时使用 Web 开发领域的 LocalStorage 技术来实现的一个功能。

用户访问 Storefront 的 homepage,可以在 Language 的下拉菜单里,选择语言:

比如下图是语言切换成中文的效果:

同样还支持货币单位的切换:

客户的需求是,更改的这些设置,在关闭浏览器之后,仍然能够生效。意思是下次重新打开浏览器,Storefront homepage 仍然按照之前的设置去加载。

为此,我们团队采取的实现方式是,利用 Web 开发领域中的 LocalStorage 技术,来持久化用户指定的 Language 和货币单位的更改。

Local Storage 技术概述

Local Storage 技术是一种在Web 浏览器中用于客户端数据存储的机制。它允许 Web 应用程序在用户的本地浏览器上存储键值对形式的数据,这样用户在关闭浏览器窗口或页面后,数据仍然可以保留。这为开发者提供了一种在客户端持久保存数据的简单方式,而不必依赖于服务器。

我们在 Chrome 开发者工具 Application 面板里,可以清晰观察到这些 Key Value 键值对:

Local Storage 是Web Storage API 的一部分,与 Session Storage 不同,Local Storage 的数据在关闭浏览器后仍然存在。它使用键值对的形式存储数据,其中键和值都是字符串。该技术基于域名,即同一域名下的所有页面共享相同的 Local Storage

使用方式也非常简单直观,使用其提供的 get 和 set API 即可。

在 JavaScript 中,通过 localStorage 对象来访问和操作 Local Storage。以下是一些基本的 localStorage 操作:

存储数据:

javascript 复制代码
// 存储数据
localStorage.setItem('username', 'John');

// 存储数字
localStorage.setItem('userAge', 25);

读取数据:

javascript 复制代码
// 读取数据
const username = localStorage.getItem('username');
const userAge = localStorage.getItem('userAge');

删除数据:

javascript 复制代码
// 删除数据
localStorage.removeItem('username');

清空所有数据:

javascript 复制代码
// 清空所有数据
localStorage.clear();

我们项目组当时选择用 LocalStorage 技术来实现用户需求,也是基于了如下考虑:

  1. 持久性: 数据在浏览器关闭后仍然存在,适用于长期保存用户偏好设置等信息,比如我们项目中客户对于 Language 和货币单位的持久化需求。

  2. 容量: Local Storage 允许存储较大数量的数据(通常至少5MB),相对于 Cookie 的4KB而言,具备更大的容量,我们用来存储两个字符串值,可以说是绰绰有余。

  3. 简易性: 使用简单的键值对操作,易于理解和实现。

尽管 LocalStorage 数据存储在客户端,但是我们存储的仅仅是 Language 和货币单位,所以不存在敏感信息。

Local Storage 技术的项目实战

首先我们在 state-config.ts 文件里定义了 StorageSyncType 的枚举值:

可以看到目前我们打算支持 LocalStorage 和 SessionStorage 两种方式,方便 SDK 的 consumer 自己切换。

而 getStorage 函数用来封装获取 LocalStorage API 的行为:

typescript 复制代码
export function getStorage(
  storageType: StorageSyncType,
  winRef: WindowRef
): Storage | undefined {
  let storage: Storage | undefined;

  switch (storageType) {
    case StorageSyncType.LOCAL_STORAGE: {
      storage = winRef.localStorage;
      break;
    }
    case StorageSyncType.SESSION_STORAGE: {
      storage = winRef.sessionStorage;
      break;
    }
    case StorageSyncType.NO_STORAGE: {
      storage = undefined;
      break;
    }

    default: {
      storage = winRef.sessionStorage;
    }
  }

这里 storage API 从依赖注入参数的 winReflocalStorage 或者 sessionStorage 字段里读取。 这两个字段都是全局对象 window 里的标准属性之一。

本文之前介绍的 LocalStorage API 就位于 localStorage 字段的原型链上,如下图高亮区域所示:

language 字段的 LocalStorage 读取

用户重新打开浏览器时,需要从 LocalStorage 里将存储的 language 字段值读取出来。

这个场景通过下图的 readFromStorage 函数实现:

typescript 复制代码
export function readFromStorage(storage: Storage, key: string): unknown {
  if (isSsr(storage)) {
    return;
  }

  const storageValue = storage.getItem(key);
  if (!storageValue) {
    return;
  }

  return JSON.parse(storageValue);
}

逻辑很直接,首先判断是否是在 SSR 环境下,如果是就直接返回。因为按照笔者这篇文章的介绍,用户的个性化设置和私有数据页面,比如购物车,WishList 等,不应该被 Angular 服务器端渲染考虑,所以我们代码里如果 isSsr 检测函数返回 true,直接返回;否则调用 storage 的 API 即 getItem 返回浏览器 LocalStorage 里的存储值。

下面是调试器里的截图:

language 字段的 LocalStorage 的写入

当用户在 Storefront 界面上用下拉菜单更换 Language 字段值时,会调用 browser-storage.ts 里的 persistToStorage 方法:

我们可以看到这个方法里调用代码第 44 行的 setItem,将 Angular UI 上用户选定的值写入到 LocalStorage 里。

下拉菜单的实现位于 site-context-selector.component.html 文件内部。当用户切换下拉菜单值的时候,触发第 3 行 select 元素的 change 事件。

事件的处理函数主体就只有一个 active = $any($event).target.value 的赋值操作,这会触发定义在 active 属性上的 set 方法:

set 方法里调用 this.componentService.setActive(value, this.context),这个函数调用最终把执行投递到 storage.setItem(configKey, JSON.stringify(value)) 上去:

总结

在 Local Storage 出现之前,客户端数据存储主要依赖于 cookies。但是,cookies 存在许多不足,比如存储空间有限(通常只有 4KB),数据在每次 HTTP 请求时都会被发送到服务器,这会消耗更多的带宽。相比之下,Local Storage 提供了更大的存储空间(通常是 5MB),并且数据只存储在客户端,不会被发送到服务器。这使得 Local Storage 成为一种更有效的客户端数据存储方式。

本文介绍了笔者在实际 Angular 开发项目中使用 Local Storage 来持久化用户个性化选择的一个案例,希望能帮助到需要实现类似功能的开发者们。

相关推荐
Nicholas68几秒前
flutterAppBar之SystemUiOverlayStyle源码解析(一)
前端
黑客飓风17 分钟前
JavaScript 性能优化实战大纲
前端·javascript·性能优化
emojiwoo2 小时前
【前端基础知识系列六】React 项目基本框架及常见文件夹作用总结(图文版)
前端·react.js·前端框架
张人玉2 小时前
XML 序列化与操作详解笔记
xml·前端·笔记
杨荧2 小时前
基于Python的宠物服务管理系统 Python+Django+Vue.js
大数据·前端·vue.js·爬虫·python·信息可视化
YeeWang3 小时前
🎉 Eficy 让你的 Cherry Studio 直接生成可预览的 React 页面
前端·javascript
gnip3 小时前
Jenkins部署前端项目实战方案
前端·javascript·架构
Orange3015113 小时前
《深入源码理解webpack构建流程》
前端·javascript·webpack·typescript·node.js·es6
lovepenny4 小时前
Failed to resolve entry for package "js-demo-tools". The package may have ......
前端·npm
超凌4 小时前
threejs 创建了10w条THREE.Line,销毁数据,等待了10秒
前端