Làm cách nào để di chuyển iFrame trong DOM mà không làm mất trạng thái của nó?


93

Hãy xem HTML đơn giản này:

<div id="wrap1">
  <iframe id="iframe1"></iframe>
</div>
<div id="warp2">
  <iframe id="iframe2"></iframe>
</div>

Giả sử tôi muốn di chuyển các kết thúc sao cho #wrap2có trước #wrap1. Các iframe bị ô nhiễm bởi JavaScript. Tôi biết về jQuery .insertAfter().insertBefore(). Tuy nhiên, khi tôi sử dụng chúng, iFrame sẽ mất tất cả HTML và các biến và sự kiện JavaScript.

Giả sử sau đây là HTML của iFrame:

<html>
  <head>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript">
      // The variable below would change on click
      // This represents changes on variables after the code is loaded
      // These changes should remain after the iFrame is moved
      variableThatChanges = false;
      $(function(){
        $("body").click(function(){ 
          variableThatChanges = true; 
        });
      });
    </script>
  </head>
  <body>
    <div id='anything'>Illustrative Example</div>
  </body>
</html>

Trong đoạn mã trên, biến variableThatChangessẽ ... thay đổi nếu người dùng nhấp vào nội dung. Biến này và sự kiện nhấp chuột sẽ vẫn còn sau khi iFrame được di chuyển (cùng với bất kỳ biến / sự kiện nào khác đã được bắt đầu)

Câu hỏi của tôi là như sau: với JavaScript (có hoặc không có jQuery), làm cách nào tôi có thể di chuyển các nút bọc trong DOM (và các nút con iframe của chúng) để cửa sổ của iFrame vẫn giữ nguyên và các sự kiện / biến / v.v. của iFrame vẫn giữ nguyên tương tự?



Lỗi hiện tại được nâng lên với Mozilla ... bugzilla.mozilla.org/show_bug.cgi?id=254144
Manse vào

@ManseUK: các câu hỏi khác không thực sự giúp ích được gì ... nhưng lỗi khá thú vị.
JCOC611

1
@SalmanA bạn làm cách nào để di chuyển cha mẹ "xung quanh" một đứa trẻ?
djechlin

1
@denodster cách hiệu quả mong muốn trở lại khi tôi mở câu hỏi này là thay đổi thứ tự của danh sách các phần tử, mỗi phần tử có inline-blockmàn hình ... tại thời điểm này, tôi đoán một giải pháp chung chung (hoặc hiệu quả là tuyên bố như vậy là không thể) sẽ là thích hợp nhất, với sự quan tâm của những người khác.
JCOC611

Câu trả lời:


46

Không thể di chuyển iframe từ vị trí này trong dom đến nơi khác mà không tải lại.

Đây là một ví dụ cho thấy rằng ngay cả khi sử dụng JavaScript gốc, iFrames vẫn tải lại: http://jsfiddle.net/pZ23B/

var wrap1 = document.getElementById('wrap1');
var wrap2 = document.getElementById('wrap2');
setTimeout(function(){
    document.getElementsByTagName('body')[0].appendChild(wrap1);
},10000);

4
Chà, nếu iFrames tải lại thì đó không phải là một tùy chọn.
JCOC611

3
Đúng vậy, mục đích của ví dụ là cho thấy rằng ngay cả khi sử dụng JavaScript gốc, iFrames vẫn tải lại.
Kevin B

Thực ra, tôi thực sự không quan tâm đến việc nó có tải lại hay không, vì vị trí của chúng là about:blankgì, nhưng điều tôi quan tâm là làm mất nội dung bên trong khung.
JCOC611

1
nếu nó tải lại, điều đó sẽ khiến nó mất nội dung bên trong iframe. Tôi đoán bạn có thể lấy nội dung bên trong iframe trước khi di chuyển nó bằng jquery, $("#iframeid").contents()tuy nhiên điều đó sẽ không nhận được dữ liệu javascript được lưu trữ, nó sẽ phải được iframe gửi đến trang mẹ. (Hoặc trang mẹ sẽ phải lấy nó từ iframe)
Kevin B

