Вопрос по iframe, javascript – Создание iframe с заданным HTML динамически

114

Я пытаюсь создать iframe из JavaScript и заполнить его произвольным HTML, например, так:

<code>var html = '<body>Foo</body>';
var iframe = document.createElement('iframe');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);
</code>

Я бы ожидалiframe чтобы затем содержать действительное окно и документ. Однако это не тот случай:

> console.log(iframe.contentWindow);
null

Попробуйте сами:http://jsfiddle.net/TrevorBurnham/9k9Pe/

Что я пропускаю?

Обратите внимание, что в HTML5 появился новый параметр, который делает это автоматически: W3schools.com / теги / att_iframe_srcdoc.asp Единственная проблема заключается в совместимости браузера ... Vincent Audebert

Ваш Ответ

5   ответов
11

это меня несколько раз застало. При использовании источника HTML dataURI я обнаружил, что должен определить полный HTML-документ.

См. Ниже модифицированный пример.

var html = '<html><head></head><body>Foo</body></html>';
var iframe = document.createElement('iframe');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);

принять к сведению содержание HTML, завернутый в<html> теги иiframe.src строка.

Элемент iframe необходимо добавить в дерево DOM для анализа.

document.body.appendChild(iframe);

Вы не сможете осмотретьiframe.contentDocument если только ты неdisable-web-security в вашем браузере. Вы получите сообщение

DOMException: не удалось прочитать свойство 'contentDocument' из 'HTMLIFrameElement': заблокирован фрейм с источником "http: // локальный: 7357 "от доступа к фрейму перекрестного происхождения.

95

src недавно созданногоiframe в javascript не вызывает анализатор HTML, пока элемент не будет вставлен в документ. Затем HTML обновляется, и анализатор HTML будет вызван и обработает атрибут, как и ожидалось.

http: //jsfiddle.net/9k9Pe/2

var iframe = document.createElement('iframe');
var html = '<body>Foo</body>';
iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);
document.body.appendChild(iframe);
console.log('iframe.contentWindow =', iframe.contentWindow);

Также ответьте на ваш вопрос. Важно отметить, что у этого подхода есть проблемы с совместимостью с некоторыми браузерами, пожалуйста, смотрите ответ @mschr для кросс-браузерного решения.

Даже не работает в IE10. Ответ @ mschr наверняка работает в IE7 +, может быть, даже в более старых версиях. James M. Greene
Его вопрос был "Что я пропускаю?" и это был тот факт, что iframe не был добавлен к документу. Я никогда не утверждаю, что это были кросс-браузеры, и только спустя год после того, как я ответил, что кто-то действительно жаловался. Нет, это не кросс-браузер. Но давайте будем честны, если вы хотите, чтобы качество кода было, вероятно, гораздо более чистым решением, чем в первую очередь использование iframe:) GillesC
быстро проверил это в IE9, и оно не работает alex
196

Хотя твойsrc = encodeURI должно сработать, я бы пошел другим путем:

var iframe = document.createElement('iframe');
var html = '<body>Foo</body>';
document.body.appendChild(iframe);
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(html);
iframe.contentWindow.document.close();

Поскольку это не имеет ограничений для x-домена и полностью выполняется черезiframe handle, вы можете получить доступ и манипулировать содержимым фрейма позже. Все, что вам нужно, это убедиться, что содержимое было отображено, и оно (в зависимости от типа браузера) запустится во время / после выполнения команды .write -н не обязательно делать, когдаclose() называется

100% совместимым способом выполнения обратного вызова может быть такой подход:

<html><body onload="parent.myCallbackFunc(this.window)"></body></html>

днако у @Iframes есть событие onload. Вот подход для доступа к внутреннему HTML как DOM (js):

iframe.onload = function() {
   var div=iframe.contentWindow.document.getElementById('mydiv');
};
Это работает в Internet Explorer! Это удобно, поскольку URI данных не могут использоваться в качестве источников iframe ни в одной версии IE. Caniuse.com / # подвиг = datauri Jesse Hallett
Это лучший ответ. James M. Greene
@ mschr Поддерживает ли этот метод полный HTML-код страницы, где также загружаются таблицы включений и таблицы стилей? Видеть Stackoverflow.com / вопросы / 19871886 1.21 gigawatts
В принципе, да, я считаю, что это должно быть, плохой комментарий там. Техника в основном открывает входной текстовый поток, в который вы можете писать через document.write. В свою очередь, обычная веб-страница загрузки получает это через поток websocket. mschr
Интересно, чтоdocument.body.appendChild(iframe) требуется, чтобы это работало. Paul
7

содержимое которого представляет собой строку HTML: атрибут srcdoc. Это не поддерживается в старых браузерах (главный из них: Internet Explorer и, возможно, Safari?), но есть Polyfill для этого поведения, которое вы можете поместить в условные комментарии для IE или использовать что-то вроде has.js для условно-ленивой загрузки.

support для этого сейчас довольно распространен (за исключением IE). И это, безусловно, предпочтительнее, чем прямой доступ к contentDocument, особенно если использовать его вместе с атрибутом песочницы, и вы не сможете получить доступ к contentDocument. CambridgeMike
0

Сделай эт

...
var el = document.getElementById('targetFrame');

var frame_win = getIframeWindow(el);

console.log(frame_win);
...

GetIframeWindow определяется здесь

function getIframeWindow(iframe_object) {
  var doc;

  if (iframe_object.contentWindow) {
    return iframe_object.contentWindow;
  }

  if (iframe_object.window) {
    return iframe_object.window;
  } 

  if (!doc && iframe_object.contentDocument) {
    doc = iframe_object.contentDocument;
  } 

  if (!doc && iframe_object.document) {
    doc = iframe_object.document;
  }

  if (doc && doc.defaultView) {
   return doc.defaultView;
  }

  if (doc && doc.parentWindow) {
    return doc.parentWindow;
  }

  return undefined;
}

Похожие вопросы