到目前为止,我只看过postmessage的教程,其中一个窗口发送一种消息,另一个窗口只用一种方式解释消息。
如果我想在windows之间进行多种不同的交互,那么postmessage可以处理吗?
这是否违背了postmessage应该做的事情?
例如,如果我希望能够来回发送自定义回调等,该怎么办?
答案 0 :(得分:54)
有两种方法可以将多部分消息传递给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到stringify
对象完全相同,只是在前一种情况下,浏览器正在进行自己的序列化(以及随后的反序列化) ),而后一种方法则由你来序列化/反序列化。
这里的外卖点是:
文档和参考资料
window.postMessage
:https://developer.mozilla.org/en/DOM/window.postMessage String.split
:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/split JSON.stringify
:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/stringify JSON.parse
:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/parse 答案 1 :(得分:3)
我在npm called "silver-bullet"找到了一个不错的插件。它使用回调执行postMessage并使用eventEmitter来获取特定事件。非常好。
但要实现这一点,我会做类似的事情......
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), '*');
}
你必须这样做:
以下是一个非常基本的演示:
if (messageHandler[message.handler])
messageHandler[message.handler](message, function() {
iframe.contentWindow.postMessage(JSON.stringify(message), '*');
});
else
iframe.contentWindow.postMessage(JSON.stringify(message), '*');
我更进一步使用这个概念并使用消息处理程序查找,其中消息具有所需的处理函数名称以唤起并传递消息。消息处理程序也会进行回调,完成后会触发回调。回调只是具有调用本机发布消息的简单逻辑,再次发回其收到的回调ID。
因此,消息事件处理的最后一行代码是:
function onLoad() {
document.addEventListener("deviceready", onDeviceReady, false);
}
function onDeviceReady() {
}
var map;
function initialize() {
var mapOptions = {
zoom: 14
};
map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
// Try HTML5 geolocation
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var pos = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
var infowindow = new google.maps.InfoWindow({
content: 'contentstring'
});
var marker1 = new google.maps.Marker({
position: pos,
map: map,
title: 'ciao!'
});
google.maps.event.addListener(marker1, 'click', function() {
infowindow.open(map,marker1);
});
var marker2 = new google.maps.Marker({
position: new google.maps.LatLng( 45.4353135, 12.135795400000006 ),
map: map,
title: 'ciao!'
});
map.setCenter(pos);
}, function() {
handleNoGeolocation(true);
});
} else {
// Browser doesn't support Geolocation
handleNoGeolocation(false);
}
}
function handleNoGeolocation(errorFlag) {
if (errorFlag) {
var content = 'Error: The Geolocation service failed.';
} else {
var content = 'Error: Your browser doesn\'t support geolocation.';
}
var options = {
map: map,
position: new google.maps.LatLng(60, 105),
content: content
};
var infowindow = new google.maps.InfoWindow(options);
map.setCenter(options.position);
}
google.maps.event.addDomListener(window, 'load', initialize);
允许异步内容发生。
答案 2 :(得分:0)
在不传递任何实际代码的情况下,触发回调的一种非常简单的方法是:
:定位强>
var callbacks = {
myCallback: function() { doSomething(); }
};
window.addEventListener('message', function (ev) {
// origin checking etc
callbacks[ev.data]();
}, false);
<强>来源
target.postMessage('myCallback', 'http://www.example.com');
答案 3 :(得分:0)
我最近遇到了同样的问题。经过数小时的搜索,我遇到了post-robot。它由paypal
开发,解决了我的大多数问题,包括为postMessage
回调。
它还支持在有效载荷内部传递函数。
您可以在此处Introducing post-robot
查看介绍。