diff --git a/README.md b/README.md index ac845b5..97c12e3 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,29 @@ Since modern browsers have native cross-document communication method(the PostMe messenger.send(msg); 6. 现在看到iframe收到消息的alert提示了吗? - + ## Demo ## http://biqing.github.io/labs/messenger/parent.html - + +或者用Node.js开启测试服务器,在`test`文件夹内的: +`` +$ node server +`` +然后打开该地址:locallhost:80进行测试。 ## 关于消息安全性 ## 由于任何iframe都可以收到广播的消息,建议传递消息时使用JSON String的形式,使用一个字段做消息有效性的验证。如果怕一个固定值(如项目名)不安全,可以使用一个简单的加密算法,并对业务脚本进行压缩混淆,此时的安全风险可以降到最低。 ## 问题与建议 ## 使用中难免遇到问题,欢迎提问与建议 : ) -[提交Issue](https://github.com/biqing/MessengerJS/issues/new) \ No newline at end of file +[提交Issue](https://github.com/biqing/MessengerJS/issues/new) + +# 根据前辈的Messenger写成了Messenger2 # +支持消息标记,比如监听一个名为 `test`的消息名称,发送的时候只发送消息个`test`的监听事件。 + + //iframe 1 + ifr.listen('test',function(data){ + console.log('post'+data+'from test'); + }); + //iframe 2 + ifr2.to('ifr',0).post('test','test1'); diff --git a/messenger2.js b/messenger2.js new file mode 100644 index 0000000..f072e7c --- /dev/null +++ b/messenger2.js @@ -0,0 +1,99 @@ +window.Messenger = (function(w,jQuery){ + var prefix = '[_Project_Name]'; + + var ie = w.navigator.appName !== 'Netscape'; + var parent = w.parent; + var nv = ie ? parent.navigator : void(0); + + var Messenger = function (myName){ + if(ie)this.self = nv[myName] = new Watcher(); + this.evNames = {}; + this.data = []; + return this; + }; + + var iePostMessage = {}; + var usePostMessage = {}; + //ie下的通信 + //监视器 + function Watcher(){ + this.targets = {}; + } + Watcher.prototype.addListener = function(evName,callback){ + var targets = this.targets; + targets[evName] = callback; + }; + Watcher.prototype.emit = function(evName,msg){ + var targets = this.targets; + targets[evName](msg); + }; + //ie post + iePostMessage.to = function(target,n){ + this.tName = target; + return this; + }; + iePostMessage.post = function(evName,msg){ + var self = this; + var name = self.tName; + parent['ifr'].onload = function(){ + self.target = nv[name]; + self.target.emit(evName,msg); + } + return this; + }; + iePostMessage.listen = function(evName,callback){ + this.self.addListener(evName,callback); + return this; + }; + //post message + usePostMessage.post = function(evName,msg){ + var self = this; + var data = self.data; + var tg = self.target; + data.push({name:evName,msg:msg}); + self._onload(function(){ + tg.contentWindow.postMessage(data,tg.src); + }); + return this; + }; + usePostMessage.to = function(target,n){ + var self = this; + self.tName = target; + if(n === void(0)){ + self.target = document.querySelector('#'+self.tName); + }else{ + self.ftf = !0; + self.target = {contentWindow : parent.frames[n],src:'*'} + } + return this; + }; + usePostMessage.listen = function(evName,callback){ + var self = this; + var name = evName; + var names = self.evNames; + names[name] = callback; + var wrap = function(event){ + var data = event.data; + var ns = names; + var n = name; + data.forEach(function(v){ + var evN = v.name; + if(n && n!==evN)return; + var msg = v.msg; + if(n==evN || (!n && ns[evN]))ns[evN](msg); + }); + }; + w.onmessage = wrap; + return this; + }; + Messenger.prototype = ie ? iePostMessage : usePostMessage; + Messenger.prototype._onload = function(fn){ + var self = this; + if(self.ftf){ + fn(); + }else if(w == parent){ + self.target.onload = fn; + } + } + return Messenger; +})(window,window.jQuery); diff --git a/demo/child.html b/test/child.html similarity index 97% rename from demo/child.html rename to test/child.html index 3bedf21..6348b62 100644 --- a/demo/child.html +++ b/test/child.html @@ -1,44 +1,44 @@ - - - - - - iframe communication (child window page) - - - - -
-

- child window - This is a child window under the domain: - -

- -

- - -

-

-
- - - + + + + + + iframe communication (child window page) + + + + +
+

+ child window + This is a child window under the domain: + +

+ +

+ + +

+

+
+ + + \ No newline at end of file diff --git a/demo/iframe1.html b/test/iframe1.html similarity index 94% rename from demo/iframe1.html rename to test/iframe1.html index 2a7f1d8..e2fd168 100644 --- a/demo/iframe1.html +++ b/test/iframe1.html @@ -1,53 +1,53 @@ - - - - - - iframe communication (iframe page) - - - - -
-

- iframe1 - This is a iframe under the domain: - -

- -

- - - - -

-

-
- - - - \ No newline at end of file + + + + + + iframe communication (iframe page) + + + + +
+

+ iframe1 + This is a iframe under the domain: + +

+ +

+ + + + +

+

+
+ + + + diff --git a/demo/iframe2.html b/test/iframe2.html similarity index 97% rename from demo/iframe2.html rename to test/iframe2.html index 203f088..3e52c3f 100644 --- a/demo/iframe2.html +++ b/test/iframe2.html @@ -1,53 +1,53 @@ - - - - - - iframe communication (iframe page) - - - - -
-

- iframe2 - This is a iframe under the domain: - -

- -

- - - - -

-

-
- - - + + + + + + iframe communication (iframe page) + + + + +
+

+ iframe2 + This is a iframe under the domain: + +

+ +

+ + + + +

+

+
+ + + \ No newline at end of file diff --git a/test/messenger.js b/test/messenger.js new file mode 100644 index 0000000..7fa8abf --- /dev/null +++ b/test/messenger.js @@ -0,0 +1,123 @@ +/** + * __ ___ + * / |/ /___ _____ _____ ___ ____ ____ _ ___ _____ + * / /|_/ // _ \ / ___// ___// _ \ / __ \ / __ `// _ \ / ___/ + * / / / // __/(__ )(__ )/ __// / / // /_/ // __// / + * /_/ /_/ \___//____//____/ \___//_/ /_/ \__, / \___//_/ + * /____/ + * + * @description MessengerJS, a common cross-document communicate solution. + * @author biqing kwok + * @version 2.0 + * @license release under MIT license + */ + +window.Messenger = (function(){ + + // 消息前缀, 建议使用自己的项目名, 避免多项目之间的冲突 + // !注意 消息前缀应使用字符串类型 + var prefix = "[PROJECT_NAME]", + supportPostMessage = 'postMessage' in window; + + // Target 类, 消息对象 + function Target(target, name){ + var errMsg = ''; + if(arguments.length < 2){ + errMsg = 'target error - target and name are both requied'; + } 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; + } + + // 往 target 发送消息, 出于安全考虑, 发送消息会带上前缀 + if ( supportPostMessage ){ + // IE8+ 以及现代浏览器支持 + Target.prototype.send = function(msg){ + this.target.postMessage(prefix + msg, '*'); + }; + } else { + // 兼容IE 6/7 + Target.prototype.send = function(msg){ + var targetFunc = window.navigator[prefix + this.name]; + if ( typeof targetFunc == 'function' ) { + targetFunc(prefix + msg, window); + } else { + throw new Error("target callback function is not defined"); + } + }; + } + + // 信使类 + // 创建Messenger实例时指定, 必须指定Messenger的名字, (可选)指定项目名, 以避免Mashup类应用中的冲突 + // !注意: 父子页面中projectName必须保持一致, 否则无法匹配 + function Messenger(messengerName, projectName){ + this.targets = {}; + this.name = messengerName; + this.listenFunc = []; + prefix = projectName || prefix; + if(typeof prefix !== 'string') { + prefix = prefix.toString(); + } + this.initListen(); + } + + // 添加一个消息对象 + Messenger.prototype.addTarget = function(target, name){ + var targetObj = new Target(target, name); + this.targets[name] = targetObj; + }; + + // 初始化消息监听 + Messenger.prototype.initListen = function(){ + var self = this; + var generalCallback = function(msg){ + if(typeof msg == 'object' && msg.data){ + msg = msg.data; + } + // 剥离消息前缀 + msg = msg.slice(prefix.length); + for(var i = 0; i < self.listenFunc.length; i++){ + 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[prefix + this.name] = generalCallback; + } + }; + + // 监听消息 + Messenger.prototype.listen = function(callback){ + this.listenFunc.push(callback); + }; + // 注销监听 + 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; +})(); diff --git a/demo/parent.html b/test/parent.html similarity index 83% rename from demo/parent.html rename to test/parent.html index 0156eb9..a8bc66c 100644 --- a/demo/parent.html +++ b/test/parent.html @@ -1,76 +1,76 @@ - - - - - - Demo - MessengerJS - - - - - -
-

Demo of MessengerJS

-

Github project page

-

- parent - Domain of the parent page - -

-

- - -

- -

- - - - - -

-

-
- - - \ No newline at end of file + + + + + + Demo - MessengerJS + + + + + +
+

Demo of MessengerJS

+

Github project page

+

+ parent + Domain of the parent page + +

+

+ + +

+ +

+ + + + + +

+

+
+ + + diff --git a/test/server.js b/test/server.js new file mode 100644 index 0000000..3814024 --- /dev/null +++ b/test/server.js @@ -0,0 +1 @@ +require('./server/index.js')(); diff --git a/test/server/http.js b/test/server/http.js new file mode 100644 index 0000000..38bccf4 --- /dev/null +++ b/test/server/http.js @@ -0,0 +1,30 @@ +var u = require('url'); +var fs = require('fs'); + +var http = require('http').createServer(function(req,res){ + var path = require('url').parse(req.url).pathname; + if(req.method == 'GET'){ + switch(path){ + case '/': + res.writeHead(200, {'Content-Type': 'text/html'}); + fs.readFile('./parent.html',function(err,data){ + res.end(data,'utf8'); + }); + break; + case '/child.html': + fs.readFile('./child.html',function(err,data){ + res.end(data,'utf8'); + }); + break; + case '/messenger.js': + res.writeHead(200, {'Content-Type': 'application/x-javascript'}); + fs.readFile('./messenger.js',function(err,data){ + res.end(data,'utf8'); + }); + break; + default: + res.end('not path'); + } + } +}).listen(80); +console.log('serve open - locallhost:80'); diff --git a/test/server/http1.js b/test/server/http1.js new file mode 100644 index 0000000..6ad6d7a --- /dev/null +++ b/test/server/http1.js @@ -0,0 +1,26 @@ +var u = require('url'); +var fs = require('fs'); + +var http = require('http').createServer(function(req,res){ + + var path = require('url').parse(req.url).pathname; + + res.writeHead(200, {'Content-Type': 'text/html'}); + if(req.method == 'GET'){ + switch(path){ + case '/': + fs.readFile('./iframe1.html',function(err,data){ + res.end(data,'utf8'); + }); + break; + case '/messenger.js': + res.writeHead(200, {'Content-Type': 'application/x-javascript'}); + fs.readFile('./messenger.js',function(err,data){ + res.end(data,'utf8'); + }); + break; + default: + res.end('not path'); + } + } +}).listen(8080); diff --git a/test/server/http2.js b/test/server/http2.js new file mode 100644 index 0000000..3abb7a2 --- /dev/null +++ b/test/server/http2.js @@ -0,0 +1,26 @@ +var u = require('url'); +var fs = require('fs'); + +var http = require('http').createServer(function(req,res){ + + var path = require('url').parse(req.url).pathname; + + res.writeHead(200, {'Content-Type': 'text/html'}); + if(req.method == 'GET'){ + switch(path){ + case '/': + fs.readFile('./iframe2.html',function(err,data){ + res.end(data,'utf8'); + }); + break; + case '/messenger.js': + res.writeHead(200, {'Content-Type': 'application/x-javascript'}); + fs.readFile('./messenger.js',function(err,data){ + res.end(data,'utf8'); + }); + break; + default: + res.end('not path'); + } + } +}).listen(3000); diff --git a/test/server/index.js b/test/server/index.js new file mode 100644 index 0000000..ebadb38 --- /dev/null +++ b/test/server/index.js @@ -0,0 +1,7 @@ +var cp = require('child_process'); +function server(){ + var child = cp.fork('./server/http.js'); + var child1 = cp.fork('./server/http1.js'); + var child2 = cp.fork('./server/http2.js'); +} +module.exports = server; diff --git a/test2/iframe1.html b/test2/iframe1.html new file mode 100644 index 0000000..6e82eff --- /dev/null +++ b/test2/iframe1.html @@ -0,0 +1,17 @@ + + + + + Document + + +
0sdasdasdas
+ + + + diff --git a/test2/iframe2.html b/test2/iframe2.html new file mode 100644 index 0000000..682b4f6 --- /dev/null +++ b/test2/iframe2.html @@ -0,0 +1,15 @@ + + + + + Document + + +
if2
+ + + + diff --git a/test2/messenger.js b/test2/messenger.js new file mode 100644 index 0000000..f072e7c --- /dev/null +++ b/test2/messenger.js @@ -0,0 +1,99 @@ +window.Messenger = (function(w,jQuery){ + var prefix = '[_Project_Name]'; + + var ie = w.navigator.appName !== 'Netscape'; + var parent = w.parent; + var nv = ie ? parent.navigator : void(0); + + var Messenger = function (myName){ + if(ie)this.self = nv[myName] = new Watcher(); + this.evNames = {}; + this.data = []; + return this; + }; + + var iePostMessage = {}; + var usePostMessage = {}; + //ie下的通信 + //监视器 + function Watcher(){ + this.targets = {}; + } + Watcher.prototype.addListener = function(evName,callback){ + var targets = this.targets; + targets[evName] = callback; + }; + Watcher.prototype.emit = function(evName,msg){ + var targets = this.targets; + targets[evName](msg); + }; + //ie post + iePostMessage.to = function(target,n){ + this.tName = target; + return this; + }; + iePostMessage.post = function(evName,msg){ + var self = this; + var name = self.tName; + parent['ifr'].onload = function(){ + self.target = nv[name]; + self.target.emit(evName,msg); + } + return this; + }; + iePostMessage.listen = function(evName,callback){ + this.self.addListener(evName,callback); + return this; + }; + //post message + usePostMessage.post = function(evName,msg){ + var self = this; + var data = self.data; + var tg = self.target; + data.push({name:evName,msg:msg}); + self._onload(function(){ + tg.contentWindow.postMessage(data,tg.src); + }); + return this; + }; + usePostMessage.to = function(target,n){ + var self = this; + self.tName = target; + if(n === void(0)){ + self.target = document.querySelector('#'+self.tName); + }else{ + self.ftf = !0; + self.target = {contentWindow : parent.frames[n],src:'*'} + } + return this; + }; + usePostMessage.listen = function(evName,callback){ + var self = this; + var name = evName; + var names = self.evNames; + names[name] = callback; + var wrap = function(event){ + var data = event.data; + var ns = names; + var n = name; + data.forEach(function(v){ + var evN = v.name; + if(n && n!==evN)return; + var msg = v.msg; + if(n==evN || (!n && ns[evN]))ns[evN](msg); + }); + }; + w.onmessage = wrap; + return this; + }; + Messenger.prototype = ie ? iePostMessage : usePostMessage; + Messenger.prototype._onload = function(fn){ + var self = this; + if(self.ftf){ + fn(); + }else if(w == parent){ + self.target.onload = fn; + } + } + return Messenger; +})(window,window.jQuery); diff --git a/test2/parent.html b/test2/parent.html new file mode 100644 index 0000000..7b7acfc --- /dev/null +++ b/test2/parent.html @@ -0,0 +1,15 @@ + + + + + Document + + + + + + + + diff --git a/test2/server.js b/test2/server.js new file mode 100644 index 0000000..3814024 --- /dev/null +++ b/test2/server.js @@ -0,0 +1 @@ +require('./server/index.js')(); diff --git a/test2/server/http.js b/test2/server/http.js new file mode 100644 index 0000000..a8ef8b0 --- /dev/null +++ b/test2/server/http.js @@ -0,0 +1,25 @@ +var u = require('url'); +var fs = require('fs'); + +var http = require('http').createServer(function(req,res){ + var path = require('url').parse(req.url).pathname; + if(req.method == 'GET'){ + switch(path){ + case '/': + res.writeHead(200, {'Content-Type': 'text/html'}); + fs.readFile('./parent.html',function(err,data){ + res.end(data,'utf8'); + }); + break; + case '/messenger.js': + res.writeHead(200, {'Content-Type': 'application/x-javascript'}); + fs.readFile('./messenger.js',function(err,data){ + res.end(data,'utf8'); + }); + break; + default: + res.end('not path'); + } + } +}).listen(80); +console.log('serve open - locallhost:80'); diff --git a/test2/server/http1.js b/test2/server/http1.js new file mode 100644 index 0000000..a3a222b --- /dev/null +++ b/test2/server/http1.js @@ -0,0 +1,24 @@ +var u = require('url'); +var fs = require('fs'); + +var http = require('http').createServer(function(req,res){ + var path = require('url').parse(req.url).pathname; + if(req.method == 'GET'){ + switch(path){ + case '/': + res.writeHead(200, {'Content-Type': 'text/html'}); + fs.readFile('./iframe1.html',function(err,data){ + res.end(data,'utf8'); + }); + break; + case '/messenger.js': + res.writeHead(200, {'Content-Type': 'application/x-javascript'}); + fs.readFile('./messenger.js',function(err,data){ + res.end(data,'utf8'); + }); + break; + default: + res.end('not path'); + } + } +}).listen(8080); diff --git a/test2/server/http2.js b/test2/server/http2.js new file mode 100644 index 0000000..a03dfbc --- /dev/null +++ b/test2/server/http2.js @@ -0,0 +1,24 @@ +var u = require('url'); +var fs = require('fs'); + +var http = require('http').createServer(function(req,res){ + var path = require('url').parse(req.url).pathname; + if(req.method == 'GET'){ + switch(path){ + case '/': + res.writeHead(200, {'Content-Type': 'text/html'}); + fs.readFile('./iframe2.html',function(err,data){ + res.end(data,'utf8'); + }); + break; + case '/messenger.js': + res.writeHead(200, {'Content-Type': 'application/x-javascript'}); + fs.readFile('./messenger.js',function(err,data){ + res.end(data,'utf8'); + }); + break; + default: + res.end('not path'); + } + } +}).listen(3000); diff --git a/test2/server/index.js b/test2/server/index.js new file mode 100644 index 0000000..739b72f --- /dev/null +++ b/test2/server/index.js @@ -0,0 +1,7 @@ +var cp = require('child_process'); +function server(){ + var child = cp.fork('./server/http.js'); + var child1 = cp.fork('./server/http1.js'); + var child1 = cp.fork('./server/http2.js'); +} +module.exports = server;