浏览器间的跨窗口通信之storage

简介

继上篇文章,浏览器间的跨窗口通信之postMessagepostMessage 可以实现浏览器窗口间之间的通信,但终归于一点,使用起来有点复杂,如果我的需求很简单:

  • 同域名下通信

  • 只需要在特定情况下两窗口间可以互消息传递。

再继续使用哪种方式是不是有点大材小用了?于是本文的 storage 就进入了我的视线。

代入

首先大家可以先看一个例子:

  • 打开 QQ音乐官网(此时我们称这个页面为A)

  • 随便点击一首专辑或者歌曲进行播放

  • 然后就发现是个新开标签页,专门用来当播放器(我们称这个页面为B)

  • 如果此时返回A页面,点击一首其他歌曲,会发现自动跳到之前打开的 页面B ,页面并无整体刷新,而是更新歌单并进行播放新的歌曲

看到这里,如果熟悉相关API同学的话,大概就有思路了。

逐步

首先需要我们来熟悉一个 window 事件,storage 事件。

事件参考 StorageEvent

image.png

该事件使用方式很简单,代码如下:


window.addEventListener('storage', function(stroageEvent) {
  console.log('stroageEvent :>> ', stroageEvent);
})

复制代码

以下所指 storage 均为 localStorage ,至于为什么不使用 sessionStorage,请滑至文章底部,或者直接点击右侧大纲的 反问

如果你也恰巧写了个 demo ,在当前页面修改 localStorage 想触发 storage 事件,但发现并没有。无意中发现可以通过控制台修改localStorage 值来触发事件。

若未尝试动手,可以看下这个 demo

初次碰到我也有点迷惑,直到看到文档解释,瞬间秒懂。MDN

image.png

总结一下就是 storage 事件触发只能通过其他同域下的页面进行修改才会触发,当前页面修改 storage 值不会在当前页面触发 storage 事件。

这只是小插曲,并不影响我们想做的事。

然后仅凭以上聊到的知识,就可以让我们解决了浏览器跨窗口通信的问题。代码如下

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>A页面</title>
</head>
<body>
  <button id="writeBtn">写入storage一个值</button>
  <button id="deleteBtn">删除storage一个值</button>
  <button id="modifybtn">修改storage一个值</button>

  <script>
    let symbolKey = 0
    let writeBtn = document.getElementById('writeBtn')
    let deleteBtn = document.getElementById('deleteBtn')
    let modifybtn = document.getElementById('modifybtn')


    writeBtn.addEventListener('click', function() {
      localStorage.setItem(symbolKey++, Date.now())
    })
    deleteBtn.addEventListener('click', function() {
      const key = localStorage.key(0)
      if(!key) {
        console.log('已无可删的localStorage键值了')
        return
      }
      localStorage.removeItem(key)
    })
    modifybtn.addEventListener('click', function() {
      const key = localStorage.key(0)
      if(!key) {
        console.log('已无可删的localStorage键值了')
        return
      }
      localStorage.setItem(key, Date.now())
    })
  </script>
</body>
</html>
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>B页面</title>
</head>
<body>
  <script>
    window.addEventListener('storage', function(stroageEvent) {
      console.log('stroageEvent :>> ', stroageEvent);
    })
  </script>
</body>
</html>
复制代码

codesandebox 代码链接

预览链接A页面 预览链接B页面

复盘

回到最开始我们提到的 QQ音乐官网 例子

  • 打开 QQ音乐官网

  • 随便点击一首专辑或者歌曲进行播放

    • 将歌单信息存入 localStorage
  • 然后就发现是个新开标签页,专门用来当播放器

    • 在A页面调用 window.open 新开标签页,并可以获取到新开标签页(页面B)的 window 对象。

    • 读取 localStorage 存入的歌单信息,进行播放操作

  • 如果此时返回A页面,点击一个其他歌单,会发现自动跳到之前打开的 页面B ,页面并无整体刷新,而是更新歌单并进行播放新的歌曲

    • A页面点击一首其他歌曲,或者歌单(实测,点击歌单回清空播放列表,然后播放新歌单。而点击歌曲,则会添加到播放列表首位)同时也对应着修改 storage 为不同的值。

    • 从A页面跳转至B页面,可以调用 window.focus() ,第三步已获取到B页面的 window 对象,就可以调用此方法进行B页面获取焦点。

    • B页面(播放器页)触发 storage 事件,重新读取播放列表,进行播放。

反问

sessionStorage 不可以吗?

引用 MDN :

  • 其区别在于:存储在 localStorage 的数据可以长期保留;而当页面会话结束——也就是说,当页面被关闭时,存储在 sessionStorage 的数据会被清除 。

  • 打开多个相同的URL的Tabs页面,会创建各自的sessionStorage

我怎么确定QQ音乐就是使用 Storage 进行通信的?

恰巧在思考浏览器跨窗口通信问题时,打开QQ音乐官网,看到这个有趣,就尝试在本地找一些有用的数据看看,果不其然在 localStorage 看到了播放列表信息。

为了验证我的猜想正确,就在播放器页添加了一个 storage 事件,然后在首页另外点了一个歌单,然后就在预料之中的触发了后添加的 storage 事件。

image.png

总结

这个比之前的 postMessage 整体理解起来简单很多,抛开其他,单聊 storage 事件。

无非就一下两点

  • A 页面进行对 storage 信息进行增删改。

  • B 页面进行监听 storage 事件,然后对修改后的值进行相关操作。

done.

最后,问下大家如果写一篇文章的话,一般需要多长时间?

感觉我每次写篇文章至少都需要三四小时,这还不包括对所写内容的探索,实践,验证等一系列过程,而且感觉最后写出来的文章和水文没区别,哈哈哈哈。

最后,如果您对这篇文章有什么看法,欢迎发表您的观点。

猜你喜欢

转载自juejin.im/post/7032989532601450533