到目前为止,我只看到了postmessage的教程,其中一个窗口发送单一类型的消息,另一个窗口以单一方式解释消息。具有多种功能或自定义回调的PostMessage
如果我想在窗口之间有很多不同种类的交互,那么postmessage可以处理那个呢?
这是违背什么postmessage应该做的粮食?
例如,如果我想能够自定义回叫来回等等,该怎么办?
到目前为止,我只看到了postmessage的教程,其中一个窗口发送单一类型的消息,另一个窗口以单一方式解释消息。具有多种功能或自定义回调的PostMessage
如果我想在窗口之间有很多不同种类的交互,那么postmessage可以处理那个呢?
这是违背什么postmessage应该做的粮食?
例如,如果我想能够自定义回叫来回等等,该怎么办?
有几种方法可将多部分消息传递到postMessage
处理程序。第一种(也就是“干净”的方式)是使用分隔字符,然后通过字符串传递数据。
假设我们想传递用户ID,操作和用户名。字符串应该是这样的:
54|do_logout|chris
内postMessage
处理程序中,所传递的数据可以是对|
字符split
(docs),那么可以根据需要所使用的消息的每个分段。
另一种方法是使用JSON(docs)将对象转换为一侧的字符串,然后使用JSON将其转换回处理程序中的对象,而不是手动创建/拆分字符串。
var pass_data = {
'name':'Chris',
'id':54,
'action':'do_logout'
};
target_window.postMessage(JSON.stringify(pass_data), "http://www.example.net");
...然后在处理程序:
function (event) {
var pass_data = JSON.parse(event.data);
}
一定要测试,不过,因为没有提供对所有用户代理,尤其是老年人的JSON
对象。有许多(很多很多)的第三方库可以提供JSON支持,所以不要让缺乏完整的接受程序来吓跑你--JSON绝对是一种安全的“前进”标准。
如果我们能够直接传递这个对象,会不会更好?那么,盯着Firefox 6(source),你传递给postmessage处理程序的数据可能是一个对象。该对象将被序列化,所以在这方面有一些担心,但是:
var pass_data = {
'name':'Chris',
'id':54,
'action':'do_logout'
};
target_window.postMessage(pass_data, "http://www.example.net");
有点更好,呃?不幸的是,当前版本的IE只能处理字符串。 IE 10的postMessage
未来计划未能找到任何讨论。此外,IE 8/9中存在一个已知的错误,该错误除了帧以外的其他内容都会被破坏postMessage
。 (source)。
进入您的问题的具体方面 - 回调。除非你能够通过函数名称传递回调,否则没有办法传递一个函数;没有匿名功能给你。这与数据实际传递给处理程序的方式有关。在实践中,“不”支持对象作为数据,在幕后浏览器将传递的对象转换为字符串(序列化)。所有这一切说,那么,你应该明白,传递一个对象与在传递之前使用JSON到一个对象完全相同,只是在前一种情况下浏览器正在做自己的序列化(以及后续的非序列化),而使用后者的路由由您来序列化/反序列化。
外卖点这里:
文档和参考
window.postMessage
:https://developer.mozilla.org/en/DOM/window.postMessageString.split
:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/splitJSON.stringify
:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/stringifyJSON.parse
:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/parse很好的回答!祝愿我会为+10家庭假期评论 – johnnietheblack
您可以随时在消息的任意一侧执行JSON编码和解码。 – Pointy
即使使用JSON序列化,也不能传递函数引用(我相信OP是在之后的),因为它们不能被序列化。如果您使用JSON对对象进行编码(对于IE)或仅传递对象(对于Firefox> 6),则情况就是这样。如果您尝试在Firefox中传递函数,则会出现错误:错误:无法克隆该对象。:(太糟糕了,但这可能会更安全。) –
一个很简单的方法来触发回调不传递任何实际的代码是:
目标
var callbacks = {
myCallback: function() { doSomething(); }
};
window.addEventListener('message', function (ev) {
// origin checking etc
callbacks[ev.data]();
}, false);
来源
target.postMessage('myCallback', 'http://www.example.com');
有一个很好的插件,我就发现npm called "silver-bullet"。它使用回调函数执行postMessage,并使用eventEmitter来获取特定的事件。这是很不错的。
但要实现这一点,我会做这样的事情......
phostMessage(iframe, someObj, callback);
你必须这样做:
下面是一个非常基本的演示:
var callbacks = {};
// when receiving messages
window.addEventListener('message', function(ev) {
// todo: add origin check
if (!ev.data)
return;
var message;
try {
message = JSON.parse(ev.data);
} catch (ex) {
console.error(ex);
}
// ignore messages not having a callback ID
if (!message || !message.callbackId)
return;
// we are the sender getting the callback
if (callbacks[message.callbackId]) {
callbacks[message.callbackId](message);
delete callbacks[message.callbackId];
return;
}
// we are the receiver so we respond with the callback ID
// todo: restrict who can receive message (last param)
iframe.contentWindow.postMessage(JSON.stringify(message), '*');
});
// when sending messages
function phostMessage(iframe, obj, callback) {
obj.eventId = Math.random();
callbacks[obj.eventId] = callback;
// todo: restrict who can receive message (last param)
iframe.contentWindow.postMessage(JSON.stringify(obj), '*');
}
我将这个概念一点,并使用该消息具有所需的处理函数名,以唤起和传递消息到消息处理程序查找。消息处理程序也会进行回调,以便在完成时触发回调。回调只是简单的调用本地post消息的逻辑,再次发回其接收到的回叫id。
所以代码的消息事件处理的最后一行是:
if (messageHandler[message.handler])
messageHandler[message.handler](message, function() {
iframe.contentWindow.postMessage(JSON.stringify(message), '*');
});
else
iframe.contentWindow.postMessage(JSON.stringify(message), '*');
允许异步的东西发生。
不确定你的意思;你可以自由地检查收到的消息,并有条件地调用不同的代码等,所以... – Pointy
迄今为止,我还没有看到任何的例子,并从我读过的,postmessage不能发送对象或任何东西,这意味着我不得不剖析字符串...只是看起来不太干净。 – johnnietheblack