指定されたHTMLでiframeを動的に作成する


148

JavaScriptからiframeを作成し、次のように任意のHTMLで埋めようとしています。

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

iframe次に、有効なウィンドウとドキュメントが含まれることを期待します。ただし、これは当てはまりません。

> console.log(iframe.contentWindow);
ヌル

自分で試してください:http : //jsfiddle.net/TrevorBurnham/9k9Pe/

私は何を見落としているか?


9
HTML5はこれを自動的に行う新しいパラメーターを導入したことに注意してください:w3schools.com/tags/att_iframe_srcdoc.asp 唯一の問題はブラウザーの互換性です...
Vincent Audebert

回答:


121

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の答えを参照してください。


3
IE10でも機能しません。@mschrの回答はIE7 +で確実に機能し、おそらく古いバージョンでも機能します。
James M. Greene

6
彼の質問は「私が見落としているものは何ですか?」でした。そしてそれは、iframeがドキュメントに追加されなかったという事実でした。それがクロスブラウザだと言ったことは一度もありません。誰かが実際に不満を言ったと答えてから1年以上です。いいえ、クロスブラウザではありません。しかし、正直に言うと、コードの品質が必要な場合は、最初にiframeを使用するよりもはるかにクリーンな解決策がおそらくあります:)
GillesC

1
encodeURI(...)あなたのHTMLのような特殊な文字を持っているのであれば、すべての文字をコードしない#、これは壊れます。encodeURIComponent(...)これらの文字をエンコードします。この回答を
Ryan Morlok

237

あなた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ハンドルを介して完全に行われるため、後でフレームのコンテンツにアクセスして操作できます。あなたは確かのようにするために必要なすべての内容は(ブラウザの種類によって異なります)であろう、レンダリングされていること、である.WRITEコマンドが発行された後に/中に開始- しかし、ときnescessarily行われていないclose()と呼ばれています。

コールバックを行う100%の互換性のある方法は、このアプローチである可能性があります。

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

ただし、iframesにはonloadイベントがあります。以下は、DOM(js)として内部のhtmlにアクセスする方法です。

iframe.onload = function() {
   var div=iframe.contentWindow.document.getElementById('mydiv');
};

面白い; 私はこのテクニックを見たことがありません。URIエンコード/デコードがパフォーマンスに影響を与えることは知っていますが、srcdocプロパティをサポートしない環境での唯一の代替手段として説明されていることも確認しました。このdocument.writeアプローチにはマイナス面がありますか?
Trevor Burnham

1
@mschrこのメソッドは、インクルードとスタイルシートも読み込まれる完全なHTMLページコードをサポートしますか?stackoverflow.com/questions/19871886を
1.21ギガワット

2
基本的に、そうだと思いますが、そこには悪いコメントがあります。この手法は基本的に、document.writeを介して書き込むことができるinputtextstreamを開きます。次に、通常の読み込みWebページは、websocket-streamを介してこれを取得します。
mschr 2013年

2
これはInternet Explorerで機能します。IEのどのバージョンでもデータURIをiframeソースとして使用できないため、これは便利です。 caniuse.com/#feat=datauri
ジェシーハレット

2
document.body.appendChild(iframe)これが機能するために必要なことは興味深いです。
ポール

14

あなたの素晴らしい質問をありがとう、これは私を数回引っ張り出しました。dataURI HTMLソースを使用すると、完全な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>タグとiframe.src文字列でラップされたhtmlコンテンツに注意してください。

解析するには、iframe要素をDOMツリーに追加する必要があります。

document.body.appendChild(iframe);

ブラウザを使用しiframe.contentDocumentない限り、を検査することはできませんdisable-web-security。メッセージが届きます

DOMException:「HTMLIFrameElement」からの「contentDocument」プロパティの読み取りに失敗しました:クロスオリジンフレームへのアクセスからの原点「http:// localhost:7357」のフレームをブロックしました


12

内容がHTMLの文字列であるiframeを作成する方法として、srcdoc属性があります。これは古いブラウザーではサポートされていません(その主なもの:Internet Explorer、そしておそらくSafari?)。ただし、この動作にはポリフィルがあり、IEの条件付きコメントに入れたり、has.jsなどを使用して条件付きで遅延したりできます。それをロードします。


2
これのサポートは現在かなり主流です(IEを保存)。そして、これはcontentDocumentに直接アクセスするよりも間違いなく好ましいです。特に、sandbox属性と組み合わせて使用​​すると、contentDocumentにアクセスできないためです。
CambridgeMike

1

これは古い質問であることはわかっていsrcdocますが、この属性は現在広くサポートされており、この質問が頻繁に表示されるため、属性を使用した例を提供すると思いました。

srcdoc属性を使用して、埋め込むインラインHTMLを提供できます。srcサポートされている場合は、属性をオーバーライドします。srcサポートされていない場合、ブラウザーは属性にフォールバックします。

このsandbox属性を使用して、フレーム内のコンテンツに追加の制限を適用することもお勧めします。HTMLが自分のものでない場合、これは特に重要です。

const iframe = document.createElement('iframe');
const html = '<body>Foo</body>';
iframe.srcdoc = html;
iframe.sandbox = '';
document.body.appendChild(iframe);

古いブラウザをサポートする必要がある場合は、srcdocサポートを確認し、他の回答から他の方法のいずれかにフォールバックできます。

function setIframeHTML(iframe, html) {
  if (typeof iframe.srcdoc !== 'undefined') {
    iframe.srcdoc = html;
  } else {
    iframe.sandbox = 'allow-same-origin';
    iframe.contentWindow.document.open();
    iframe.contentWindow.document.write(html);
    iframe.contentWindow.document.close();
  }
}

var iframe = document.createElement('iframe');
iframe.sandbox = '';
var html = '<body>Foo</body>';

document.body.appendChild(iframe);
setIframeHTML(iframe, html);


1

URLアプローチは、小さなHTMLフラグメントに対してのみ機能します。より確実な方法は、BLOBからオブジェクトURLを生成し、それを動的iframeのソースとして使用することです。

const html = '<html>...</html>';
const iframe = document.createElement('iframe');
const blob = new Blob([html], {type: 'text/html'});
iframe.src = window.URL.createObjectURL(blob);
document.body.appendChild(iframe);

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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.