1. 程式人生 > >2個瀏覽器視窗間通訊

2個瀏覽器視窗間通訊

1.localStorage

一個視窗更新localStorage,另一個視窗監聽window物件的“storage”事件,來實現通訊

注:兩個頁面要同源

//本視窗的設定程式碼
localStorage.setItem('aaa', (Math.random() * 10).toString())
//其他視窗監聽storage事件
window.addEventListener("storage", function(e){
   console.log(e)
   console.log(e.newValue)  
})

2. WebSocket

所有的WebSocket都監聽同一個伺服器地址,利用send傳送訊息,利用onmessage獲取訊息的變化,不僅能多視窗,還能跨瀏覽器,相容性最佳,只是需要消耗點伺服器資源。

var ws = new WebSocket("ws://localhost:3000/")
ws.onopen = function(event){
  //或者把此方法註冊到其他事件中,即可與其他伺服器通訊
  ws.send({now: Date.now()});  //通過伺服器中轉訊息    
};
ws.onmessage = function(event) {
  //消費訊息
  console.log(event.data);    
}

3. postMessage

藉助iframe 或 window.open

回顧一下API

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

1) otherWindow

其他視窗的一個引用,比如iframe的contentWindow屬性、執行window.open返回的視窗物件、或者是命名過或數值索引的window.frames.

2) message

將要傳送到其他window的資料。它將會被結構化克隆演算法序列化。這意味著你可以不受什麼限制的將資料物件安全的傳送給目標視窗而無需自己序列化。

3) targetOrigin

通過視窗的origin屬性來指定哪些視窗能接收到訊息事件,其值可以是字串“”(表示無限制)或者一個URI。在傳送訊息的時候,如果目標視窗的協議、主機地址或者埠這三者的任意一項不匹配targetOrigin提供的值,那麼訊息就不會被髮送;只有三者完全匹配,訊息才會被髮送。這個機制用來控制訊息可以傳送到哪些視窗;例如:當用postMessage傳送密碼時,這個引數就顯得尤為重要,必須保證它的值與這條包含密碼的資訊的預期接受者的origin屬性完全一致,來防止密碼被惡意的第三方截獲。如果你明確的知道訊息應該傳送到哪個視窗,那麼請始終提供一個確切值的targetOrigin,而不是,不提供確切的目標將導致資料洩露到任何對資料感興趣的惡意站點。

4) transfer可選

是一串和message同時傳遞的Transferable物件。這些物件的所有權將被轉移給訊息的接收方,而傳送一方將不再保有所有權。

/*
 * A視窗的域名是<http://example.com:8080>,以下是A視窗的script標籤下的程式碼:
 *
 */

var popup = window.open(...popup details...);

//如果彈出框沒有被阻止且載入完成

//這行語句沒有傳送訊息出去,即使假設當前頁面沒有改變location(因為targetOrigin設定不對)
popup.postMessage("The user is 'bob' and the password is 'secret'", "https://secure.example.net");

//假設當前頁面沒有改變location,這條語句會成功新增message到傳送佇列中去(targetOrigin設定對了)
popup.postMessage("hello there!", "http://example.org");

function receiveMessage(event) {
    //我們能相信資訊的傳送者嗎?(也許這個傳送者和我們最初開啟的不是同一個頁面)
  if(event.origin !== "http://example.org") return;

//event.source 是我們通過window.open開啟的彈出頁面 popup
//event.data 是 popup傳送給當前頁面的訊息 "hi there yourself! the secret response is: rheeeeeet!"
}

window.addEventListener("message", receiceMessage, false);
/*
 * 彈出頁 popup 域名是<http://example.org>,以下是script標籤中的程式碼:
 *
 */
function receiveMessage(event) {
   //我們能信任資訊來源嗎?
  if (event.origin !== "http://example.com:8080") return;

   //event.source 就當前彈出頁的來源頁面
   //event.data 是 "hello there!"

   //假設你已經驗證了所收到資訊的origin(任何時候你都應該這樣做),
//一個很方便的方式就是把event.source作為回信的物件,並且把event.origin作為targetOrigin
  event.source.postMessage("hi there yourself! the secert response " + "is: rheeeet!", event.origin); } window.addEventListener("message", receiveMessage, false);

4. cookie + setInterval【差】

在頁面A設定一個使用 setInterval定時器不斷重新整理,檢查Cookies的值是否發生變化,如果變化就進行重新整理的操作。

由於Cookies是在同域可讀的,所以在頁面B稽核的時候改變Cookies的值,頁面A自然是可以拿到的。

這樣做確實可以實現想要的功能,但是這樣的方法相當浪費資源。雖然在這個效能過盛的時代,浪費不浪費感覺不出來,但是這種方案,確實不夠優雅。

5. SharedWorker

HTML5中的Web Worker 可以分為2種不同的執行緒型別,一個是專用執行緒 Dedicated Worker,一個是共享執行緒 Shared Worker。

1) Dedicated Worker 直接使用 new Worker() 即可建立,這種webworker是當前頁面專有的。

2) SharedWorker 可以被多個window、標籤頁、iframe共同使用,但必須保證這些標籤頁都是同源的(相同的協議、主機和埠號)

6.直接引用

其實就是直接獲取對方DOM,適用於2個頁面在同一域;可以傳遞物件資料(物件資料使用 instanceof 做型別判斷時有坑);參考window.open;

例:

//父頁面獲取iframe
document.getElementById("iframe的id").contentWindow.document

//子iframe獲取父頁面
window.parent.document

7. window.name

瀏覽器視窗有window.name屬性。這個屬性的最大特點是,無論是否同源,只要在同一窗口裡,前一個網頁設定了這個屬性,後一個網頁可以讀取它。

父視窗先開啟一個子視窗,載入一個不同源的網頁,該網頁將資訊寫入window.name屬性

window.name = data

接著,子視窗跳回一個與主視窗同域的網址

window.location.href = "http://parent.url.com/xxx.html";

然後,主視窗就可以讀取子視窗的window.name了

var data = document.getElementById("iframe的id").contentWindow.name;

這種方法的優點是,window.name容量最大,可以放置非常長的字串;缺點是必須監聽子視窗window.name屬性的變化,影響網頁效能。