Bir iFrame, durumunu kaybetmeden DOM içinde nasıl taşınır?


95

Bu basit HTML'ye bir göz atın:

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

Diyelim ki, sarmalları. 'Dan #wrap2önce olacak şekilde taşımak istedim #wrap1. İç çerçeveler JavaScript ile kirlenmiştir. JQuery'nin .insertAfter()ve .insertBefore(). Ancak, bunları kullandığımda, iFrame tüm HTML ve JavaScript değişkenlerini ve olaylarını kaybediyor.

Aşağıdakinin iFrame'in HTML'si olduğunu varsayalım:

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

Yukarıdaki kodda, değişken variableThatChanges... kullanıcı gövdeye tıklarsa değişirdi. Bu değişken ve tıklama olayı, iFrame taşındıktan sonra kalmalıdır (başlatılan diğer değişkenler / olaylarla birlikte)

Sorum şu: JavaScript ile (jQuery ile veya jQuery olmadan), iFrame'in penceresi aynı kalacak ve iFrame'in olayları / değişkenleri / vb. aynı?



Mozilla ile ortaya çıkan Güncel Hata ... bugzilla.mozilla.org/show_bug.cgi?id=254144
Manse

@ManseUK: Diğer sorular gerçekten yardımcı olmadı ... ama hata oldukça ilginç.
JCOC611

1
@SalmanA Bir ebeveyni bir çocuğu "etrafında" nasıl hareket ettirirsiniz?
djechlin

1
@denodster, bu soruyu açtığımda istediğim etki, her biri inline-blockgörüntülü bir öğe listesinin sırasını değiştirmekti ... bu noktada, genel bir çözüm (veya etkin bir şekilde bunun imkansız olduğu ifadesi) tahmin ediyorum başkalarının ilgisi göz önüne alındığında en uygun olanıdır.
JCOC611

Yanıtlar:


46

Yeniden yüklemeden bir iframe'i dom içindeki bir yerden başka bir yere taşımak mümkün değildir.

İşte yerel JavaScript kullanıldığında bile iFrame'lerin hala yeniden yüklendiğini gösteren bir örnek: http://jsfiddle.net/pZ23B/

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

4
İFrame'ler yeniden yüklenirse, bu bir seçenek değildir.
JCOC611

3
Doğru, örneğin amacı, yerel JavaScript kullanıldığında bile iFrame'lerin hala yeniden yüklendiğini göstermektir.
Kevin B

Aslında, yeniden yüklenip yüklenmemesi umrumda değil, çünkü yerleri olduğu için about:blank, ama benim önemsediğim şey çerçevenin içindeki içeriği kaybetmek.
JCOC611

1
yeniden yüklenirse, iframe içindeki içeriği kaybetmesine neden olur. Sanırım jquery kullanarak onu taşımadan önce iframe içindeki içerikleri yakalayabilirsiniz, $("#iframeid").contents()ancak bu javascript verilerini saklamaz, iframe tarafından üst sayfaya gönderilmesi gerekir. iframe)
Kevin B

1
DelightedD0D, ödül @djechlin tarafından açıldı - Bu konuyla ilgili son 5 yılda herhangi bir değişiklik olup olmadığını görmek için "Bunun 2016'da hala doğru olup olmadığını merak ediyorum". Bu yıllardaki değişikliklerle ilgili cevabımdaki özete bakabilirsiniz.
Dekel

41

Bu cevap @djechlin'in ödülü ile ilgilidir.

W3 / dom özelliklerinde çok fazla arama yapıldı ve özellikle iframe'in DOM ağacında taşınırken yeniden yüklenmesi gerektiğini söyleyen nihai bir şey bulamadım, ancak webkit'in trac / bugzilla / microsoft'unda ilgili birçok referans ve yorum buldum. yıllar içinde farklı davranış değişiklikleri.

