如何实现浏览器标签页之间的通信
浏览器标签页之间通信的实现
使用场景
前端开发过程中,总是避免不了要进行前端标签页之间的通信,最经典的例子莫过于音乐播放网站中,当第一次点击播放列表中的歌曲时,它会打开一个新的标签页进行播放,而当在列表中再次点击歌曲播放时,并不会再多打开一个标签页,而是会在刚才新打开的标签页上播放歌曲。
方式方法
这里跳转新页面均使用window.open
[1]方法,这里稍微说下window.open
方法的参数
-
url
(可选)
一个字符串,表示要加载的资源的 URL 或路径。如果指定空字符串(""
)或省略此参数,则会在目标浏览上下文中打开一个空白页。 -
target
(可选)
一个不含空格的字符串,用于指定加载资源的浏览上下文的名称。如果该名称无法识别现有的上下文,则会创建一个新的上下文,并赋予指定的名称。还可以使用特殊的target
关键字:_self
、_blank
、_parent
和_top
。该名称可用作
<a>
或<form>
元素的target属性。 -
windowFeatures
(可选)
一个字符串,包含以逗号分隔的窗口特性列表,形式为name=value
,布尔特性则仅为name
。这些特性包括窗口的默认大小和位置、是否打开最小弹出窗口等选项。在下面的例子中采用audio,作为浏览上下文的名称,让他从始至终只创建一个新的标签页
1.使用路由上的query传参
list.html
const broadCastChannel = new BroadcastChannel('audio')
function showAudio(){
//方式一:通过query,缺点会刷新已打开的页面,但并没有同源策略影响
window.open('/audio.html?name=张三&id=555','audio')
}
audio.html
const app = document.getElementById('app')
const query = new URLSearchParams(window.location.href.split('?')[1])
app.innerText = query.get('name')
优点:每次打开,audio页面都会变为当前活动标签页
缺点:
- 每次打开,audio页面都会被刷新,重新加载
- 如果新打开的浏览上下文不共享相同的源[2],则打开脚本将无法与浏览上下文的内容进行交互(读取或写入)。
2.使用localStroage监听
利用同源页面[2:1]共享localStroage
的特性,利用windw.addEventLister
监听stroage[3]的变化,来实现两个标签页的通信,详细查看下面例子:
list.html
function showAudio(){
if(!localStorage.getItem('hasAudio')){
window.open('/audio.html','audio')
localStorage.setItem('hasAudio',1)
}
setTimeout(()=>{
localStorage.setItem('name','李四')
},3000)
}
audio.html
window.onunload = () =>{
localStorage.removeItem('hasAudio')
localStorage.removeItem('name')
}
const app = document.getElementById('app')
window.addEventListener('stroage',e=>{
const app = document.getElementById('app')
app.innerText = e.newValue
})
优点:
- 第一次打开,之后再传参无需刷新界面重新加载资源
缺点:
- 打开页面的需为同源页面,localStroage在同源页面中共享
- 同源页面需通过localStroage检控通信,控制麻烦,复杂场景使用不方便
3.使用BroadcastChannel
BroadcastChannel
接口代理了一个命名频道,可以让指定 origin
下的任意 browsing context 来订阅它。它允许同源[2:2]的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。
list.html
const broadCastChannel = new BroadcastChannel('audio')
function showAudio(){
if(!localStorage.getItem('hasAudio')){
window.open('/audio.html','audio')
localStorage.setItem('hasAudio',1)
}
setTimeout(()=>{
broadCastChannel.postMessage({name:'李四'})
},3000)
}
audio.html
window.onunload = () =>{
localStorage.removeItem('hasAudio')
}
const app = document.getElementById('app')
const broadCastChannel = new BroadcastChannel('audio')
broadCastChannel.addEventListener('message',e=>{
const {name} = e.data
const app = document.getElementById('app')
app.innerText = name
})
优点:
- 第一次打开,之后再传参无需刷新界面重新加载资源
- 需要共用频道的页面,通信简单
缺点:
- 打开页面的需为同源页面[2:3],
BroadcastChannel
只会向命名频道相同的同源页面发送和接收消息