关于你不知道的storage事件

168 阅读3分钟

windowstorage 事件不知道大家有没有使用过,今天在写业务的时候由于页面设计的不太合理,需要分离两个本应该在一块的组件。当然也可以通过 router-view 传参去搞定这件事情,但是我想尝试一下新的方法。

首先来介绍一下 window.storage 事件的作用,当前页面当中的 sessionStorage 或者 localStorage 发生变化的时候会触发该监听事件,可以理解为一个响应式的数据,数据变化之后去通知对应的依赖更新。

<template>
    {{ curNum }}
    <el-button @click="handleChangeStorage(index)">更新</el-button>
</template>
<script setup>
...
const curNum = ref(0)
function handleChangeStorage (newVal) {
    sessionStorage.setItem('curNum', `${++curNum.value}`) // 此处也可以使用localStorage,这个不影响
}
onMounted(() => {
    curNum.value = JSON.parse(sessionStorage.getItem('curNum') || '0')
})
<script>


以上是一个简单的方法去更新了一下当前会话存储空间当中的 curNum 这个字段。接下来我们去另一个页面去添加 windowstorage 事件。

...
onMounted(() => {
    window.addEventListener('storage', (event) => {
        console.log('%c [ event ]-134', 'font-size:13px; background:pink; color:#bf2c9f;', event)
    })
})

按理来讲他应该会打印出来一个 Event 事件,但是此时点击去触发更新 curNum 并不会触发该方法的执行。那么此时通过getEventListener(window)查询到window身上是有这个事件的,仅仅是没有触发,那么我直接手动修改他的值会触发吗?答案是会的,返回对象如下如所示:

image.png

但是我通过代码修改的 curNum 并不会触发该事件,我很疑惑,为什么他不会触发呢?都是修改了值,只有方式不一样,然后我去百度搜索了一下相关的信息,得出的结论是 默认情况下,当前页面修改localStorage,本页面是无法监听的,只有同源的其他页面才可以监听到本页面localStorage的改变。 合着我在本页面修改了二级路由,但是由于二级路由部分与下方的 router-view 是分离的还监听不到这个的变化,我直接吐出一口老血。

到这里问题已经出来了,那么如何解决这个问题呢?通过查询百度,我找到了解决方案,如下:

function handleNewStorage() {
  var orignSetItem = window.localStorage.setItem
  window.localStorage.setItem = function (key, newValue) {
    var newSetItemEvent = new Event('newSetItemEvent')
    newSetItemEvent.newValue = newValue
    newSetItemEvent.key = key
    window.dispatchEvent(newSetItemEvent) // 抛出我们在上面定义的事件 (newSetItemEvent)
    orignSetItem.apply(this, [key, newValue])
  }
}

我们通过对 setItem 事件的重新封装并且通过 dispatchEvent 添加了该自定义事件,通过 apply 传入了我们想要的数据,接下来我们通过监听我们自己写的自定义事件就可以在本窗口监听数据的变化了。

onMounted(() => {
    window.addEventListener('newSetItemEvent', (event) => {
        console.log('%c [ event ]-134', 'font-size:13px; background:pink; color:#bf2c9f;', event)
    })

截图如下:

image.png

此时我们已经成功的获取到了心心念念的 Event 对象,这次开发过程遭遇是我没有预料到,在此谨记。当然也在最开始就说过,可以通过 router-view 传参去简单解决这个问题。但是那样就学不到这个知识点了,也算是有所收获吧!