你可以将一个字符串化的函数作为postmessage事件数据进行传递,没有任何阻碍。实现起来很简单,对于如下任何函数声明:
function doSomething(){
alert("hello world!");
}
您可以使用encodeURI
对其字符串表示进行编码:
console.log(encodeURI(doSomething.toString()));
//function%20doSomething()%20%7B%0A%20%20%20%20alert(%22hello%20world!%22);%0A%7D
它可以作为闭包的一部分执行 - 比如说并不需要过于想象力的东西,像这样:
eval('('+decodeURI(strCallback)+')();');
这里有一个概念验证的可行性示例,没有跨框架结构 - 我会尝试制作一个postMessage版本,但在jsfiddle上托管它将是非常困难的。
更新
正如承诺的那样,下面是一个完整的模拟,它可以工作(链接在下面)。通过正确的event.origin
检查,它足以防范攻击,但我知道我们的安全团队绝不会像这样把eval
放到生产环境中 :)
如果有选择的话,我建议在两个页面之间规范化功能,以便只需要传递参数信息(即传递参数而不是函数);但肯定有一些情况下这种方法更加优选。
父级代码:
document.domain = "fiddle.jshell.net";
window.addEventListener("message", receiveMessage, false);
function receiveMessage(e) {
try {
eval('(' + decodeURI(e.data) + ')();');
} catch(e) {}
}
IFrame 代码:
document.domain = "fiddle.jshell.net";
window.addEventListener("message", receiveMessage, false);
function receiveMessage(e) {
e.source.postMessage(serializeFunction(doSomething), "http://fiddle.jshell.net");
}
function serializeFunction(f) {
return encodeURI(f.toString());
}
function doSomething() {
alert("hello world!");
}
原型模型: 父代码 和 iframe 代码。
window.parent
变量应该可以从 iframe 中访问。主窗口也会有一个parent
,但我相信它将指向自身。 - sparebytes