1
DelightedD0D, tiền thưởng được mở bởi @djechlin - "Tôi tự hỏi liệu điều này có còn đúng vào năm 2016 không" để xem có điều gì thay đổi trong 5 năm qua liên quan đến vấn đề này không. Bạn có thể kiểm tra phần tóm tắt trong câu trả lời của tôi về những thay đổi trong những năm này.
Dekel

40

Câu trả lời này có liên quan đến tiền thưởng của @djechlin

Rất nhiều tìm kiếm về thông số kỹ thuật của w3 / dom và không tìm thấy bất kỳ điều gì cuối cùng nói cụ thể rằng iframe nên được tải lại khi di chuyển trong cây DOM, tuy nhiên tôi đã tìm thấy rất nhiều tài liệu tham khảo và nhận xét trong trac / bugzilla / microsoft của webkit về thay đổi hành vi khác nhau trong nhiều năm.

Tôi hy vọng ai đó sẽ tìm thấy bất kỳ điều gì cụ thể liên quan đến vấn đề này, nhưng hiện tại đây là những phát hiện của tôi:

  1. Theo Ryosuke Niwa - "Đó là hành vi được mong đợi".
  2. Có một "iframe ma thuật" ( webkit, 2010 ), nhưng nó đã bị xóa vào năm 2012 .
  3. Theo MS - " tài nguyên iframe được giải phóng khi loại bỏ khỏi DOM ". Khi bạn appendChild(node)của nút hiện có - nút đó nodelần đầu tiên bị xóa khỏi dom.
    Điều thú vị ở đây - IE<=8không tải lại iframe - hành vi này (hơi) mới (kể từ IE>=9).
  4. Theo nhận xét của Hallvord RM Steen , đây là trích dẫn từ thông số kỹ thuật iframe

    Khi phần tử iframe được chèn vào tài liệu có ngữ cảnh duyệt, tác nhân người dùng phải tạo bối cảnh duyệt mới, đặt ngữ cảnh duyệt lồng nhau của phần tử thành ngữ cảnh duyệt mới được tạo, sau đó xử lý thuộc tính iframe cho "lần đầu tiên " .

    Đây là điều gần nhất mà tôi tìm thấy trong thông số kỹ thuật, tuy nhiên nó vẫn yêu cầu một số diễn giải (vì khi chúng tôi di chuyển iframephần tử trong DOM, chúng tôi không thực sự thực hiện đầy đủ remove, ngay cả khi các trình duyệt sử dụng node.removeChildphương pháp này).


7
Sẽ đánh giá cao một câu trả lời từ downvoter với lời giải thích.
Dekel

14

Bất cứ khi nào iframe được thêm vào và có áp dụng thuộc tính src, nó sẽ kích hoạt một hành động tải tương tự như khi tạo thẻ Hình ảnh thông qua JS. Vì vậy, khi bạn xóa và sau đó nối chúng, chúng là các thực thể hoàn toàn mới và chúng làm mới. Nó window.location = window.locationsẽ tải lại một trang như thế nào .

Cách duy nhất tôi biết để định vị lại iframeslà thông qua CSS. Dưới đây là một ví dụ tôi tổng hợp cho thấy một cách để xử lý điều này với flex-box: https://jsfiddle.net/3g73sz3k/15/

Ý tưởng cơ bản là tạo một flex-boxtrình bao bọc và sau đó xác định một thứ tự cụ thể cho các iframe bằng cách sử dụng thuộc tính order trên mỗi trình bao bọc iframe.

<style>
  .container{
    display: flex;
    flex-direction: column;
  }
</style>
<div class="container">
  <div id="wrap1" style="order: 0" class="iframe-wrapper">
    <iframe id="iframe1" src="https://google.com"></iframe>
  </div>
  <div id="warp2" style="order: 1" class="iframe-wrapper">
    <iframe id="iframe2" src="https://bing.com"></iframe>
  </div>
</div>

Như bạn có thể thấy trong JS fiddle, các orderkiểu này nằm trong dòng để đơn giản hóa flipnút, vì vậy hãy xoay iframes.

Tôi tìm nguồn giải pháp từ câu hỏi StackOverflow này: Chỉ hoán đổi vị trí DIV bằng CSS

