PostMessage Source IFrame
Я работаю над веб-сайтом с междоменными iframe, размер которых изменяется до нужной высоты, используя postMessage. Единственная проблема, с которой я столкнулась, - это определить, какой из iframe имеет ту высоту. Способ, которым я в настоящее время настроен, заключается в том, что когда один iframe отправляет свою высоту родительскому, все высоты iframes изменяются.
Родитель:
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function(e) {
$('iframe').height(e.data);
}, false);
Iframe:
var updateHeight = function() {
if(window.parent) {
window.parent.postMessage($('.widget').outerHeight(), '*');
}
};
Есть ли способ определить, какой iframe отправил событие message
?
Ответы
Ответ 1
Я нашел решение отсюда: Как разделить данные между окном и фреймом в JavaScript
Родитель:
var frames = document.getElementsByTagName('iframe');
for (var i = 0; i < frames.length; i++) {
if (frames[i].contentWindow === event.source) {
$(frames[i]).height(event.data); //the height sent from iframe
break;
}
}
Ответ 2
Да, вы можете идентифицировать IFRAME, который сделал postMessage
. Существуют разные ситуации:
-
источник IFRAME имеет тот же самый URL-адрес (например, http://example.com/
) в качестве окна, которое получает сообщение: IFRAME идентифицируется с помощью
myIFRAME.contentWindow == event.source
-
источник IFRAME имеет тот же самый источник, но относительный URL (например, /myApp/myPage.html
), на родительскую HTML-страницу: IFRAME идентифицируется с помощью
myIFRAME.contentWindow == event.source.parent
-
источник IFRAME имеет URL-адрес перекрестного происхождения (например, http://example.com/
), отличающийся от страницы, получающей сообщение (например, http://example.org/
): вышеуказанные методы не работают ( сравнение всегда false
, а доступ к свойствам event.source
приводит к ошибкам Access Denied
), и IFRAME должен быть идентифицирован на основе его исходного домена;
myIFRAME.src.indexOf(event.origin)==0
Чтобы управлять этими тремя разными ситуациями, я использую следующее:
var sourceFrame = null; // this is the IFRAME which send the postMessage
var myFrames = document.getElementsByTagName("IFRAME");
var eventSource = event.source; // event is the event raised by the postMessage
var eventOrigin = event.origin; // origin domain, e.g. http://example.com
// detect the source for IFRAMEs with same-origin URL
for (var i=0; i<myFrames.length; i++) {
var f = myFrames[i];
if (f.contentWindow==eventSource || // for absolute URLs
f.contentWindow==eventSource.parent) { // for relative URLs
sourceFrame = f;
break;
}
}
// detect the source for IFRAMEs with cross-origin URL (because accessing/comparing event.source properties is not allowed for cross-origin URL)
if (sourceFrame==null) {
for (var i=0; i<myFrames.length; i++) {
if (myFrames[i].src.indexOf(eventOrigin)==0) {
sourceFrame = myFrames[i];
break;
}
}
}
Для междоменных URL-адресов обратите внимание, что мы не можем отличить истинный источник, если event.origin
является областью, общей для нескольких IFRAME.
Некоторые люди используют ===
вместо ==
, но в этом контексте я не нашел никакой разницы, поэтому я использую самый короткий компаратор.
Эта реализация была протестирована и работает под:
В качестве альтернативы (предложенной Гриффином) вы можете использовать IFRAME src с уникальным idenfitier (например, timestamp), и веб-приложение IFRAME отправит обратно этот уникальный идентификатор в опубликованные сообщения. Хотя идентификация IFRAME будет проще, этот подход требует изменения веб-приложения IFRAME'd (что не всегда возможно). Это также может привести к проблемам безопасности (например, веб-приложение IFRAME пытается угадать уникальный идентификатор других приложений IFRAME).
Ответ 3
У меня есть идея решить эту проблему. когда вы создаете iframe, укажите id/id в iframe..
а в script внутри iframe отправить сообщение как объект, который будет выглядеть как
window.parent.postMessage({"height" : $('.widget').outerHeight(), "frmname" : window.name}, '*');
в родительском слушателе,
eventer(messageEvent, function(e) {`enter code here`
$(e.data.frmname).height(e.data.height);
}, false);
Ответ 4
Если исходный iframe вложен в более чем один родительский iframe, вам нужно будет переустановить свойство window.frames каждого iframe и сравнить его с свойством messageEvent # source.
Например, если сообщение генерируется iframe # level3 этого Dom.
<iframe Id=level1>
<iframe Id=level2>
<iframe Id=level3 />
</iframe>
</iframe>
Вы должны иметь возможность найти индекс предка iframe в текущем окне, используя.
FindMe = event.source
FrameIndex = find(window)
frames[FrameIndex].frameElement == getElByTagName(iframe)[FrameIndex]
function find(target){
for (i=0; I< target.frames.length; i ++)
if(target.frames[i] == FindMe || find(target.frames[i]))
return i
return false
}
Важно отметить, что
Свойство Window.frames не ограничено политикой междоменной политики
Этот метод будет работать независимо от того, насколько глубоко вложен источник iframe, который был
window.frames - это набор объектов окна, а не элементов iframe.
доступ к параметрам s memebers из коллекции window.frames рестриктируется Same Origin (например, вы не сможете получить доступ к свойствам frameElement или местоположения window.frames [i]
Ответ 5
Событие также должно иметь свойство "источник", которое можно сравнить с свойством iframes "contentWindow".