Tạo một iframe với HTML đã cho một cách linh hoạt


148

Tôi đang cố gắng tạo iframe từ JavaScript và điền nó bằng HTML tùy ý, như vậy:

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

Tôi hy vọng sẽ iframechứa một cửa sổ và tài liệu hợp lệ. Tuy nhiên, đây không phải là trường hợp:

> console.log (iframe.contentWindow);
vô giá trị

Hãy tự mình thử: http://jsfiddle.net/TrevorBurnham/9k9Pe/

Tôi đang nhìn cái gì?


9
Lưu ý rằng HTML5 đã giới thiệu một tham số mới tự động thực hiện việc này: w3schools.com/tags/att_iframe_srcdoc.asp Vấn đề duy nhất là khả năng tương thích trình duyệt ...
Vincent Audebert

Câu trả lời:


121

Đặt cài đặt srcmới được tạo iframetrong javascript không kích hoạt trình phân tích cú pháp HTML cho đến khi phần tử được chèn vào tài liệu. HTML sau đó được cập nhật và trình phân tích cú pháp HTML sẽ được gọi và xử lý thuộc tính như mong đợi.

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);

Ngoài ra, câu trả lời này cho câu hỏi của bạn, điều quan trọng cần lưu ý là phương pháp này có vấn đề tương thích với một số trình duyệt, vui lòng xem câu trả lời của @mschr để biết giải pháp đa trình duyệt.


3
Thậm chí không hoạt động trong IE10. Câu trả lời của @ mschr hoạt động trong IE7 + chắc chắn, thậm chí có thể là các phiên bản cũ hơn.
James M. Greene

6
Câu hỏi của anh ấy là "Tôi đang nhìn cái gì?" và đó là thực tế là iframe không được thêm vào tài liệu. Tôi không bao giờ tuyên bố đó là trình duyệt chéo và chỉ hơn một năm sau khi tôi trả lời rằng có ai đó thực sự phàn nàn. Không, nó không phải là trình duyệt chéo. Nhưng hãy trung thực nếu bạn muốn chất lượng mã có lẽ có một giải pháp sạch hơn nhiều so với sử dụng iframe ở vị trí đầu tiên :)
GillesC

1
Lưu ý rằng encodeURI(...)không mã hóa tất cả các ký tự, vì vậy nếu HTML của bạn có các ký tự đặc biệt như thế #, điều này sẽ bị hỏng. encodeURIComponent(...)mã hóa các ký tự này. Xem câu trả lời này
Ryan Morlok

237

Mặc dù bạn src = encodeURInên làm việc, tôi đã đi một con đường khác:

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();

Vì điều này không có hạn chế tên miền x và được thực hiện hoàn toàn thông qua iframetay cầm, bạn có thể truy cập và thao tác nội dung của khung sau này. Tất cả những gì bạn cần chắc chắn là, nội dung đã được hiển thị, sẽ (tùy thuộc vào loại trình duyệt) bắt đầu trong / sau khi lệnh .write được ban hành - nhưng không được thực hiện khi close()được gọi.

Một cách tương thích 100% để thực hiện một cuộc gọi lại có thể là cách tiếp cận này:

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

Iframes có sự kiện onload, tuy nhiên. Đây là một cách tiếp cận để truy cập html bên trong dưới dạng DOM (js):

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

Hấp dẫn; Tôi đã không nhìn thấy kỹ thuật này trước đây. Tôi biết rằng mã hóa / giải mã URI thêm một điểm nhấn hiệu năng, nhưng tôi cũng đã thấy nó được mô tả như là sự thay thế duy nhất trong các môi trường không hỗ trợ thuộc srcdoctính . Có một nhược điểm của document.writecách tiếp cận?
Trevor Burnham

1
@mschr Phương pháp này có hỗ trợ mã trang HTML đầy đủ trong đó bao gồm cả và bảng định kiểu cũng được tải không? Xem stackoverflow.com/questions/19871886
1.21 gigawatt

