最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

前端實現(xiàn)跨標簽頁通信的方案總結(jié)

 更新時間:2025年11月20日 09:00:44   作者:!win !  
這篇文章主要為大家詳細介紹了前端實現(xiàn)跨標簽頁通信的相關(guān)方案,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以跟隨小編一起學習一下

前情

平時開發(fā)很少有接觸到有什么需求需要實現(xiàn)跨標簽頁通信,但最近因為一些變故,不得不重新開始找工作了,其中就有面試官問到一道題,跨標簽頁怎么實現(xiàn)數(shù)據(jù)通信,我當時只答出二種,面試完后特意重新查資料,因此有些文章

localStorage / sessionStorage

利用localStorage的存儲事件實現(xiàn)通信,當一個標簽頁修改localStorage時,其他同源標簽頁會觸發(fā)storage事件

關(guān)鍵代碼如下:

標簽頁1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>page0-localStorage</title>
</head>
<body>
  <button id="setCacheBtn">設(shè)置本地緩存</button>
  <script>
    document.getElementById('setCacheBtn').addEventListener('click', () => {
      localStorage.setItem('message', JSON.stringify({
        type: 'greeting',
        // 這里為了保證通信每次生效,每次都設(shè)置不同的值
        content: 'Hello from page0.html' + Date.now()
      }));
    });
  </script>
</body>
</html>

標簽頁2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>page1-localStorage</title>
</head>
<body>
  <script>
    window.addEventListener('storage', (e) => {
      if (e.key === 'message') {
        const data = JSON.parse(e.newValue);
        console.log('Received:page1.html', data);
      }
    });
  </script>
</body>
</html>

動圖演示:

提醒:

  • 同源標簽才有效
  • 設(shè)置不同的本地存儲值才有效,如果設(shè)置的是同一個緩存值是不會生效的
  • 兼容性非常nice,可以大膽使用了,國內(nèi)一些瀏覽器從can i use查不到,但兼容性是沒啥問題的
  • sessionStorage僅在同一標簽頁的不同 iframe 間有效,不適用于不同標簽頁

BroadcastChannel

專門用于同源標簽頁通信的 API,創(chuàng)建一個頻道后,所有加入該頻道的頁面都能收到消息

關(guān)鍵代碼如下:

標簽頁1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>BroadcastChannel0</title>
</head>
<body>
  <h1>BroadcastChannel0</h1>
  <button id="communication">BroadcastChannel0.html 發(fā)送消息</button>
  <script>
    // 所有頁面都創(chuàng)建相同名稱的頻道
    const channel = new BroadcastChannel('my_channel');

    // 發(fā)送消息
    document.getElementById('communication').addEventListener('click', () => {
      channel.postMessage({ type: 'update', data: 'new content from BroadcastChannel0.html' });
    });
  </script>
</body>
</html>

標簽頁2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>BroadcastChannel1</title>
</head>
<body>
  <h1>BroadcastChannel1</h1>
  <script>
    // 所有頁面都創(chuàng)建相同名稱的頻道
    const channel = new BroadcastChannel('my_channel');

    // 接收消息
    channel.onmessage = (e) => {
      console.log('Received:BroadcastChannel1.html', e.data);
    };
  </script>
</body>
</html>

演示動圖如下:

提醒:

  • 要通信的標簽記得都初始化BroadcastChannel,一定記得使用相同的名稱
  • 查詢來看除IE外可以大但使用了

SharedWorker

共享工作線程可以在多個標簽頁之間共享數(shù)據(jù)和邏輯,通過postMessage通信

關(guān)鍵代碼如下:

標簽頁1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SharedWorker0</title>
</head>
<body>
  <h1>SharedWorker0</h1>
  <button id="communication">SharedWorker0.html 發(fā)送消息</button>
  <script>
    // 主線程
    const worker = new SharedWorker('sw.js');

    // 發(fā)送消息
    document.getElementById('communication').addEventListener('click', () => {
      worker.port.postMessage('Hello from Tab:SharedWorker0.html');
    });
  </script>
