Bagaimana cara memindahkan iFrame di DOM tanpa kehilangan statusnya?

95

Lihatlah HTML sederhana ini:

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

Katakanlah saya ingin memindahkan wraps sehingga #wrap2akan menjadi sebelum #wrap1. Iframe tercemar oleh JavaScript. Saya tahu tentang jQuery .insertAfter()dan .insertBefore(). Namun, saat saya menggunakannya, iFrame kehilangan semua HTML, variabel, dan peristiwa JavaScript.

Katakanlah berikut ini adalah HTML 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>

Pada kode di atas, variabel variableThatChangesakan ... berubah jika pengguna mengklik body. Variabel ini, dan peristiwa klik, harus tetap ada setelah iFrame dipindahkan (bersama dengan variabel / peristiwa lain yang telah dimulai)

Pertanyaan saya adalah sebagai berikut: dengan JavaScript (dengan atau tanpa jQuery), bagaimana saya bisa memindahkan simpul bungkus di DOM (dan anak iframe mereka) sehingga jendela iFrame tetap sama, dan acara / variabel / dll iFrame tetap sama?

JCOC611
sumber
Ditanyakan sebelumnya (lama sekali) -> stackoverflow.com/questions/2885504/… dan stackoverflow.com/questions/3029871/…
Manse
Bug saat ini diangkat dengan Mozilla ... bugzilla.mozilla.org/show_bug.cgi?id=254144
Manse
@ManseUK: pertanyaan lain tidak terlalu membantu ... tapi bugnya cukup menarik.
JCOC611
1
@SalmanA bagaimana Anda memindahkan orang tua "di sekitar" seorang anak?
djechlin
1
@denodster efek yang diinginkan saat saya membuka pertanyaan ini adalah mengubah urutan daftar elemen, masing-masing dengan inline-blocktampilan ... pada titik ini, saya menebak solusi umum (atau secara efektif pernyataan bahwa itu tidak mungkin) akan menjadi yang paling tepat, mengingat minat orang lain.
JCOC611

Jawaban:

46

Tidak mungkin memindahkan iframe dari satu tempat di dom ke tempat lain tanpa memuat ulang.

Berikut adalah contoh yang menunjukkan bahwa meskipun menggunakan JavaScript asli, iFrame masih memuat ulang: http://jsfiddle.net/pZ23B/

var wrap1 = document.getElementById('wrap1');
var wrap2 = document.getElementById('wrap2');
setTimeout(function(){
    document.getElementsByTagName('body')[0].appendChild(wrap1);
},10000);
Kevin B
sumber
4
Nah, jika iFrames dimuat ulang maka itu bukan pilihan.
JCOC611
3
Benar, tujuan contoh ini adalah untuk menunjukkan bahwa bahkan menggunakan JavaScript asli, iFrames masih memuat ulang.
Kevin B
Sebenarnya, saya benar-benar tidak peduli apakah itu memuat ulang atau tidak, karena lokasinya about:blank, tetapi yang saya pedulikan adalah kehilangan konten di dalam bingkai.
JCOC611
1
jika dimuat ulang, itu akan menyebabkan kehilangan konten di dalam iframe. Saya kira Anda bisa mengambil konten di dalam iframe sebelum memindahkannya menggunakan jquery $("#iframeid").contents()namun itu tidak akan mendapatkan data javascript yang tersimpan, itu harus dikirim ke halaman induk oleh iframe. (Atau halaman induk harus mengambilnya dari iframe)
Kevin B
1
DelightedD0D, bounty dibuka oleh @djechlin - "Saya ingin tahu apakah ini masih berlaku di tahun 2016" untuk melihat apakah ada yang berubah dalam 5 tahun terakhir terkait masalah ini. Anda dapat memeriksa ringkasan di jawaban saya mengenai perubahan selama tahun-tahun ini.
Dekel
41

Jawaban ini terkait dengan bounty oleh @djechlin

Banyak pencarian di spesifikasi w3 / dom dan tidak menemukan sesuatu yang final yang secara khusus mengatakan bahwa iframe harus dimuat ulang saat bergerak di pohon DOM, namun saya menemukan banyak referensi dan komentar di trac / bugzilla / microsoft webkit tentang perubahan perilaku yang berbeda selama bertahun-tahun.

Saya berharap seseorang akan menemukan sesuatu yang spesifik tentang masalah ini, tetapi untuk saat ini inilah temuan saya:

  1. Menurut Ryosuke Niwa - "Itulah perilaku yang diharapkan".
  2. Ada "iframe ajaib" ( webkit, 2010 ), tapi dihapus pada 2012 .
  3. Menurut MS - " sumber daya iframe dibebaskan saat dihapus dari DOM ". Ketika Anda appendChild(node)dari node yang ada - yang nodepertama dihapus dari dom.
    Hal yang menarik di sini - IE<=8tidak memuat ulang iframe - perilaku ini (agak) baru (sejak IE>=9).
  4. Menurut komentar Hallvord RM Steen , ini adalah kutipan dari spesifikasi iframe

    Saat elemen iframe dimasukkan ke dalam dokumen yang memiliki konteks penelusuran, agen pengguna harus membuat konteks penelusuran baru, menyetel konteks penelusuran bertingkat elemen tersebut ke konteks penelusuran yang baru dibuat, lalu memproses atribut iframe untuk "pertama kali. " .

    Ini adalah hal paling dekat yang saya temukan di spesifikasi, namun masih memerlukan beberapa interpretasi (karena ketika kita memindahkan iframeelemen di DOM kita tidak benar-benar melakukan sepenuhnya remove, bahkan jika browser menggunakan node.removeChildmetode tersebut).

