Ответ 1
У Chrome есть ограничения по умолчанию, которые не позволяют вам обращаться к другим окнам с жесткого диска, даже если они технически одинаковы. В Chrome есть флаг, который может ослабить это ограничение безопасности (аргумент командной строки в Windows - это то, что я помню), хотя я бы не рекомендовал использовать этот флаг для более чем быстрого теста. См. этот пост или в этой статье для получения информации о аргументе командной строки.
Если вы запустите файлы с веб-сервера (даже если это локальный веб-сервер) вместо вашего жесткого диска, у вас не будет этой проблемы.
Или вы можете протестировать в других браузерах, которые не являются ограничивающими.
Теперь, когда вы изменили вопрос на что-то другое, вам нужно подождать, пока загрузится окно iframe, прежде чем вы сможете получить доступ к содержанию в нем, и вы не сможете использовать jQuery .ready()
в другом документе (это не так работа над другим документом).
$(document).ready(function() {
// get the iframe in my documnet
var iframe = document.getElementById("testFrame");
// get the window associated with that iframe
var iWindow = iframe.contentWindow;
// wait for the window to load before accessing the content
iWindow.addEventListener("load", function() {
// get the document from the window
var doc = iframe.contentDocument || iframe.contentWindow.document;
// find the target in the iframe content
var target = doc.getElementById("target");
target.innerHTML = "Found It!";
});
});
Страница тестирования здесь.
EDIT:. После дальнейших исследований я обнаружил, что jQuery выполнит некоторые из этих работ для вас, как это, и решение jQuery работает во всех основных браузерах:
$(document).ready(function() {
$("#testFrame").load(function() {
var doc = this.contentDocument || this.contentWindow.document;
var target = doc.getElementById("target");
target.innerHTML = "Found It!";
});
});
Страница тестирования здесь.
Если посмотреть на реализацию jQuery для этого, все, что он действительно делает, это настроить прослушиватель событий load
на самом iFrame.
Если вы хотите узнать подробные подробные сведения, которые вошли в отладку/решение первого метода выше:
В моей попытке решить эту проблему, я обнаружил некоторые довольно странные вещи (в Chrome) с iFrames. Когда вы сначала смотрите в окне iframe, есть документ, и он говорит, что его readyState === "complete"
такой, что вы думаете, что он загружал, но он лжет. Фактический документ и фактический тег <body>
из документа, загружаемого через URL-адрес в iframe, на самом деле НЕ есть. Я доказал это, поместив пользовательский атрибут в <body data-test="hello">
и проверив этот настраиваемый атрибут. И вот. Даже если document.readyState === "complete"
, этот пользовательский атрибут отсутствует в теге <body>
. Итак, я заключаю (по крайней мере, в Chrome), что iFrame изначально имеет в нем фиктивный и пустой документ и тело, которые не являются фактическими, которые будут установлены после того, как URL-адрес будет загружен в iFrame. Это делает весь этот процесс обнаружения, когда он готов быть довольно запутанным (это стоило мне часов, выясняя это). Фактически, если я установил таймер интервала и опрос iWindow.document.body.getAttribute("data-test")
, я увижу, что он будет отображаться как undefined
несколько раз, а затем, наконец, он будет отображаться с правильным значением и все это с document.readyState === "complete"
, что означает, что он полностью лежит.
Я думаю, что происходит, когда iFrame начинается с фиктивного и пустого документа и тела, который затем заменяется ПОСЛЕ загрузки контента. С другой стороны, iFrame window
является реальным окном. Таким образом, единственные способы, по которым я действительно ожидал загрузки контента, - это отслеживать событие load
на iFrame window
, поскольку это, похоже, не так. Если вы знали, что есть какой-то конкретный контент, которого вы ждали, вы также можете опросить, пока этот контент не будет доступен. Но даже тогда вы должны быть осторожны, потому что вы не можете получить iframe.contentWindow.document
слишком рано, потому что это будет неправильный документ, если вы его получите слишком рано. Все это довольно сломано. Я не могу найти способ использовать DOMContentLoaded
из-за самого документа iFrame, потому что у вас нет способа узнать, существует ли на самом деле объект document
, чтобы вы могли привязать к нему обработчик событий. Итак... Я поселился для события load
в окне iFrame, которое, похоже, работает.
Если вы действительно управляете кодом в iFrame, вы можете легче запускать событие из самого iFrame либо с помощью jQuery с $(document).ready()
в коде iFrame с его собственной версией jQuery, либо путем вызова функции в родительское окно из script, расположенное после вашего целевого элемента (таким образом, чтобы целевой элемент был загружен и готов).
Дальнейшее редактирование
После целой серии исследований и тестирования, здесь функция, которая сообщит вам, когда iFrame попадает в событие DOMContentLoaded
, а не ждет событие load
(которое может занять больше времени с изображениями и таблицами стилей).
// This function ONLY works for iFrames of the same origin as their parent
function iFrameReady(iFrame, fn) {
var timer;
var fired = false;
function ready() {
if (!fired) {
fired = true;
clearTimeout(timer);
fn.call(this);
}
}
function readyState() {
if (this.readyState === "complete") {
ready.call(this);
}
}
// cross platform event handler for compatibility with older IE versions
function addEvent(elem, event, fn) {
if (elem.addEventListener) {
return elem.addEventListener(event, fn);
} else {
return elem.attachEvent("on" + event, function () {
return fn.call(elem, window.event);
});
}
}
// use iFrame load as a backup - though the other events should occur first
addEvent(iFrame, "load", function () {
ready.call(iFrame.contentDocument || iFrame.contentWindow.document);
});
function checkLoaded() {
var doc = iFrame.contentDocument || iFrame.contentWindow.document;
// We can tell if there is a dummy document installed because the dummy document
// will have an URL that starts with "about:". The real document will not have that URL
if (doc.URL.indexOf("about:") !== 0) {
if (doc.readyState === "complete") {
ready.call(doc);
} else {
// set event listener for DOMContentLoaded on the new document
addEvent(doc, "DOMContentLoaded", ready);
addEvent(doc, "readystatechange", readyState);
}
} else {
// still same old original document, so keep looking for content or new document
timer = setTimeout(checkLoaded, 1);
}
}
checkLoaded();
}
Это называется так:
// call this when you know the iFrame has been loaded
// in jQuery, you would put this in a $(document).ready()
iFrameReady(document.getElementById("testFrame"), function() {
var target = this.getElementById("target");
target.innerHTML = "Found It!";
});