</body>
</html>

標簽頁2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SharedWorker1</title>
</head>
<body>
  <h1>SharedWorker1</h1>
  <script>
    // 主線程
    const worker = new SharedWorker('sw.js');

    // 接收消息
    worker.port.onmessage = (e) => {
      console.log('Received:SharedWorker1.html', e.data);
    };
  </script>
</body>
</html>

sw.js關(guān)鍵代碼:

const connections = [];

self.onconnect = (e) => {
  const port = e.ports[0];
  connections.push(port);
  
  port.onmessage = (e) => {
    // 廣播給所有連接的頁面
    connections.forEach(p => p.postMessage(e.data));
  };
};

動圖演示:

提醒:

  • 同源標簽才有效
  • 不同頁面創(chuàng)建 SharedWorker 時,若指定的腳本路徑不同(即使內(nèi)容相同),會創(chuàng)建不同的 worker 實例
  • 頁面與 SharedWorker 之間通過 MessagePort 通信,需通過 port.postMessage() 發(fā)送消息,通過 port.onmessage 接收消息
  • SharedWorker 無法訪問 DOM、window 對象或頁面的全局變量,僅能使用 JavaScript 核心 API 和部分 Web API(如 fetch、WebSocket
  • 兼容性一般,安卓webview全系不兼容

Service Worker

專門用于同源標簽頁通信的 API,創(chuàng)建一個頻道后,所有加入該頻道的頁面都能收到消息

關(guān)鍵代碼如下:

標簽頁1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ServiceWorker0</title>
</head>
<body>
  <h1>ServiceWorker0</h1>
  <button id="sendBtn">發(fā)送消息</button>
  <script>
    // 注冊ServiceWorker
    let swReg;
    navigator.serviceWorker.register('ServiceWorker.js')
      .then(reg => {
        swReg = reg;
        console.log('SW注冊成功');
      });
    
    // 發(fā)送消息
    document.getElementById('sendBtn').addEventListener('click', () => {
      if (swReg && swReg.active) {
        swReg.active.postMessage('來自頁面0的消息');
      }
    });
  </script>
</body>
</html>

標簽頁2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ServiceWorker1</title>
</head>
<body>
  <h1>ServiceWorker1</h1>
  <script>
    // 注冊ServiceWorker
    navigator.serviceWorker.register('ServiceWorker.js')
      .then(() => console.log('SW注冊成功'));
    
    // 接收消息
    navigator.serviceWorker.addEventListener('message', (e) => {
      console.log('---- Received:ServiceWorker1.html ----:',  e.data);
    });
  </script>
</body>
</html>

ServiceWorker.js關(guān)鍵代碼

// 快速激活
self.addEventListener('install', e => e.waitUntil(self.skipWaiting()));
self.addEventListener('activate', e => e.waitUntil(self.clients.claim()));

// 消息轉(zhuǎn)發(fā)
self.addEventListener('message', e => {
  self.clients.matchAll().then(clients => {
    clients.forEach(client => {
      if (client.id !== e.source.id) {
        client.postMessage(e.data);
      }
    });
  });
});

演示動圖如下:

提醒:

Service Worker 要求頁面必須在 HTTPS 環(huán)境 下運行(localhost 除外,方便本地開發(fā)),這是出于安全考慮,防止中間人攻擊篡改 Service Worker 腳本

Service Worker 有嚴格的生命周期(安裝、激活、空閑、銷毀),一旦注冊成功會長期運行在后臺,更新 Service Worker 需滿足兩個條件:

腳本 URL 不變但內(nèi)容有差異

需在 install 事件中調(diào)用 self.skipWaiting(),并在 activate 事件中調(diào)用 self.clients.claim() 讓新 Worker 立即生效

Service Worker 的作用域由注冊路徑?jīng)Q定,默認只能控制其所在路徑及子路徑下的頁面,例如:/sw.js 可控制全站,/js/sw.js 默認只能控制 /js/ 路徑下的頁面,可通過 scope 參數(shù)指定作用域,但不能超出注冊文件所在路徑的范圍