Dekel
sumber
7
Akan menghargai balasan dari downvoter dengan penjelasan.
Dekel
14

Setiap kali iframe ditambahkan dan memiliki atribut src yang diterapkan, itu mengaktifkan tindakan pemuatan yang mirip dengan saat membuat tag Gambar melalui JS. Jadi, saat Anda menghapus dan menambahkannya, mereka adalah entitas yang benar-benar baru dan menyegarkan. Ini semacam bagaimana window.location = window.locationakan memuat ulang halaman.

Satu-satunya cara yang saya tahu untuk memposisikan ulang iframesadalah melalui CSS. Berikut adalah contoh yang saya kumpulkan untuk menunjukkan satu cara untuk menangani ini dengan flex-box: https://jsfiddle.net/3g73sz3k/15/

Ide dasarnya adalah membuat flex-boxpembungkus dan kemudian menentukan urutan khusus untuk iframe menggunakan atribut pesanan pada setiap pembungkus 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>

Seperti yang Anda lihat di biola JS, ordergaya ini sejajar untuk menyederhanakan fliptombol jadi putar iframes.

Saya mengambil solusi dari pertanyaan StackOverflow ini: Tukar posisi DIV dengan CSS saja

Semoga membantu.

PaulSCoder
sumber
1
Bounty untuk paragraf pertama dan menjelaskannya mirip dengan img dan membuat entitas baru. bukan css: P
djechlin
Sangat sederhana dan efektif! Terima kasih banyak!
Stan
8

Jika Anda telah membuat iFrame di halaman dan hanya perlu memindahkan posisinya nanti, coba pendekatan ini:

Tambahkan iFrame ke badan dan gunakan indeks-z tinggi dan atas, kiri, lebar, tinggi untuk meletakkan iFrame di tempat yang Anda inginkan.

Bahkan zoom CSS bekerja pada tubuh tanpa memuat ulang yang luar biasa!

Saya mempertahankan dua status untuk "widget" saya dan itu disuntikkan di tempat di DOM atau ke tubuh menggunakan metode ini.

Ini berguna ketika konten atau pustaka lain akan menekan atau menekan iFrame Anda.

LEDAKAN!

mattdlockyer
sumber
5

Sayangnya, parentNodeproperti elemen HTML DOM bersifat hanya baca. Anda tentu saja dapat menyesuaikan posisi iframe, tetapi Anda tidak dapat mengubah lokasinya di DOM dan mempertahankan statusnya.

Lihat jsfiddle yang saya buat yang menyediakan test bed yang bagus. http://jsfiddle.net/RpHTj/1/

Klik pada kotak untuk mengubah nilainya. Klik pada "pindah" untuk menjalankan javascript.

Matt H.
sumber
4

Pertanyaan ini cukup lama ... tetapi saya menemukan cara untuk memindahkan iframe tanpa memuat ulang. Hanya CSS. Saya memiliki banyak iframe dengan aliran kamera, saya tidak suka ketika mereka memuat ulang ketika saya menukarnya. Jadi saya menggunakan kombinasi float, position: absolute, dan beberapa dummy blok untuk memindahkannya tanpa memuat ulang dan memiliki tata letak yang diinginkan sesuai permintaan (mengubah ukuran dan semuanya).

moeiscool
sumber
1
Kedengarannya seperti satu-satunya opsi yang layak. Anda harus memposting solusi lengkap yang Anda dapatkan! Setidaknya beberapa kode dasar untuk memulai orang lain. Terima kasih!
JCOC611
1

Menanggapi bounty @djechlin yang ditempatkan pada pertanyaan ini, saya telah mengubah jsfiddle yang diposting oleh @ matt-h dan sampai pada kesimpulan bahwa ini masih tidak mungkin.

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);
}
denodster
sumber
0

Jika Anda menggunakan iframe untuk mengakses halaman yang Anda kontrol, Anda dapat membuat beberapa javascript agar orang tua Anda dapat berkomunikasi dengan iframe melalui postMessage

Dari sana, Anda bisa membuat login di dalam iframe untuk merekam perubahan status, dan sebelum memindahkan dom, memintanya sebagai objek json.

Setelah dipindahkan, iframe akan dimuat ulang, Anda dapat meneruskan data status ke iframe dan mendengarkan iframe dapat mengurai data kembali ke status sebelumnya.

Drew Mayor
sumber
Memang, ini banyak kode, menganggap Anda mengontrol semua data yang akan ditampilkan dalam bingkai, dan secara teknis masih tidak "mempertahankan keadaan saat bergerak di DOM"
Drew Major