Hy vọng rằng sẽ giúp.


1
Tiền thưởng cho đoạn đầu tiên và giải thích nó tương tự như img và tạo thực thể mới. không phải là css: P
djechlin

Thật đơn giản và hiệu quả! Cảm ơn bạn rất nhiều!
Stan

8

Nếu bạn đã tạo iFrame trên trang và chỉ cần di chuyển vị trí của nó sau đó, hãy thử phương pháp này:

Nối iFrame vào phần thân và sử dụng chỉ số z cao và trên cùng, bên trái, chiều rộng, chiều cao để đặt iFrame ở nơi bạn muốn.

Ngay cả CSS zoom cũng hoạt động trên body mà không cần tải lại, thật tuyệt vời!

Tôi duy trì hai trạng thái cho "widget" của mình và nó được đưa vào vị trí trong DOM hoặc vào cơ thể bằng phương pháp này.

Điều này rất hữu ích khi nội dung hoặc thư viện khác sẽ làm hỏng hoặc làm mất iFrame của bạn.

BÙM!


5

Thật không may, thuộc parentNodetính của phần tử HTML DOM là chỉ đọc. Tất nhiên, bạn có thể điều chỉnh vị trí của iframe, nhưng bạn không thể thay đổi vị trí của chúng trong DOM và giữ nguyên trạng thái của chúng.

Xem jsfiddle này mà tôi đã tạo để cung cấp một giường thử nghiệm tốt. http://jsfiddle.net/RpHTj/1/

Nhấp vào hộp để chuyển đổi giá trị. Nhấp vào "di chuyển" để chạy javascript.


4

Câu hỏi này khá cũ ... nhưng tôi đã tìm ra cách để di chuyển iframe mà không cần tải lại. Chỉ CSS. Tôi có nhiều iframe với các luồng camera, tôi không thích khi chúng tải lại khi tôi hoán đổi chúng. Vì vậy, tôi đã sử dụng sự kết hợp của float, position: tuyệt đối và một số khối giả để di chuyển chúng xung quanh mà không cần tải lại chúng và có bố cục mong muốn theo yêu cầu (thay đổi kích thước và tất cả).


1
Nghe có vẻ như là lựa chọn khả thi duy nhất. Bạn nên đăng toàn bộ giải pháp mà bạn đã nghĩ ra! Ít nhất một số mã cơ bản để người khác bắt đầu. Cảm ơn!
JCOC611

1

Để trả lời cho tiền thưởng @djechlin được đặt cho câu hỏi này, tôi đã tách jsfiddle được đăng bởi @ matt-h và đã đi đến kết luận rằng điều này vẫn không thể thực hiện được.

http://jsfiddle.net/gr3wo9u6/

//this does not work, the frames reload when appended back to the DOM
function swapFrames() {
    var w1 = document.getElementById('wrap1');
    var w2 = document.getElementById('wrap2');
    var f1 = w1.querySelector('iframe');
    var f2 = w2.querySelector('iframe');

    w1.removeChild(f1);
    w2.removeChild(f2);
    w1.appendChild(f2);
    w2.appendChild(f1);
    //f1.parentNode = w2;
    //f2.parentNode = w1;

    //alert(f1.parentNode.id);
}

0

Nếu bạn đang sử dụng iframe để truy cập các trang bạn kiểm soát, bạn có thể tạo một số javascript để cho phép cha mẹ bạn giao tiếp với iframe qua postMessage

Từ đó, bạn có thể xây dựng thông tin đăng nhập bên trong iframe để ghi lại các thay đổi trạng thái và trước khi chuyển dom, hãy yêu cầu điều đó dưới dạng đối tượng json.

Sau khi di chuyển, iframe sẽ tải lại, bạn có thể chuyển dữ liệu trạng thái vào iframe và việc nghe iframe có thể phân tích cú pháp dữ liệu trở lại trạng thái trước đó.


Cấp, điều này là rất nhiều mã, giả sử bạn kiểm soát tất cả dữ liệu sẽ được hiển thị trong khung hình, và vẫn về mặt kỹ thuật doesnt "duy trì trạng thái khi di chuyển trong DOM"
Drew chính
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.