可在瀏覽器開發(fā)者工具的 Application > Service Workers 面板進行調(diào)試,

  • 查看當前運行的 Service Worker 狀態(tài)
  • 強制更新、停止或注銷 Worker
  • 模擬離線環(huán)境

主流瀏覽器都支持,使用的時候可以通過Is service worker ready?,測試兼容性

window.open + window.opener

如果標簽頁是通過window.open打開的,可以直接通過opener屬性通信

父窗口,打開子窗口的頁面關(guān)鍵代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>parent</title>
</head>
<body>
  <h1>window.open parent</h1>
  <button id="openBtn">打開子窗口</button>
  <button id="sendBtn">發(fā)送消息</button>
  <div id="messageDisplay"></div>
  <script>
    let childWindow = null;
    let messageHandler = null;
    
    // 打開子窗口
    document.getElementById('openBtn').addEventListener('click', () => {
      // 如果已有窗口,先關(guān)閉
      if (childWindow && !childWindow.closed) {
        childWindow.close();
      }
      childWindow = window.open('./children.html', 'childWindow');
    });

    // 發(fā)送消息
    document.getElementById('sendBtn').addEventListener('click', () => {
      if (childWindow && !childWindow.closed) {
	      // window.location.origin限制接收域名
        childWindow.postMessage('Hello child', window.location.origin);
      } else {
        alert('請先打開子窗口');
      }
    });
    
    // 接收子窗口的消息
    messageHandler = (e) => {
      if (e.origin === window.location.origin && e.source !== window) {
        document.getElementById('messageDisplay').textContent = '收到消息: ' + e.data;
        console.log('父頁面收到消息:', e.data);
      }
    };
    
    window.addEventListener('message', messageHandler);
  </script>
</body>
</html>

通過window.open打開的子頁面關(guān)鍵代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>children</title>
</head>
<body>
  <h1>子窗口</h1>
  <button id="replyBtn">回復(fù)父窗口</button>
  <div id="messageDisplay"></div>
  
  <script>
    let messageHandler = null;
    
    // 只在頁面加載完成后設(shè)置消息監(jiān)聽
    window.onload = function() {
      // 接收父頁面消息
      messageHandler = (e) => {
        if (e.origin === window.location.origin && e.source !== window) {
          console.log('子頁面收到消息:', e.data);
          
          // 顯示收到的消息
          document.getElementById('messageDisplay').textContent = '收到消息: ' + e.data;
          
          window.opener.postMessage('子窗口已收到消息', e.origin);
        }
      };
      
      window.addEventListener('message', messageHandler);
    };
    
    // 手動回復(fù)按鈕
    document.getElementById('replyBtn').addEventListener('click', () => {
      if (window.opener) {
        window.opener.postMessage('來自子窗口的回復(fù)', window.location.origin);
      }
    });
  </script>
</body>
</html>

提醒:

  • 允許跨域通信,但必須由開發(fā)者顯式指定信任的源,避免惡意網(wǎng)站濫用
  • 在事件監(jiān)聽的時候記得判斷e.source,避免自己發(fā)送的事件自己接收了
  • 若子窗口被關(guān)閉,父窗口中對它的引用(如 childWindow)會變成無效對象,調(diào)用其方法會報錯
  • window.open使用會有一些限制,最好是在事件中使用,有的瀏覽器還會有權(quán)限提示,需要用戶同意才行,若 window.open 被瀏覽器攔截(非用戶主動觸發(fā)),會返回 null,導致后續(xù)通信失敗

總結(jié)

面試官有提到Service Worker也可以,我面試完后的查詢資料嘗試了這些方法,都挺順利的,就是Service Worker折騰了一會才跑通,使用起來相比前面的一些方式,它稍微復(fù)雜一些,我覺得用于消息通信只是它的冰山一角,它有一個主要功能就是用來解決一些耗性能的計算密集任務(wù)

個人技術(shù)有限,如果你有更好的跨標簽頁通信方式,期待你的分享,你工作中有遇到這種跨標簽頁通信的需求么,如果有你用的是哪一種了,期待你的留言