2
Về cơ bản, vâng tôi tin rằng nó nên, bình luận xấu ở đó. Kỹ thuật về cơ bản mở ra một dòng inputtext mà bạn có thể viết thông qua document.write. Đổi lại, một trang web tải bình thường truy xuất thông tin này thông qua luồng websocket.
mschr

2
Điều này hoạt động trong Internet Explorer! Điều đó rất hữu ích vì URI dữ liệu không thể được sử dụng làm nguồn iframe trong bất kỳ phiên bản IE nào. caniuse.com/#feat=datauri
Jesse Hallett

2
Điều thú vị document.body.appendChild(iframe)là cần thiết cho việc này để làm việc.
Paul

14

Cảm ơn câu hỏi tuyệt vời của bạn, điều này đã bắt gặp tôi một vài lần. Khi sử dụng nguồn HTML dataURI, tôi thấy rằng tôi phải xác định một tài liệu HTML hoàn chỉnh.

Xem bên dưới một ví dụ sửa đổi.

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

lưu ý nội dung html được bao bọc bởi <html>các thẻ và iframe.srcchuỗi.

Phần tử iframe cần được thêm vào cây DOM để được phân tích cú pháp.

document.body.appendChild(iframe);

Bạn sẽ không thể kiểm tra iframe.contentDocumenttrừ khi bạn disable-web-securitytrên trình duyệt của mình. Bạn sẽ nhận được một tin nhắn

DOMException: Không thể đọc thuộc tính 'contentDocument' từ 'HTMLIFrameEuity': Bị chặn một khung có nguồn gốc " http: // localhost: 7357 " khi truy cập vào khung có nguồn gốc chéo.


12

Có một cách khác để tạo iframe có nội dung là một chuỗi HTML: thuộc tính srcdoc . Điều này không được hỗ trợ trong các trình duyệt cũ hơn (chủ yếu trong số đó: Internet Explorer và có thể cả Safari ?), Nhưng có một polyfill cho hành vi này, bạn có thể đưa ra các nhận xét có điều kiện cho IE hoặc sử dụng một cái gì đó như has.js để lười biếng một cách có điều kiện tải nó.


2
Hiện tại hỗ trợ này khá chính thống (lưu IE). Và điều này chắc chắn là tốt hơn để truy cập trực tiếp vào contentDocument - đặc biệt là nếu được sử dụng cùng với thuộc tính hộp cát, bạn không thể truy cập contentDocument.
CambridgeMike

1

Tôi biết đây là một câu hỏi cũ nhưng tôi nghĩ rằng tôi sẽ cung cấp một ví dụ sử dụng srcdocthuộc tính vì hiện tại nó được hỗ trợ rộng rãi và đây là câu hỏi được xem thường xuyên.

Sử dụng srcdocthuộc tính, bạn có thể cung cấp HTML nội tuyến để nhúng. Nó ghi đè srcthuộc tính nếu được hỗ trợ. Trình duyệt sẽ quay trở lại srcthuộc tính nếu không được hỗ trợ.

Tôi cũng sẽ khuyên bạn nên sử dụng sandboxthuộc tính để áp dụng các hạn chế bổ sung cho nội dung trong khung. Điều này đặc biệt quan trọng nếu HTML không phải là của riêng bạn.

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

Nếu bạn cần hỗ trợ các trình duyệt cũ hơn, bạn có thể kiểm tra srcdochỗ trợ và dự phòng một trong những phương pháp khác từ các câu trả lời khác.

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

Cách tiếp cận URL sẽ chỉ hoạt động đối với các đoạn HTML nhỏ. Cách tiếp cận vững chắc hơn là tạo một URL đối tượng từ một đốm màu và sử dụng nó làm nguồn của iframe động.

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

Làm cái này

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

var frame_win = getIframeWindow(el);

console.log(frame_win);
...

getIframeWindow được định nghĩa ở đây

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.