주어진 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자바 스크립트로 설정하면 요소가 문서에 삽입 될 때까지 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 명령이 실행되는 동안 / 이후에 (브라우저 유형에 따라) 컨텐츠가 렌더링되는지 확인해야 하지만close() 호출이 불필요하게 완료되지는 않습니다 .

콜백을 수행하는 100 % 호환 가능한 방법은 다음과 같습니다.

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

그러나 iframe에는 onload 이벤트가 있습니다. 내부 HTML을 DOM (js)으로 액세스하는 방법은 다음과 같습니다.

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

흥미있는; 나는이 기술을 전에 보지 못했다. URI 인코딩 / 디코딩이 성능 저하를 추가한다는 것을 알고 있지만 srcdoc속성을 지원하지 않는 환경에서 유일한 대안으로 설명 했습니다 . document.write접근 방식에 단점이 있습니까?
트레버 번햄

1
@mschr이 메소드는 포함 및 스타일 시트가로드되는 전체 HTML 페이지 코드를 지원합니까?
1.21 기가 와트를

2
기본적으로, 그렇습니다. 이 기술은 기본적으로 document.write를 통해 쓸 수있는 입력 텍스트 스트림을 엽니 다. 차례로, 정상적인 로딩 웹 페이지는 웹 소켓 스트림을 통해이를 검색합니다.
mschr

2
이것은 Internet Explorer에서 작동합니다! IE의 모든 버전에서 데이터 URI를 iframe 소스로 사용할 수 없으므로 편리합니다. caniuse.com/#feat=datauri
Jesse Hallett

2
document.body.appendChild(iframe)이것이 작동하는 데 흥미가 있습니다.
Paul

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 attribute . 이것은 오래된 브라우저 (주로 Internet Explorer 및 아마도 Safari ?)에서 지원되지 않지만 이 동작에 대한 polyfill 이 있습니다 .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.