以上就是前端實現(xiàn)跨標簽頁通信的方案總結(jié)的詳細內(nèi)容,更多關(guān)于前端跨標簽頁通信的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JS中artdialog彈出框控件之提交表單思路詳解

    JS中artdialog彈出框控件之提交表單思路詳解

    artDialog是一個基于javascript編寫的對話框組件,它擁有精致的界面與友好的接口。本文給大家介紹JS中artdialog彈出框控件之提交表單思路詳解,對本文感興趣的朋友一起學習吧
    2016-04-04
  • JavaScript實現(xiàn)網(wǎng)頁電子時鐘

    JavaScript實現(xiàn)網(wǎng)頁電子時鐘

    這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)網(wǎng)頁電子時鐘,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 前端頁面文件拖拽上傳模塊js代碼示例

    前端頁面文件拖拽上傳模塊js代碼示例

    這篇文章主要為大家詳細介紹了前端頁面文件拖拽上傳模塊js代碼示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 微信小程序?qū)崿F(xiàn)禁止分享代碼實例

    微信小程序?qū)崿F(xiàn)禁止分享代碼實例

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)禁止分享代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • 小程序開發(fā)指南之全局配置

    小程序開發(fā)指南之全局配置

    這篇文章主要給大家介紹了關(guān)于小程序開發(fā)指南之全局配置的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2022-01-01
  • JavaScript實現(xiàn)審核流程狀態(tài)的動態(tài)顯示進度條

    JavaScript實現(xiàn)審核流程狀態(tài)的動態(tài)顯示進度條

    對于有很多流程的東西,我們希望能夠根據(jù)不同的階段,用流程條對應(yīng)地進行顯示,非常直觀,給用戶帶來極好的用戶體驗,下面小編給大家分享JavaScript實現(xiàn)審核流程狀態(tài)的動態(tài)顯示進度條功能,需要的的朋友參考下
    2017-03-03
  • javascript對象的相關(guān)操作小結(jié)

    javascript對象的相關(guān)操作小結(jié)

    下面小編就為大家?guī)硪黄猨avascript對象的相關(guān)操作小結(jié)。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-05-05
  • JS中with的替代方法與String中的正則方法詳解

    JS中with的替代方法與String中的正則方法詳解

    最近這幾天在升級自己的MVVM 框架,遇到很多小問題,所以想著就在這里統(tǒng)一解決了。文中主要介紹了關(guān)于Javascript中with的替代方法與String中的正則方法,有需要的朋友們可以參考借鑒,下面來一起看看吧。
    2016-12-12
  • 小程序上傳文件至云存儲的實現(xiàn)

    小程序上傳文件至云存儲的實現(xiàn)

    在小程序云開發(fā)中,要實現(xiàn)上傳文件至云存儲,有兩種方案:云函數(shù)和HTTP?API,本文主要講講如何使用HTTP?API實現(xiàn)小程序外上傳文件至云存儲,感興趣的可以了解一下
    2022-01-01
  • js實現(xiàn)可控制左右方向的無縫滾動效果

    js實現(xiàn)可控制左右方向的無縫滾動效果

    這篇文章主要介紹了js實現(xiàn)可控制左右方向的無縫滾動效果,頁面中添加了兩個按鈕,控制圖片滾動的方向,感興趣的小伙伴們可以參考一下
    2016-05-05

最新評論

陇西县| 昭觉县| 屏山县| 潼南县| 图木舒克市| 德阳市| 七台河市| 西充县| 三河市| 丰镇市| 陈巴尔虎旗| 托里县| 奇台县| 沐川县| 邓州市| 南雄市| 大埔区| 娱乐| 涿州市| 瑞金市| 木里| 马公市| 罗甸县| 固始县| 凭祥市| 三穗县| 敦化市| 怀柔区| 青河县| 临朐县| 孝义市| 德阳市| 盐城市| 喀什市| 丹巴县| 隆昌县| 靖江市| 华容县| 游戏| 罗定市| 将乐县|