摘要:剛來(lái)公司時(shí)做得第一個(gè)項(xiàng)目是跨部門合作,使用了來(lái)做通信,十分簡(jiǎn)單,代碼不長(zhǎng),這里分析一下間通信的實(shí)現(xiàn)方式源碼消息前綴建議使用自己的項(xiàng)目名避免多項(xiàng)目之間的沖突注意消息前綴應(yīng)使用字符串類型類消息對(duì)象往發(fā)送消息出于安全考慮發(fā)送消息會(huì)帶上前綴
剛來(lái)公司時(shí)做得第一個(gè)項(xiàng)目是跨部門合作,使用了MessengerJS來(lái)做通信,十分簡(jiǎn)單,MessengerJS代碼不長(zhǎng),這里分析一下iframe間通信的實(shí)現(xiàn)方式
源碼
/** * __ ___ * / |/ /___ _____ _____ ___ ____ ____ _ ___ _____ * / /|_/ // _ / ___// ___// _ / __ / __ `// _ / ___/ * / / / // __/(__ )(__ )/ __// / / // /_/ // __// / * /_/ /_/ \___//____//____/ \___//_/ /_/ \__, / \___//_/ * /____/ * * @description MessengerJS, a common cross-document communicate solution. * @author biqing kwok * @version 2.0 * @license release under MIT license */ window.Messenger = (function(){ // 消息前綴, 建議使用自己的項(xiàng)目名, 避免多項(xiàng)目之間的沖突 // !注意 消息前綴應(yīng)使用字符串類型 var prefix = "[PROJECT_NAME]", supportPostMessage = "postMessage" in window; // Target 類, 消息對(duì)象 function Target(target, name, prefix){ var errMsg = ""; if(arguments.length < 2){ errMsg = "target error - target and name are both required"; } else if (typeof target != "object"){ errMsg = "target error - target itself must be window object"; } else if (typeof name != "string"){ errMsg = "target error - target name must be string type"; } if(errMsg){ throw new Error(errMsg); } this.target = target; this.name = name; this.prefix = prefix; } // 往 target 發(fā)送消息, 出于安全考慮, 發(fā)送消息會(huì)帶上前綴 if ( supportPostMessage ){ // IE8+ 以及現(xiàn)代瀏覽器支持 Target.prototype.send = function(msg){ this.target.postMessage(this.prefix + "|" + this.name + "__Messenger__" + msg, "*"); }; } else { // 兼容IE 6/7 Target.prototype.send = function(msg){ var targetFunc = window.navigator[this.prefix + this.name]; if ( typeof targetFunc == "function" ) { targetFunc(this.prefix + msg, window); } else { throw new Error("target callback function is not defined"); } }; } // 信使類 // 創(chuàng)建Messenger實(shí)例時(shí)指定, 必須指定Messenger的名字, (可選)指定項(xiàng)目名, 以避免Mashup類應(yīng)用中的沖突 // !注意: 父子頁(yè)面中projectName必須保持一致, 否則無(wú)法匹配 function Messenger(messengerName, projectName){ this.targets = {}; this.name = messengerName; this.listenFunc = []; this.prefix = projectName || prefix; this.initListen(); } // 添加一個(gè)消息對(duì)象 Messenger.prototype.addTarget = function(target, name){ var targetObj = new Target(target, name, this.prefix); this.targets[name] = targetObj; }; // 初始化消息監(jiān)聽 Messenger.prototype.initListen = function(){ var self = this; var generalCallback = function(msg){ if(typeof msg == "object" && msg.data){ msg = msg.data; } var msgPairs = msg.split("__Messenger__"); var msg = msgPairs[1]; var pairs = msgPairs[0].split("|"); var prefix = pairs[0]; var name = pairs[1]; for(var i = 0; i < self.listenFunc.length; i++){ if (prefix + name === self.prefix + self.name) { self.listenFunc[i](msg); } } }; if ( supportPostMessage ){ if ( "addEventListener" in document ) { window.addEventListener("message", generalCallback, false); } else if ( "attachEvent" in document ) { window.attachEvent("onmessage", generalCallback); } } else { // 兼容IE 6/7 window.navigator[this.prefix + this.name] = generalCallback; } }; // 監(jiān)聽消息 Messenger.prototype.listen = function(callback){ var i = 0; var len = this.listenFunc.length; var cbIsExist = false; for (; i < len; i++) { if (this.listenFunc[i] == callback) { cbIsExist = true; break; } } if (!cbIsExist) { this.listenFunc.push(callback); } }; // 注銷監(jiān)聽 Messenger.prototype.clear = function(){ this.listenFunc = []; }; // 廣播消息 Messenger.prototype.send = function(msg){ var targets = this.targets, target; for(target in targets){ if(targets.hasOwnProperty(target)){ targets[target].send(msg); } } }; return Messenger; })();
下面主要分析代碼結(jié)構(gòu)
supportPostMessage變量用來(lái)檢測(cè)當(dāng)前瀏覽器是否支持postMessage
postMessage是HTML5引入的通信API,它可以避開同源策略的限制,實(shí)現(xiàn)安全的跨域通信
向外界窗口發(fā)送消息
otherWindow.postMessage(message, targetOrigin);
otherWindow: 指目標(biāo)窗口,也就是給哪個(gè)window發(fā)消息,是 window.frames 屬性的成員或者由 window.open 方法創(chuàng)建的窗口
message: 是要發(fā)送的消息,類型為 String、Object (IE8、9 不支持),一般使用json數(shù)據(jù)
targetOrigin: 是限定消息接收范圍,協(xié)議+主機(jī)+端口號(hào)[+URL],URL會(huì)被忽略,所以可以不寫,不限制請(qǐng)使用 ‘*’
接受信息的message事件
var onmessage = function (event) { var data = event.data; var origin = event.origin; //do someing }; if (typeof window.addEventListener != "undefined") { window.addEventListener("message", onmessage, false); } else if (typeof window.attachEvent != "undefined") { //for ie window.attachEvent("onmessage", onmessage); }
注意:ie6/7不支持postMessage,因此在ie6/7中跨域通信通常使用window.name
window.name的美妙之處:name 值在不同的頁(yè)面(甚至不同域名)加載后依舊存在,并且可以支持非常長(zhǎng)的 name 值(2MB)
window.navigator有與window.name類似的特性,而且可以保存回調(diào)方法
MessengerJS的實(shí)現(xiàn)思路是高級(jí)瀏覽器使用postMessage,不支持postMessage的使用window.navigator來(lái)保存回調(diào)方法
Target類消息類,發(fā)送執(zhí)行者
function Target(target, name){ this.target = target; this.name = name; } Target.prototype.send = function(msg){ // 發(fā)送消息 };Messenger類
信使類,創(chuàng)建多個(gè)消息對(duì)象,注冊(cè)多個(gè)監(jiān)聽事件,每一個(gè)消息對(duì)象的廣播消息會(huì)被這個(gè)信使類下面的所有監(jiān)聽事件接收到
function Messenger(messengerName, projectName){ this.targets = {}; this.name = messengerName; this.listenFunc = []; this.initListen(); } // 添加一個(gè)消息對(duì)象 Messenger.prototype.addTarget = function(target, name){}; // 初始化消息監(jiān)聽 Messenger.prototype.initListen = function(){}; // 監(jiān)聽消息 Messenger.prototype.listen = function(callback){}; // 注銷監(jiān)聽 Messenger.prototype.clear = function(){}; // 廣播消息 Messenger.prototype.send = function(msg){};
實(shí)現(xiàn)邏輯是:
initListen方法初始化,將generalCallback回調(diào)方法注冊(cè)到message監(jiān)聽中
addTarget將消息對(duì)象添加到targets對(duì)象中
listen方法將監(jiān)聽方法添加到listenFunc數(shù)組中
send方法執(zhí)行每一個(gè)target對(duì)象的send方法
target對(duì)象的send方法執(zhí)行,觸發(fā)了message監(jiān)聽,觸發(fā)了generalCallback的執(zhí)行,從而執(zhí)行了listenFunc數(shù)組中的方法
在postMessage的注冊(cè)回調(diào)方法里加了一個(gè)回調(diào)方法組listenFunc
在postMessage的監(jiān)聽觸發(fā)方法外加了一層集體觸發(fā)對(duì)象targets
從而達(dá)到了廣播的效果
postMessage本身可以實(shí)現(xiàn)廣播的效果,但是MessengerJS為了兼容,限制了postMessage的能力,自行實(shí)現(xiàn)了廣播
使用場(chǎng)景MessengerJS來(lái)做iframe通信解決的最常見的問題是,在主頁(yè)面為iframe留足高度
parent頁(yè)面
var messenger = new Messenger("parent"); var iframe = document.getElementById("iframepage"); messenger.addTarget(iframe.contentWindow, "iframe"); messenger.listen(function (msg) { var result = parseInt(msg, 10) + 20; if (result < mainWindowHeight) { result = mainWindowHeight; } $("#iframepage").height(result); });
iframe頁(yè)面
// iframe跨域傳數(shù)據(jù) var messenger = new Messenger("iframe"); messenger.addTarget(window.parent, "parent"); // 跨域傳main 高度 var height = $(".main").height(); messenger.targets["parent"].send(height); messenger.listen(function (msg) { });總結(jié)
postMessage是一個(gè)用于安全的使用跨源通信的方法,幫助web開發(fā)回歸正軌
MessengerJS實(shí)現(xiàn)效果很好,即便做頻繁的交互,也不會(huì)有明顯的卡頓,不過時(shí)代在進(jìn)步,以后可能會(huì)很少用到這樣的兼容了
官方博文看這里:MessengerJS
本文轉(zhuǎn)載自筆者個(gè)人博客:Gaoxuefeng"s Blog
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/79403.html
摘要:消息前綴建議使用自己的項(xiàng)目名避免多項(xiàng)目之間的沖突類消息對(duì)象往發(fā)送消息出于安全考慮發(fā)送消息會(huì)帶上前綴以及現(xiàn)代瀏覽器支持兼容信使類添加一個(gè)消息對(duì)象初始化消息監(jiān)聽剝離消息前綴兼容監(jiān)聽消息廣播消息用法頁(yè)面頁(yè)面跨域傳數(shù)據(jù)跨域傳高度 messengerjs /** * __ ___ *...
摘要:小結(jié)小結(jié)本文主要是介紹了一個(gè)方案及其使用方法,來(lái)解決父窗體與子窗體的通信問題。同時(shí)提供了一個(gè)完整的實(shí)例,可以實(shí)現(xiàn)子窗體向父窗體傳遞消息,父窗體通過監(jiān)聽消息事件,來(lái)獲取子窗體消息的目的。歡迎大家前往騰訊云+社區(qū),獲取更多騰訊海量技術(shù)實(shí)踐干貨哦~ 本文由前端林子發(fā)表于云+社區(qū)專欄 本文主要會(huì)介紹如何基于MessengerJS,實(shí)現(xiàn)iframe父窗體與子窗體間的通信,傳遞數(shù)據(jù)信息。同時(shí)本文會(huì)提...
摘要:開發(fā)者需要在中設(shè)置屬性為跨域是的簡(jiǎn)稱這是一種利用瀏覽器漏洞解決跨域的辦法腳本元素可以不受瀏覽器同源策略的限制。 什么是瀏覽器同源策略? 同源是指,域名,協(xié)議,端口號(hào)均相同,如圖: showImg(https://segmentfault.com/img/bV9rAO?w=1088&h=394); 注意:localhost和127.0.0.1雖然都指向本機(jī),但也是跨域. 瀏覽器同源策略(...
摘要:說(shuō)到跨域,就不得不提起瀏覽器的同源策略。跨域無(wú)刷新提交跨域的方法有很多,像等等,由于項(xiàng)目中用到了進(jìn)行跨域,所以本文主要總結(jié)一下如何利用進(jìn)行無(wú)刷新提交。為了拿到返回回來(lái)的,需要使用一個(gè)函數(shù),函數(shù)名后臺(tái)已經(jīng)告知。 以前在面試的時(shí)候經(jīng)常遇到問關(guān)于跨域的事兒,所以自己對(duì)跨域有一定的概念性了解,知道什么是跨域以及解決跨域的方法,但是具體實(shí)際從來(lái)沒有操作過,直到最近在公司項(xiàng)目中,遇到了一個(gè)需要使i...
閱讀 1402·2021-11-22 09:34
閱讀 1378·2021-09-22 14:57
閱讀 3400·2021-09-10 10:50
閱讀 1372·2019-08-30 15:54
閱讀 3690·2019-08-29 17:02
閱讀 3472·2019-08-29 12:54
閱讀 2611·2019-08-27 10:57
閱讀 3316·2019-08-26 12:24