观察者:localStorage更新后,如何通知?

695 阅读5分钟

前言

  • 常网IT源码上线啦!
  • 本篇录入吊打面试官专栏,希望能祝君拿下Offer一臂之力,各位看官感兴趣可移步🚶。
  • 有人说面试造火箭,进去拧螺丝;其实个人觉得问的问题是项目中涉及的点 || 热门的技术栈都是很好的面试体验,不要是旁门左道冷门的知识,实际上并不会用到的。
  • 接下来想分享一些自己在项目中遇到的技术选型以及问题场景。

我一直觉得人应该先了解自己,先认识自己是什么样的人,想过什么样的生活。
可是行动是产生结果的唯一途径。
你有这个想法,你想去认识自己,可能这个想法,世界上有一万个人想到,真正去坐的只有一千个人,找到自己的只有一百个人,我们先当这一千个,再当这一百个人。

2.JPG

大家知道,这里是哪里嘛

一、前言

今天像往常一样,开开心心的打代码编程。

突然产品说:这个加入购物车之后,右侧要实时显示数量,并且在页面刷新的时候,依然保存起来。

于是便有了今天这篇文章,一起来探讨一下。

当然,你也可以当做实操性面试题。

二、分析

后端同学说:这个应该不用调接口,保存吧。

霸气回复:并不需要,我大前端足矣!

当然,在说之前,我们是有底气的,相信大家第一想到就是:localStorage。

我们知道,localStorage的set完值之后,不会像观察者模式有通知机制的。

上个月去考了软考,猛学设计模式,之前看是一定的了解,现在学了这么多年前端,再去看,又有不一样的思考。

既然localStorage没有提供相关事件,那我们便无中生有。

于是我们需要借用storage 事件来实现。

这样,当一个组件(例如 A 组件)设置了 localStorage 的值时,另一个组件(例如 B 组件)能够接收到该变化。

而这里,我们需要先封装 localStorage.setItem 方法。

三、setItem

首先,我们封装 localStorage.setItem 方法,当设置 localStorage 的值时,手动触发 storage 事件,以便其他组件能接收到更新。

utils/localStorage.js

const originalSetItem = localStorage.setItem;

// 封装 localStorage.setItem 方法
localStorage.setItem = function(key, value) {
    // 调用原始的 setItem 方法
    originalSetItem.apply(localStorage, arguments);

    // 触发 storage 事件,通知其他页面
    const event = new StorageEvent('storage', {
        key: key,
        newValue: value,
        oldValue: localStorage.getItem(key),
        storageArea: localStorage,
    });
    window.dispatchEvent(event);
};

监听 storage 事件

在 Vue 组件中,我们可以使用 window.addEventListener 来监听 storage 事件,并在事件发生时执行相关的回调函数。

四、代码实现

A页面

加入购物车相关逻辑

change(data) {
  const appliedList = JSON.parse(localStorage.getItem('appliedList') || '[]')
  // 选中
  if(data.isSelectCart) {
    const _index = appliedList.map(a => a.id).indexOf(data.id)
    appliedList.splice(_index, 1)
  } else {
    appliedList.push(data)
  }
  this.$set(data, 'isSelectCart', !data.isSelectCart)
  localStorage.setItem('appliedList', JSON.stringify(appliedList))
}

B页面

A页面setItem的时候,会触发我们重写的localStorage,StorageEvent触发 storage 事件,通知其他页面。

而在B页面的代码监听:

mounted() {
  // 监听 storage 事件
  window.addEventListener('storage', this.handleStorageChange)
  
  // 初始时检查 localStorage 是否已经有值
  const storedData = localStorage.getItem('appliedList')
  if (storedData) {
    const appliedList = JSON.parse(localStorage.getItem('appliedList') || '[]')
    this.badge = appliedList.length	// 显示
  }
}

handleStorageChange(event) {
    if (event.key === 'appliedList') {
      const appliedList = JSON.parse(localStorage.getItem('appliedList') || '[]')
      this.badge = appliedList.length // 显示
    }
  }

五、上线

于是,你在本地调试了,发现效果确实是达到了,A页面set之后,B页面也确实收到了消息更新。

欣喜若狂部署到线上,测试说,你这也没实现啊。

是的,我早知道了,因为StorageEvent该事件能够让多个页面(或不同的标签页)在同一浏览器中相互通信,从而实现跨标签页的数据同步。

注意只是在不同标签才会通知,当前标签是不会更新的。

所以,我们还要借着vuebus去做更新通知。

这个比较简单,如果有不明白的,可以留言讨论。

六、StorageEvent

来都来了,顺便了解一下StorageEvent。

该事件能够让多个页面(或不同的标签页)在同一浏览器中相互通信,从而实现跨标签页的数据同步。

StorageEvent 事件对象包含多个关键属性,用来描述存储的更新情况:

  • key:表示被修改的 localStorage 或 sessionStorage 项的键名(即字段名)。当调用 clear() 清空所有存储项时,key 的值将为 null
  • newValue:表示存储项的新值。如果是通过 removeItem() 删除某项数据,newValue 将为 null
  • oldValue:表示存储项更新前的旧值。如果使用 setItem() 设置新值,则 oldValue 为更新前的值。如果是通过 removeItem() 删除某项,oldValue 将是被删除的值。
  • url:触发该事件的文档的 URL,指明了存储操作发生的页面来源。
  • storageArea:指向 localStorage 或 sessionStorage 对象,表示当前操作的是哪个存储区域。这个值通常为 localStorage 或 sessionStorage,取决于使用的存储类型。

StorageEvent 事件通常用于在同一浏览器中不同标签页之间同步数据。

至此撒花~

后记

我们在实际项目中或多或少遇到一些奇奇怪怪的问题。

自己也会对一些写法的思考,为什么不行🤔,又为什么行了?

最后,祝君能拿下满意的offer。

我是Dignity_呱,来交个朋友呀,有朋自远方来,不亦乐乎呀!深夜末班车

👍 如果对您有帮助,您的点赞是我前进的润滑剂。

以往推荐

小小导出,我大前端足矣!

靓仔,说一下keep-alive缓存组件后怎么更新及原理?

面试官问我watch和computed的区别以及选择?

面试官问我new Vue阶段做了什么?

前端仔,快把dist部署到Nginx上

多图详解,一次性啃懂原型链(上万字)

Vue-Cli3搭建组件库

Vue实现动态路由(和面试官吹项目亮点)

项目中你不知道的Axios骚操作(手写核心原理、兼容性)

VuePress搭建项目组件文档

原文链接

juejin.cn/spost/74433…