偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

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

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

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

業(yè)務(wù)場景

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

圖片圖片

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

解決方案

window.opener

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

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

圖片圖片

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

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

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

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

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

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

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

BroadcastChannel

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

列表頁創(chuàng)建一個 BroadcastChannel 實(shí)例來監(jiān)聽消息:

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

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

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

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

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

postMessage

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

列表頁打開新窗口,并監(jiān)聽 message 事件:

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

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

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

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

MessageChannel

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

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

圖片圖片

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

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

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

新增功能頁面使用 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 對象如果使用 addEventListener 監(jiān)聽 message 事件,就需要調(diào)用下 port.start() 方法,使用 onmessage 則可以不需要。

storage 事件

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

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

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

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

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

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

SharedWorker

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

先寫個 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);
    });
  };
};

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

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

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

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

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

總結(jié)

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

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

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

2018-04-11 10:51:25

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

2022-04-07 18:49:56

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

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ù)庫

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

延時消息分布式MQ

2013-12-06 14:57:24

瀏覽器

2019-10-12 01:10:09

物聯(lián)網(wǎng)無線技術(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信號集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ù)棧公眾號