html中跨页面通讯方式,web跨页面通信的几种方式

最近在处理一个weex三端的项目,在weex文档中提到,不同的 Weex 页面使用的是不同的执行环境,即使全局变量也是互相隔离的,官方推荐使用BroadcastChannel 来实现实现跨页面通信。由于移动端safri中BroadcastChannel存在兼容问题,因此决定研究下web跨页面通信的其他方法。

参考

1. 使用BroadcastChannel

每个页面通过创建一个具有相同频道名称的 BroadcastChannel 对象来加入特定频道。 然后实现 onmessage 接口来监听消息事件。通过调用 BroadcastChannel 对象上的 postMessage() 方法可以在频道中广播一条消息给所有订阅者。

bc.onmessage = function(ev){

console.log(ev);

bc.postMessage({

msg: `receive message : ${ev.data.msg}`

});

};

另外的页面

bcBtn click

bcBtn.onclick = function(){

bc.postMessage({

msg: "helloWorld"

});

};

bc.onmessage = function(ev){

console.log(ev.data.msg);

};

需要注意的是

这种方式存在兼容问题,移动端safri不支持BroadcastChannel

2. storage事件

当存储域发生改变时会触发事件。(例如: 有新的项被存储),因此可以通过调用localStorage.setItem等方式触发storage事件,然后通知其他监听了改事件的页面

由于onstorage事件是浏览器触发的,所以如果我们打开了多个相同域名下的页面,并在其中任一一个页面执行window.localStorage.setItem方法(还要保证满足文章开头提到的第二个条件),那么其他页面如果监听了onstorage事件,则这些页面中的onstorage事件回调都会被执行

// 1.html

window.addEventListener("storage", function(e){

let msg = e.key +

" 键已经从 " +

e.oldValue +

" 改变为 " +

e.newValue +

"."

console.log(msg)

outputScreen.innerHTML = msg

})

// 2.html

localStorage.setItem("test", Math.floor(Math.random()*10000))

需要注意

只有当存储的值改变时才会触发storage事件,即新值与旧值不同

触发写入操作的页面下的storage listener不会被触发

即使页面不再同一个浏览器窗口(比如打开两个Chrome浏览器实例),storage也能够触发

safari隐身模式下无法设置localStorage值

参考

3. shareWorker

SharedWorker可以被多个window共同使用,但必须保证这些标签页都是同源的

// 1.html

var sharedworker = new SharedWorker('worker.js')

sharedworker.port.start()

workerBtn.onclick = function(){

// 发送消息

sharedworker.port.postMessage('hello')

}

// 2.html

var sharedworker = new SharedWorker('worker.js')

sharedworker.port.start()

// 接收消息

sharedworker.port.onmessage = evt => {

// evt.data

console.log(evt)

}

然后还需要一个worker文件

// worker.js

const ports = [];

onconnect = e => {

const port = e.ports[0];

ports.push(port);

port.onmessage = evt => {

ports

.filter(v => v !== port) // 此处为了贴近其他方案的实现,剔除自己

.forEach(p => p.postMessage(evt.data));

};

};

参考

4. 获取对应窗口引用

4.1. postMessage

只要获取了对应窗口的window对象,如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames,就可以调用

otherWindow.postMessage(message, targetOrigin, [transfer]);

向该窗口发送消息,在该页面上,只要监听了message事件即可

postBtn click

document.getElementById("otherPage").contentWindow.postMessage("hello","http://phptest2.com");

}

window.addEventListener("message", function receiveMessage(event){

console.log(event.data);

}, false);

// test.html

function receiveMessage(event) {

outputScreen.innerHTML = event.data;

event.source.postMessage(

"hi there yourself! the secret response " +

"is: rheeeeet!",

event.origin

);

}

window.addEventListener("message", receiveMessage, false);

postMessage的兼容性较好,可以跨域传递消息,但需要获取到目标窗口引用才行,因此使用有局限性。

参考

4.2. window.opener

window.opener返回的是打开当前窗口的那个窗口的引用,在某些时候如果需要与前一个窗口进行单项通信,则可以使用该属性实现,考虑下面打开新窗口的场景

使用window.open打开了一个新的窗口

使用a链接通过target="_blank"打开了一个新的窗口

在新打开的窗口中,可以通过window.opener获取前一个窗口的引用,然后就可以修改前一个窗口页面上的内容了

// 如果不是从任何窗口打开,则opener为null

if(window.opener){

window.opener.document.getElementById("contentScreen").innerHTML = 'change from open window'

}

需要注意的是

该方法受同源策略限制,即无法通过window.opener修改非同源的窗口文档内容

参考

5. 共享数据

多个页面之间,可以通过共享数据,然后检测数据的变化来判断是否需要执行相关逻辑

5.1. 本地存储数据,轮询

比如通过写入localStorage、cookie等共享数据存储空间,

由于cookie的改变没有事件通知,所以只能采取轮询脏检查来实现业务逻辑。localStorage修改存储内容有storage事件,可以直接处理(参考上面的:使用stroage事件)

然后检测数据的值是否发生变化,如果发生变化,则执行相关回调

污染数据存储空间

修改cookie会增加额外的网络请求成本

5.2. 服务端储存

前端定期保存修改的数据到服务器,然后通过onvisibilitychange、window.onpageshow等事件回调时重新获取数据,更新页面数据内容

window.onvisibilitychange = () => {

if (document.visibilityState === 'visible') {

// AJAX更新数据

reload()

}

}

window.addEventListener("pageshow", reload)

6. 小结

目前的主流web应用均开始采用单页面应用,多个路由组件之间的通信可以通过vuex、redux等状态管理工具进行处理。web跨页面通信的使用场景并不是十分频繁,尤其是在移动端中,同时打开多个标签页,且需要这些标签页进行通信的场景是比较少的,在工作中主要遇见的情形有

某个活动页面要求用户签到后才可以进行下一步操作,点击确认前往签到页面,从签到页面返回后当前页面需要更新用户的签到状态

从个人中心前往信息编辑页面,返回后更新个人中心的用户数据状态

这些需求一般都是通过服务端保存数据信息,返回页面时重新调用接口更新页面数据即可。不过,了解跨页面通信还是很有必要的,这个在PC浏览器上的使用场景应该要频繁一些。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值