利用HTML5 LocalStorage實現跨頁面通信channel


引言

隨着Web技術的發展,涌出了越來越多的復雜的應用。諸多Web應用逐漸向增強用戶體驗方向發展。在諸如付款、在線聊天等場景中,有時需要多頁面進行數據通信。以前的實現方法有cookie、服務器中轉、Flash插件等方法,而HTML5提供了新的LocalStorage API,能夠更為便捷的實現跨頁面通信,且相比以前的技術有容量大、效率高、無需插件等優點。

“What”能實現什么

LocalStorage API被IE8+及Firefox、Chrome、Safari等主流瀏覽器所支持。利用localStorage能夠實現數據的存儲,而通過監控數據的寫入,頁面可以獲得其它頁面想要傳達的信息。

在“在線聊天”功能中,服務器與客戶端的數據通信需要占用大量的帶寬和服務器計算時間,而如果一個瀏覽器同時打開了多個窗口更是雪上加霜。作為一個綠色環保的程序員,相對於堆服務器,我們應該立足於解決帶寬與計算量的浪費,而通過跨頁面的協同合作,我們可以實現多個頁面之間可以共享一條數據通道,同時節省了服務器和客戶端的消耗。

其它的諸如微博等應用的“換膚”功能,如果能夠實現打開的多個窗口同時更換皮膚,勢必能夠提高用戶的體驗。

“Where”用在何處

上面已經提及了兩處應用場景,實際上任何Web應用都應該考慮多窗口的情形。用於在窗口之間切換時,如何實現無障礙的應用體驗?產品經理總是抱怨打開了多個窗口怎么就不能實現聯動?在一個窗口登錄了其它窗口怎么就非得刷新才能使用一些功能?這些統統可以通過跨頁面通信解決。

“How”怎么實現

HTML5 LocalStorage API中包含了"storage"事件。通過監聽window對象的storage事件,可以在其它頁面窗口調用localStorage的存儲方法時,得到通知。為了進行跨頁面通信事件與普通存儲事件的區分,我封裝了一個channel庫,可以通過命名空間進行數據的監聽。

channel庫代碼如下:

 1 /**
 2  * Channel.js: Browser support for multipage communication
 3  * 
 4  * @author Kyriosli
 5  */
 6 var channel = function(entry) {
 7     var listeners = {};
 8 
 9     if (/MSIE 8/.test(navigator.userAgent)) {
10         window.attachEvent('storage', function() {
11             // TODO: ie8 support
12         });
13     } else {
14         window.addEventListener('storage', function(e) {
15             if (e.newValue !== null && /^channel\.(.+)/.test(e.key)) {
16                 broadcast(RegExp.$1, e.newValue);
17             }
18         });
19     }
20 
21     function broadcast(channelName, str) {
22         if (channelName in listeners) {
23             var value = JSON.parse(str);
24             for ( var i = 0, arr = listeners[channelName], L = arr.length; i < L; i++) {
25                 try {
26                     arr[i](value);
27                 } catch (e) {
28                     console.error(e.stack);
29                 }
30             }
31         }
32     }
33 
34     return {
35         /**
36          * 發布數據到其它頁面
37          * 
38          * @param name
39          *            命名空間名稱
40          * @param value
41          *            要發布的數據
42          * @returns this
43          */
44         post : function(name, value) {
45             entry["channel." + name] = JSON.stringify(value);
46             setTimeout(function() {
47                 entry.removeItem("channel." + name);
48             }, 0);
49             return this;
50         },
51         /**
52          * 注冊監聽器
53          * 
54          * @param name
55          *            要監聽的命名空間
56          * @param callback
57          *            回調函數
58          * @returns this
59          */
60         on : function(name, callback) {
61             if (name in listeners) {
62                 listeners[name].push(callback);
63             } else {
64                 listeners[name] = [ callback ];
65             }
66             return this;
67         },
68         /**
69          * 取消監聽器
70          * 
71          * @param name
72          *            要取消監聽的命名空間
73          * @param callback
74          *            回調函數,如果為空,則取消所有監聽函數
75          * @returns this
76          */
77         off : function(name, callback) {
78             var arr = listeners[name];
79             if (arr) {
80                 if (!callback) {
81                     delete listeners[name];
82                 } else {
83                     var i = arr.length;
84                     while (i--) {
85                         if (arr[i] === callback) {
86                             arr.splice(i, 1);
87                         }
88                     }
89                 }
90             }
91             return this;
92         }
93     };
94 }(localStorage);

channel有3個函數:post,on,off。當窗口A調用了on函數,窗口B調用post函數時,窗口A就會收到事件。如:

// 窗口A
channel.on('abcde', function(data) {
    console.log(data);
});

// 窗口B
channel.post('abcde', "Hello world");

那么窗口A將輸出'Hello world'。

其它

IE8/9的兼容

IE8/9的storage事件與主流瀏覽器有所不同,主要有兩個地方:

  1. IE8/9的storage事件不攜帶key和newValue等屬性
  2. IE8/9的storage事件觸發在localStorage的值真正改變之前

所以要支持IE8/9,必須在事件觸發后,設置超時,並掃描檢測所有localStorage中存儲的key,手動檢測其值是否發生改變。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM