成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

六種瀏覽器跨窗口通信方案 - 從實(shí)際案例出發(fā)

系統(tǒng) 瀏覽器
各種方式都可以實(shí)現(xiàn)通知列表頁(yè)去做刷新動(dòng)作,不過(guò)更推薦使用 window.opener? 或 BroadcastChannel 來(lái)實(shí)現(xiàn),這兩種方式相對(duì)使用簡(jiǎn)單并且很符合這個(gè)業(yè)務(wù)場(chǎng)景。

瀏覽器跨窗口通信,聽(tīng)上去挺有技術(shù)感的,但實(shí)現(xiàn)起來(lái)方案倒是挺多的。本文將從一個(gè)實(shí)際的業(yè)務(wù)開(kāi)發(fā)場(chǎng)景,帶你了解如何實(shí)現(xiàn)瀏覽器跨窗口通信。

業(yè)務(wù)場(chǎng)景

一個(gè)常規(guī)的業(yè)務(wù)列表頁(yè),頁(yè)面中提供了一個(gè)新增功能,由于新增功能的表單項(xiàng)內(nèi)容比較多,所以交互上使用新開(kāi)一個(gè)窗口來(lái)完成。這時(shí)問(wèn)題來(lái)了,在新增完成后,如何通知列表頁(yè)面刷新列表數(shù)據(jù),以便展示出剛才新增的那一條數(shù)據(jù)。

圖片圖片

各位可以先自己在心中簡(jiǎn)單想想,如果讓你實(shí)現(xiàn)這個(gè)功能,你會(huì)使用什么方案。

解決方案

window.opener

window.opener 代表的是打開(kāi)當(dāng)前窗口的那個(gè)窗口的引用,例如:在 window A 中打開(kāi)了 window B,B.opener 返回 A。

有了這個(gè)引用關(guān)系,我們就可以實(shí)現(xiàn)跨窗口通信:

圖片圖片

  1. 列表頁(yè)設(shè)置刷新列表方法 window.refreshList = () => {}
  2. 列表頁(yè)通過(guò) window.open 或者 <a href="newUrl" target="_blank" rel="opener">新增</a> 打開(kāi)新增功能頁(yè)面。
  3. 用戶完成新增表單填寫并提交,通過(guò)調(diào)用 window.opener.refreshList 方法來(lái)刷新列表頁(yè)面數(shù)據(jù),并關(guān)閉當(dāng)前頁(yè)。

有人可能注意到了,在 a 標(biāo)簽中我們使用到了 rel="opener" 屬性,為什么要設(shè)置這個(gè)屬性呢?

rel 屬性定義了所鏈接的資源與當(dāng)前文檔的關(guān)系,常見(jiàn)的屬性值有:

  • opener: 打開(kāi)的新頁(yè)面 window.opener 會(huì)指向前一個(gè)頁(yè)面的 window。
  • noopener: 和 opener 相對(duì)應(yīng), window.opener 為空。
  • noreferrer:打開(kāi)新頁(yè)面時(shí)請(qǐng)求頭不會(huì)包含 Referer,比如你未設(shè)置 noreferrer 的情況下,從 antd 打開(kāi)百度,百度頁(yè)面請(qǐng)求頭就有 Referer: https://ant.design/
  • nofollow: 主要用于 SEO,告訴搜索引擎忽略該鏈接。

主要關(guān)注 opener 和 noopener 屬性,a 標(biāo)簽?zāi)J(rèn)情況下 rel=noopener,這代表打開(kāi)的新增頁(yè)面的 window.opener 對(duì)象會(huì)為空,所以需要設(shè)置 rel=opener。

那么又有一個(gè)問(wèn)題,為什么 a 標(biāo)簽?zāi)J(rèn)是 rel=noopener, 因?yàn)?nbsp;opener 存在安全漏洞,比如你以 opener 的方式打開(kāi)了一個(gè)未知的新頁(yè)面,這個(gè)新頁(yè)面可以通過(guò) window.opener.location.href = 'fake.com' 重定向你的頁(yè)面。

而 window.open 默認(rèn)情況下 rel=opener,故打開(kāi)的新頁(yè)面可以拿到 window.opener 對(duì)象,不過(guò)要是打開(kāi)第三方未知網(wǎng)站,建議設(shè)置為 noopener, 比如 window.open('https://baidu.com', 'title', 'noopener,noreferrer')。

BroadcastChannel

BroadcastChannel API 顧名思義,為“廣播頻道”,適用于在同一域名下的多個(gè)窗口、標(biāo)簽頁(yè)或 iframe 之間進(jìn)行實(shí)時(shí)消息廣播。它的使用也非常簡(jiǎn)單,我們也看下如何通過(guò)它來(lái)實(shí)現(xiàn)上面的業(yè)務(wù)場(chǎng)景。

列表頁(yè)創(chuàng)建一個(gè) BroadcastChannel 實(shí)例來(lái)監(jiān)聽(tīng)消息:

// 創(chuàng)建 BroadcastChannel 實(shí)例
const channel = new BroadcastChannel('myChannel');

// 監(jiān)聽(tīng)廣播通道的消息
channel.addEventListener('message', (event) => {
  console.log('接收:', event.data); // { action: 'refresh' }
})

新增功能頁(yè)面同樣創(chuàng)建一個(gè) BroadcastChannel 實(shí)例,頻道名稱需要和列表頁(yè)一致:

// 創(chuàng)建 BroadcastChannel 實(shí)例
const channel = new BroadcastChannel('myChannel');
// 向廣播通道發(fā)送消息
channel.postMessage({ action: 'refresh' });
// 關(guān)閉頻道
channel.close()

可以看到 BroadcastChannel 的使用很簡(jiǎn)單,雙方創(chuàng)建同名頻道的 BroadcastChannel 實(shí)例,然后一方監(jiān)聽(tīng) message 事件,一方使用 postMessage 廣播內(nèi)容。

postMessage

對(duì)于 postMessage,我們最常用的方式應(yīng)該就是當(dāng)前頁(yè)面和 iframe 的跨域消息通信了,其實(shí)它也能完成跨窗口通信,核心就是能拿到新窗口的 window 對(duì)象,這個(gè)在 window.opener 方案中我們就知道通過(guò)設(shè)置 rel="opener" 就可以辦到。

列表頁(yè)打開(kāi)新窗口,并監(jiān)聽(tīng) message 事件:

<a href="./add.html" target="_blank" rel="opener">新增</a>
<script>
  // 不同與 BroadcastChannel,這邊是監(jiān)聽(tīng) window 上的 message 事件
  window.addEventListener("message", receiveMessage);
  function receiveMessage(event) {
    console.log('接收:', event.data); // { action: 'refresh' }
  }
</script>

新增功能頁(yè)面使用 window.opener.postMessage 發(fā)送消息:

window.opener?.postMessage({ action: 'refresh' }, '*');

至此我們已經(jīng)完成了上面的業(yè)務(wù)需求,postMessage 的優(yōu)勢(shì)在于可以跨域。

MessageChannel

MessageChannel API 允許我們創(chuàng)建一個(gè)新的消息通道,并通過(guò)它的兩個(gè) MessagePort 實(shí)例屬性發(fā)送數(shù)據(jù),同時(shí)它也可以跨域通信。

不同于 BroadcastChannel 的廣播,MessageChannel 只提供雙向通信通道,不過(guò)它既可以像 postMessage 一樣用于 iframe 通信,也可以用于 Web Worker 之間進(jìn)行通信。

圖片圖片

要用 MessageChannel 實(shí)現(xiàn)跨窗口通信,方式有點(diǎn)類似 postMessage, 打開(kāi)新頁(yè)面時(shí)需要設(shè)置 rel="opener"。

列表頁(yè)初始化 MessageChannel 實(shí)例,并在 port1 上監(jiān)聽(tīng) message 事件:

// 創(chuàng)建 MessageChannel 實(shí)例
window.messageChannel = new MessageChannel();
const port1 = window.messageChannel.port1;
// port1 監(jiān)聽(tīng) message 事件
port1.onmessage = function(event) {
  console.log('接收:', event.data); // { action: 'refresh' }
};

新增功能頁(yè)面使用 window.opener.messageChannel 拿到列表的 MessageChannel 實(shí)例,并使用 port2 的 postMessage 方法往 port1 通道上發(fā)送消息:

// 獲取 MessageChannel 實(shí)例
const messageChannel = window.opener.messageChannel;
const port2 = messageChannel.port2;
// 往 port1 發(fā)送消息
port2.postMessage({ action: 'refresh' });

需要注意的是 MessagePort 對(duì)象如果使用 addEventListener 監(jiān)聽(tīng) message 事件,就需要調(diào)用下 port.start() 方法,使用 onmessage 則可以不需要。

storage 事件

當(dāng) localStorage 或 sessionStorage 被修改時(shí),將觸發(fā) storage 事件,利用這個(gè)機(jī)制,我們也可以完成跨窗口通信。同時(shí)因?yàn)橛玫氖?nbsp;localStorage 或 sessionStorage 方式,所以頁(yè)面必須是同一域名下。

值得注意的是,sessionStorage 并不能滿足上面的業(yè)務(wù)需求,sessionStorage 要想觸發(fā) storage 事件,必須在同一窗口,也就是一般只在當(dāng)前頁(yè)和其加載的同域名 iframe 下使用。還有一點(diǎn)就是當(dāng)前頁(yè)的 setItem 不會(huì)觸發(fā)當(dāng)前頁(yè)的 storage 事件,只會(huì)觸發(fā)其他窗口的。

列表頁(yè)監(jiān)聽(tīng) storage 事件,判斷是否是對(duì)應(yīng) key 值發(fā)生變化:

