简介
继上篇文章,浏览器间的跨窗口通信之postMessage,postMessage
可以实现浏览器窗口间之间的通信,但终归于一点,使用起来有点复杂,如果我的需求很简单:
-
同域名下通信
-
只需要在特定情况下两窗口间可以互消息传递。
再继续使用哪种方式是不是有点大材小用了?于是本文的 storage
就进入了我的视线。
代入
首先大家可以先看一个例子:
-
打开 QQ音乐官网(此时我们称这个页面为A)
-
随便点击一首专辑或者歌曲进行播放
-
然后就发现是个新开标签页,专门用来当播放器(我们称这个页面为B)
-
如果此时返回A页面,点击一首其他歌曲,会发现自动跳到之前打开的
页面B
,页面并无整体刷新,而是更新歌单并进行播放新的歌曲
看到这里,如果熟悉相关API同学的话,大概就有思路了。
逐步
首先需要我们来熟悉一个 window 事件,storage
事件。

该事件使用方式很简单,代码如下:
window.addEventListener('storage', function(stroageEvent) {
console.log('stroageEvent :>> ', stroageEvent);
})
复制代码
以下所指 storage
均为 localStorage
,至于为什么不使用 sessionStorage
,请滑至文章底部,或者直接点击右侧大纲的 反问
。
如果你也恰巧写了个 demo
,在当前页面修改 localStorage 想触发 storage 事件,但发现并没有。无意中发现可以通过控制台修改localStorage 值来触发事件。
若未尝试动手,可以看下这个 demo
初次碰到我也有点迷惑,直到看到文档解释,瞬间秒懂。MDN
总结一下就是 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>
复制代码
复盘
回到最开始我们提到的 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
事件。
总结
这个比之前的 postMessage 整体理解起来简单很多,抛开其他,单聊 storage
事件。
无非就一下两点
-
A 页面进行对 storage 信息进行增删改。
-
B 页面进行监听
storage
事件,然后对修改后的值进行相关操作。
done.
最后,问下大家如果写一篇文章的话,一般需要多长时间?
感觉我每次写篇文章至少都需要三四小时,这还不包括对所写内容的探索,实践,验证等一系列过程,而且感觉最后写出来的文章和水文没区别,哈哈哈哈。
最后,如果您对这篇文章有什么看法,欢迎发表您的观点。