How to execute a function through postMessage
我在iframe中有以下代码:
1 2 3 4 5 6 | window.addEventListener('message', function(e){ if(e.data == 'test') console.log(e); }, false); |
并在父文档中:
1 | $('#the_iframe').get(0).contentWindow.postMessage('test', 'http://localhost/'); |
因此,父文档会向iframe发送"测试"消息,并且它可以正常工作。
但是,如何在父文档中定义函数,以及如何通过postMessage将该函数发送到iframe,iframe将在本地执行该函数?
该函数对文档进行如下更改:
1 2 3 | var func = function(){ $("#some_div").addClass('sss'); } |
(
没有什么可以阻止您将字符串化函数作为消息传递后事件数据传递的。对于任何函数声明,实现都是微不足道的
1 2 3 | function doSomething(){ alert("hello world!"); } |
您可以
1 2 | console.log(encodeURI(doSomething.toString())); //function%20doSomething()%20%7B%0A%20%20%20%20alert(%22hello%20world!%22);%0A%7D |
然后可以将其作为闭包的一部分来执行-像这样的想象力不足
1 | eval('('+decodeURI(strCallback)+')();'); |
没有跨框架体系结构,这是一个经过提倡的概念证明-我将看看是否可以组合一个postMessage版本,但是托管w / jsfiddle并不是一件容易的事
更新资料
如所承诺的,一个完整的模型可以工作(下面的链接)。使用正确的
给定该选项,我建议在两个页面上对功能进行标准化,以便仅需要传递参数消息(即传递参数而不传递函数);但是,肯定有一些方案是首选方案。
父代码:
1 2 3 4 5 6 7 8 9 | document.domain ="fiddle.jshell.net";//sync the domains window.addEventListener("message", receiveMessage, false);//set up the listener function receiveMessage(e) { try { //attempt to deserialize function and execute as closure eval('(' + decodeURI(e.data) + ')();'); } catch(e) {} } |
iframe代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | document.domain ="fiddle.jshell.net";//sync the domains window.addEventListener("message", receiveMessage, false);//set up the listener function receiveMessage(e) { //"reply" with a serialized function e.source.postMessage(serializeFunction(doSomething),"http://fiddle.jshell.net"); } function serializeFunction(f) { return encodeURI(f.toString()); } function doSomething() { alert("hello world!"); } |
原型模型:父代码和iframe代码。
你真的不能。尽管postMessage的(草稿)规范讨论的是结构化对象,例如嵌套的对象和数组,JavaScript值(字符串,数字,日期等)和某些数据对象(例如File Blob,FileList和ArrayBuffer对象),大多数浏览器仅允许以下字符串(包括JSON)课程)。在MDN或dev.opera上了解更多信息。但是我非常确定,不可能发送函数对象,至少不能以闭包形式保存它们的范围。
因此,如果您真的想从父窗口执行一些代码,则将字符串化并在iframe中
在这种情况下,我会尝试其他方法。为什么? Bergi已经解释了为什么它无法按照您想要的方式工作。
您可以在父页面中定义(并重新定义函数):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <html> <head> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"> <script type="text/javascript"> var fun = function() { alert('I am a function!'); }; $(function() { // use this function to change div background color fun = function() { // get desired div var theDiv = $('#frame').contents().find('#some_div'); theDiv.css('background', '#ff0000'); }; // or override it, if you want to change div font color fun = function() { var theDiv = $('#frame').contents().find('#some_div'); theDiv.css('color', '#ff0000'); }; // in this example second (font color changing) function will be executed }); </head> <body> <iframe id="frame" src="frame.htm"></iframe> </body> </html> |
并在框架页面内调用函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <html> <head> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"> <script type="text/javascript"> $(function() { parent.fun(); }); </head> <body> I am a div (but inside frame)! </body> </html> |
可能不方便,但可以。
扩展以下问题,您可以对函数进行字符串化,使用
本质上,您正在做的是将功能封送,以便可以将其发送到iframe,然后在另一端将其拆封。为此,请使用以下代码:
iframe:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | window.addEventListener("message", function (event) { var data = JSON.parse(event.data); var callback = window[data.callback]; var value = data.value; if (data.type ==="function") value = eval(value); var callback = window[data.callback]; if (typeof callback ==="function") callback(value); }, false); function callFunction(funct) { funct(); } |
上级:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | var iframe = $("#the_iframe").get(0).contentWindow; postMessage(function () { $("#some_div").addClass("sss"); },"callFunction"); function postMessage(value, callback) { var type = typeof value; if (type ==="function") value = String(value); iframe.postMessage({ type: type, value: value, callback: callback },"http://localhost"); } |
在iframe和
但是请注意,该函数的范围是动态的(即,该函数中的所有非局部变量都必须已在您的iframe窗口中定义)。
在您的情况下,您在函数中使用的jquery
您始终可以将