Umarım birisi bu konuyla ilgili belirli bir şey bulur, ancak şimdilik bulgularım:

  1. Ryosuke Niwa'ya göre - "Beklenen davranış budur".
  2. Bir "sihirli iframe" vardı ( webkit, 2010 ), ancak 2012'de kaldırıldı .
  3. MS'e göre - " iframe kaynakları DOM'den kaldırıldığında serbest bırakılır ". appendChild(node)Mevcut düğümün sizde olduğu zaman - bu nodeilk olarak dom'dan kaldırılır.
    Burada ilginç olan şey - IE<=8iframe'i yeniden yüklemedi - bu davranış (biraz) yeni (beri IE>=9).
  4. Göre Hallvord RM Steen açıklama, bu bir alıntı iframe özellikleri

    Göz atma bağlamı olan bir belgeye bir iframe öğesi eklendiğinde, kullanıcı aracısı yeni bir göz atma bağlamı oluşturmalı, öğenin yuvalanmış göz atma bağlamını yeni oluşturulan göz atma bağlamına ayarlamalı ve ardından iframe niteliklerini "ilk kez " .

    Bu, özelliklerde bulduğum en yakın şey, ancak yine de biraz yorumlanması gerekiyor (çünkü iframeöğeyi DOM'da taşıdığımızda remove, tarayıcılar node.removeChildyöntemi kullansa bile, gerçekten tam olarak yapmıyoruz ).


7
Olumsuz oy verenin açıklamalı bir cevabını takdir edecektir.
Dekel

14

Bir iframe eklendiğinde ve src özniteliği uygulandığında, JS aracılığıyla bir Resim etiketi oluşturmaya benzer şekilde bir yükleme eylemi tetikler. Dolayısıyla, onları kaldırıp sonra eklediğinizde, bunlar tamamen yeni varlıklardır ve yenilenirler. window.location = window.locationBir sayfanın nasıl yeniden yükleneceği.

Yeniden konumlandırmayı bildiğim tek yol iframesCSS aracılığıyla. İşte bunu halletmenin bir yolunu gösteren bir araya getirdiğim örnek flex-box: https://jsfiddle.net/3g73sz3k/15/

Temel fikir, bir flex-boxsarmalayıcı oluşturmak ve ardından her bir iframe sarmalayıcısındaki order özniteliğini kullanarak iframe'ler için belirli bir sıralama tanımlamaktır.

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

JS kemanında görebileceğiniz gibi, bu orderstiller flipdüğmeyi basitleştirmek için satır içindedir, bu nedenle iframes.

Çözümü şu StackOverflow sorusundan aldım: DIV konumunu yalnızca CSS ile değiştirin

Umarım yardımcı olur.


1
1. paragraf için ödül ve img'ye benzediğini ve yeni varlık yarattığını açıklıyor. not the css: P
djechlin

Çok basit ve etkili! Çok teşekkür ederim!
Stan

8

İFrame'i sayfada oluşturduysanız ve yalnızca konumunu taşımanız gerekiyorsa daha sonra şu yaklaşımı deneyin:

İFrame'i gövdeye ekleyin ve iFrame'i istediğiniz yere yerleştirmek için yüksek bir z-endeksi ve üst, sol, genişlik, yükseklik kullanın.

CSS yakınlaştırma bile vücutta yeniden yüklenmeden çalışır, bu harika!

"Widget" için iki durum sürdürüyorum ve bu yöntem kullanılarak ya DOM'da yerinde ya da gövdeye yerleştiriliyor.

Bu, diğer içerik veya kitaplıklar iFrame'inizi ezecek veya ezecekse kullanışlıdır.

BOOM!


5

Ne yazık ki, parentNodebir HTML DOM öğesinin özelliği salt okunurdur. Elbette iç çerçevelerin konumlarını ayarlayabilirsiniz, ancak bunların DOM'daki konumlarını değiştiremez ve durumlarını koruyamazsınız.

İyi bir test yatağı sağlayan bu jsfiddle'a bakın. http://jsfiddle.net/RpHTj/1/

Değeri değiştirmek için kutuyu tıklayın. Javascript'i çalıştırmak için "taşı" üzerine tıklayın.


4

Bu soru oldukça eski ... ama bir iframe'i yeniden yüklemeden hareket ettirmenin bir yolunu buldum. Yalnızca CSS. Kamera akışları olan birden fazla iframe'im var, onları değiştirdiğimde yeniden yüklenmelerini sevmiyorum. Bu yüzden onları yeniden yüklemeden ve talep üzerine istenen düzene sahip (yeniden boyutlandırma ve tümü) hareket ettirmek için float, position: absolute ve bazı kukla blokların bir kombinasyonunu kullandım.


1
Tek geçerli seçenek gibi görünüyor. Bulduğunuz tam çözümü yayınlamalısınız! Başkalarını başlatmak için en azından bazı temel kodlar. Teşekkürler!
JCOC611

1

Bu soruya verilen @djechlin ödülüne yanıt olarak, @ matt-h tarafından gönderilen jsfiddle'ı çatalladım ve bunun hala mümkün olmadığı sonucuna vardım.

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

Kontrol ettiğiniz sayfalara erişmek için iframe kullanıyorsanız, ebeveyninizin iframe ile postMessage aracılığıyla iletişim kurmasına izin vermek için bir miktar javascript oluşturabilirsiniz.

Oradan, durum değişikliklerini kaydetmek için iframe içinde oturum açabilir ve dom'u taşımadan önce bunu bir json nesnesi olarak isteyebilirsiniz.

Taşındıktan sonra iframe yeniden yüklenir, durum verilerini iframe'e aktarabilirsiniz ve dinleyen iframe verileri önceki duruma geri ayrıştırabilir.


Verilmiş, bu çok fazla kod, çerçeve içinde görüntülenecek tüm verileri kontrol ettiğinizi ve teknik olarak hala "DOM'da taşınırken durumu korumadığını" varsayar
Drew Major
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.