window.addEventListener("storage", () => {
  console.log('發(fā)生變化的值:', event.key); 
  if (event.key === 'refresh') {
     // 刷新列表
  }
});

新增功能頁(yè)面使用 localStorage 的 setItem 來(lái)觸發(fā)列表的 storage 事件:

window.localStorage.setItem('fresh', Date.now())

SharedWorker

SharedWorker 是 Web Workers API 的一種擴(kuò)展,它允許在多個(gè)瀏覽器上下文中(例如多個(gè)頁(yè)面或多個(gè) iframe )共享一個(gè) Worker。ShareWorker 遵守同源策略,也就是必須在同一域名下使用 SharedWorker。

先寫個(gè) worker.js 腳本:

const ports = [];

onconnect = function (e) {
  const port = e.ports[0];
  ports.push(port);
  port.onmessage = function (e) {
    console.log("worker接收到的消息:", e.data);
    ports.forEach((p) => {
      p.postMessage(e.data);
    });
  };
};

列表頁(yè)創(chuàng)建 ShareWorker 實(shí)例,然后監(jiān)聽(tīng) message 事件:

const sharedWorker = new SharedWorker('./worker.js', 'test');
const port = sharedWorker.port;
port.onmessage = function (event) {
  console.log('接收:', event.data); // { action: 'refresh' }
};

新增功能頁(yè)面使用 postMessage 發(fā)送消息給 worker,worker 在發(fā)送給各個(gè)主線程:

const sharedWorker = new SharedWorker('./worker.js', 'test');
const port = sharedWorker.port;
port.postMessage({ action: 'refresh' });

這樣我們就完成了上述的業(yè)務(wù)需求。

總結(jié)

上述的各種方式都可以實(shí)現(xiàn)通知列表頁(yè)去做刷新動(dòng)作,不過(guò)更推薦使用 window.opener 或 BroadcastChannel 來(lái)實(shí)現(xiàn),這兩種方式相對(duì)使用簡(jiǎn)單并且很符合這個(gè)業(yè)務(wù)場(chǎng)景。

對(duì)于其他需要跨窗口通信的場(chǎng)景,可以根據(jù)各個(gè) API 的能力特點(diǎn)來(lái)選擇使用哪個(gè)。

責(zé)任編輯:武曉燕 來(lái)源: 栗子前端
相關(guān)推薦

2018-04-11 10:51:25

多線程進(jìn)程主線程

2022-04-07 18:49:56

項(xiàng)目場(chǎng)景數(shù)據(jù)庫(kù)

2019-01-17 10:58:52

JS異步編程前端

2009-04-17 22:25:16

多核四核CPU

2012-01-04 16:14:17

2025-05-06 00:00:05

MySQLES協(xié)同

2025-05-19 00:02:00

數(shù)據(jù)脫敏加密算法數(shù)據(jù)庫(kù)

2019-05-15 08:00:00

vue組件間通信前端

2019-12-03 12:16:36

物聯(lián)網(wǎng)ZigBee藍(lán)牙低功耗

2009-03-12 10:11:00

綜合布線規(guī)劃網(wǎng)絡(luò)布局

2022-05-24 10:43:02

延時(shí)消息分布式MQ

2013-12-06 14:57:24

瀏覽器

2019-10-12 01:10:09

物聯(lián)網(wǎng)無(wú)線技術(shù)IOT

2010-05-31 10:11:02

2025-03-17 08:07:11

2010-09-15 09:12:03

JavaScript瀏覽器兼容

2018-01-12 10:25:48

Nginx信號(hào)集master

2025-05-29 03:00:00

2009-02-11 09:46:00

ASON網(wǎng)絡(luò)演進(jìn)

2011-12-08 15:40:16

UC瀏覽器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 精久久久 | jlzzjlzz国产精品久久 | 日韩手机在线看片 | 国产情侣久久 | 久久久久国产一区二区三区 | 一本大道久久a久久精二百 国产成人免费在线 | 亚洲免费精品一区 | 亚洲国产日韩欧美 | 国产激情视频网站 | 免费观看一级视频 | 在线中文字幕国产 | 日韩欧美国产精品综合嫩v 一区中文字幕 | 久久久久久亚洲 | 国产精品呻吟久久av凹凸 | 视频一区二区国产 | 丝袜毛片 | 看a级黄色毛片 | 一区二区成人在线 | 亚洲欧美综合精品久久成人 | 视频一区在线 | 国产视频第一页 | 国产一区二区三区在线免费观看 | 亚洲精品自拍 | 国产一区二区精 | 成年网站在线观看 | 亚洲精品福利在线 | 天天精品综合 | 国产做爰 | 99视频在线免费观看 | 国产精品不卡一区 | 国产日韩欧美在线观看 | 在线观看视频一区 | 日日操视频 | 伊人伊人网 | 久久这里有精品 | 91精品国产欧美一区二区成人 | 久久免费大片 | 欧美黄色网| 99精品国产一区二区青青牛奶 | 91福利影院| 一区二区在线不卡 |