จะย้าย iFrame ใน DOM โดยไม่สูญเสียสถานะได้อย่างไร


95

ดู HTML ง่ายๆนี้:

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

สมมติว่าฉันต้องการย้ายการห่อเพื่อให้#wrap2อยู่ก่อนหน้า#wrap1. iframe ถูกทำให้เสียโดย JavaScript ฉันตระหนักถึง jQuery .insertAfter()และ.insertBefore(). อย่างไรก็ตามเมื่อฉันใช้สิ่งเหล่านี้ iFrame จะสูญเสียตัวแปร HTML และ JavaScript และเหตุการณ์ทั้งหมด

ให้บอกว่าต่อไปนี้เป็น 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>

ในโค้ดด้านบนตัวแปรvariableThatChangesจะ ... เปลี่ยนหากผู้ใช้คลิกที่เนื้อหา ตัวแปรนี้และเหตุการณ์การคลิกควรจะยังคงอยู่หลังจากที่ย้าย iFrame แล้ว (พร้อมกับตัวแปร / เหตุการณ์อื่น ๆ ที่เริ่มทำงาน)

คำถามของฉันมีดังต่อไปนี้: ด้วย JavaScript (มีหรือไม่มี jQuery) ฉันจะย้ายโหนดตัดใน DOM (และลูกของ iframe) ได้อย่างไรเพื่อให้หน้าต่างของ iFrame ยังคงเหมือนเดิมและเหตุการณ์ / ตัวแปร / ฯลฯ ของ iFrame จะยังคงอยู่ เหมือนกัน?


ถามก่อน (นานแล้ว) -> stackoverflow.com/questions/2885504/…และstackoverflow.com/questions/3029871/…
เซ

บั๊กปัจจุบันถูกเลี้ยงด้วย Mozilla ... bugzilla.mozilla.org/show_bug.cgi?id=254144
Manse

@ManseUK: คำถามอื่น ๆ ไม่ได้ช่วยจริงๆ ... แต่ข้อผิดพลาดค่อนข้างน่าสนใจ
JCOC611

1
@SalmanA คุณจะย้ายผู้ปกครอง "รอบ" เด็กได้อย่างไร?
djechlin

1
@denodster วิธีที่ต้องการกลับมาเมื่อฉันเปิดคำถามนี้คือการเปลี่ยนลำดับของรายการองค์ประกอบแต่ละรายการที่มีการinline-blockแสดงผล ... ณ จุดนี้ฉันกำลังเดาวิธีแก้ปัญหาทั่วไป (หรือมีประสิทธิภาพในการบอกว่าเป็นไปไม่ได้) จะเหมาะสมที่สุดโดยให้ความสนใจจากผู้อื่น
JCOC611

คำตอบ:


46

เป็นไปไม่ได้ที่จะย้าย iframe จากที่หนึ่งในโดมไปยังอีกที่หนึ่งโดยไม่ต้องโหลดซ้ำ

นี่คือตัวอย่างที่แสดงให้เห็นว่าแม้จะใช้ JavaScript ดั้งเดิม iFrames ก็ยังโหลดซ้ำ: http://jsfiddle.net/pZ23B/

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

4
ถ้า iFrames โหลดซ้ำแสดงว่าไม่ใช่ตัวเลือก
JCOC611

3
ถูกต้องจุดประสงค์ของตัวอย่างคือการแสดงให้เห็นว่าแม้จะใช้ JavaScript ดั้งเดิม แต่ iFrames ก็ยังโหลดซ้ำ
Kevin B

ที่จริงแล้วฉันไม่สนใจจริงๆว่ามันจะโหลดซ้ำหรือไม่เนื่องจากตำแหน่งของมันอยู่about:blankแต่สิ่งที่ฉันสนใจคือการสูญเสียเนื้อหาภายในเฟรม
JCOC611

1
หากโหลดซ้ำจะทำให้สูญเสียเนื้อหาภายใน iframe ฉันเดาว่าคุณสามารถคว้าเนื้อหาภายใน iframe ได้ก่อนที่จะย้ายโดยใช้ jquery $("#iframeid").contents()แต่จะไม่ได้รับข้อมูลจาวาสคริปต์ที่เก็บไว้มันจะต้องถูกส่งไปยังเพจหลักโดย iframe (หรือเพจหลักจะต้องดึงจาก iframe)
Kevin B

1
DelightedD0D @djechlin - "ฉันสงสัยว่ายังคงเป็นจริงในปี 2016" เพื่อดูว่ามีอะไรเปลี่ยนแปลงใน 5 ปีที่ผ่านมาเกี่ยวกับปัญหานี้หรือไม่ คุณสามารถตรวจสอบสรุปในคำตอบของฉันเกี่ยวกับการเปลี่ยนแปลงในช่วงหลายปีนี้
Dekel

41

คำตอบนี้เกี่ยวข้องกับรางวัลโดย @djechlin

การค้นหาจำนวนมากเกี่ยวกับข้อกำหนด w3 / dom และไม่พบสิ่งใดขั้นสุดท้ายที่ระบุว่าควรโหลด iframe ใหม่โดยเฉพาะในขณะที่ย้ายในโครงสร้าง DOM อย่างไรก็ตามฉันพบการอ้างอิงและความคิดเห็นมากมายใน trac / bugzilla / microsoft ของ webkit การเปลี่ยนแปลงพฤติกรรมที่แตกต่างกันในช่วงหลายปีที่ผ่านมา

ฉันหวังว่าใครบางคนจะพบอะไรที่เฉพาะเจาะจงเกี่ยวกับปัญหานี้ แต่สำหรับตอนนี้นี่คือสิ่งที่ฉันค้นพบ:

  1. อ้างอิงจากRyosuke Niwa - "นั่นคือพฤติกรรมที่คาดหวัง"
  2. มี "iframe วิเศษ" (เป็นWebKit 2010 ) แต่มันก็ถูกลบออกในปี 2012
  3. ตาม MS - " ทรัพยากร iframe จะเป็นอิสระเมื่อถูกลบออกจาก DOM " เมื่อคุณappendChild(node)ของโหนดที่มีอยู่ - สิ่งนั้นnodeจะถูกลบออกจากโดมก่อน
    สิ่งที่น่าสนใจที่นี่ - IE<=8ไม่ได้โหลด iframe ใหม่ - พฤติกรรมนี้ (ค่อนข้าง) ใหม่ (ตั้งแต่IE>=9)
  4. ตามความคิดเห็นของHallvord RM Steenนี่คือคำพูดจากข้อกำหนดของ iframe

    เมื่อองค์ประกอบ iframe ถูกแทรกลงในเอกสารที่มีบริบทการสืบค้นตัวแทนผู้ใช้จะต้องสร้างบริบทการสืบค้นใหม่ตั้งค่าบริบทการสืบค้นที่ซ้อนกันขององค์ประกอบเป็นบริบทการสืบค้นที่สร้างขึ้นใหม่จากนั้นประมวลผลแอตทริบิวต์ iframe สำหรับ "ครั้งแรก " .

    นี่เป็นสิ่งที่ใกล้เคียงที่สุดที่ฉันพบในข้อกำหนด แต่ก็ยังต้องมีการตีความบางอย่าง (เนื่องจากเมื่อเราย้ายiframeองค์ประกอบใน DOM เราไม่ได้ทำเต็มรูปแบบremoveแม้ว่าเบราว์เซอร์จะใช้node.removeChildวิธีนี้ก็ตาม)


7
จะขอบคุณการตอบกลับจากผู้โหวตพร้อมคำอธิบาย
Dekel

14

เมื่อใดก็ตามที่มีการต่อท้าย iframe และมีการใช้แอตทริบิวต์ src มันจะเริ่มการทำงานของโหลดเหมือนกับเมื่อสร้างแท็กรูปภาพผ่าน JS ดังนั้นเมื่อคุณลบแล้วต่อท้ายพวกเขาจะเป็นเอนทิตีใหม่ทั้งหมดและรีเฟรช ประเภทของวิธีการwindow.location = window.locationโหลดหน้าเว็บซ้ำ

วิธีเดียวที่ฉันรู้ในการเปลี่ยนตำแหน่งiframesคือผ่าน CSS นี่คือตัวอย่างที่ฉันรวบรวมซึ่งแสดงวิธีหนึ่งในการจัดการกับสิ่งนี้flex-box: https://jsfiddle.net/3g73sz3k/15/

แนวคิดพื้นฐานคือการสร้างflex-boxWrapper จากนั้นกำหนดลำดับที่เฉพาะเจาะจงสำหรับ iframe โดยใช้แอตทริบิวต์คำสั่งซื้อในแต่ละ iframe wrapper

<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 fiddle orderรูปแบบเหล่านี้เป็นแบบอินไลน์เพื่อลดความซับซ้อนของflipปุ่มดังนั้นให้หมุนไฟล์iframes.

ฉันหาวิธีแก้ปัญหาจากคำถาม StackOverflow นี้: สลับตำแหน่ง DIV กับ CSS เท่านั้น

หวังว่าจะช่วยได้


1
ค่าหัวสำหรับย่อหน้าที่ 1 และอธิบายว่าคล้ายกับ img และสร้างเอนทิตีใหม่ ไม่ใช่ css: P
djechlin

ง่ายและมีประสิทธิภาพ! ขอบคุณมาก!
สแตน

8

หากคุณสร้าง iFrame บนเพจและต้องการย้ายตำแหน่งในภายหลังให้ลองใช้วิธีนี้:

ต่อท้าย iFrame เข้ากับเนื้อหาและใช้ดัชนี z สูงและด้านบนซ้ายความกว้างความสูงเพื่อวาง iFrame ในที่ที่คุณต้องการ

แม้แต่การซูม CSS ก็ทำงานบนร่างกายโดยไม่ต้องโหลดซ้ำซึ่งยอดเยี่ยมมาก!

ฉันรักษาสองสถานะสำหรับ "วิดเจ็ต" ของฉันและอาจถูกฉีดเข้าไปใน DOM หรือในร่างกายโดยใช้วิธีนี้

สิ่งนี้มีประโยชน์เมื่อเนื้อหาหรือไลบรารีอื่น ๆ จะบีบอัด iFrame ของคุณ

บูม!


5

น่าเสียดายที่parentNodeคุณสมบัติขององค์ประกอบ HTML DOM เป็นแบบอ่านอย่างเดียว แน่นอนคุณสามารถปรับตำแหน่งของ iframe ได้ แต่คุณไม่สามารถเปลี่ยนตำแหน่งใน DOM และรักษาสถานะไว้ได้

ดู jsfiddle ที่ฉันสร้างขึ้นซึ่งเป็นเตียงทดสอบที่ดี http://jsfiddle.net/RpHTj/1/

คลิกที่ช่องเพื่อสลับค่า คลิกที่ "ย้าย" เพื่อเรียกใช้จาวาสคริปต์


4

คำถามนี้ค่อนข้างเก่า ... แต่ฉันพบวิธีย้าย iframe โดยไม่ต้องโหลดซ้ำ CSS เท่านั้น ฉันมี iframe หลายอันพร้อมสตรีมกล้องฉันไม่ชอบเวลาที่มันโหลดซ้ำเมื่อฉันสลับมัน ดังนั้นฉันจึงใช้การรวมกันของ float, position: absolute และ dummy block เพื่อย้ายไปรอบ ๆ โดยไม่ต้องโหลดซ้ำและมีเค้าโครงที่ต้องการตามต้องการ (ปรับขนาดและทั้งหมด)


1
ดูเหมือนเป็นทางเลือกเดียวที่ใช้งานได้ คุณควรโพสต์วิธีแก้ปัญหาทั้งหมดที่คุณคิด! อย่างน้อยก็มีโค้ดพื้นฐานเพื่อให้คนอื่นเริ่มต้น ขอบคุณ!
JCOC611

1

เพื่อตอบสนองต่อค่าหัวที่ @djechlin วางไว้ในคำถามนี้ฉันได้แยก jsfiddle ที่โพสต์โดย @ matt-h และได้ข้อสรุปว่ายังไม่สามารถทำได้

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

หากคุณใช้ iframe เพื่อเข้าถึงเพจที่คุณควบคุมคุณสามารถสร้างจาวาสคริปต์เพื่ออนุญาตให้ผู้ปกครองของคุณสื่อสารกับ iframe ผ่าน postMessage

จากนั้นคุณสามารถสร้างล็อกอินภายใน iframe เพื่อบันทึกการเปลี่ยนแปลงสถานะและก่อนที่จะย้าย dom ขอให้เป็นอ็อบเจกต์ json

เมื่อย้ายแล้ว iframe จะโหลดซ้ำคุณสามารถส่งข้อมูลสถานะไปยัง iframe และการฟัง iframe สามารถแยกวิเคราะห์ข้อมูลกลับไปสู่สถานะก่อนหน้าได้


จริงอยู่ว่านี่เป็นรหัสจำนวนมากโดยถือว่าคุณควบคุมข้อมูลทั้งหมดที่จะแสดงในเฟรมและในทางเทคนิคก็ยังไม่ "คงสถานะเมื่อย้ายใน DOM"
Drew Major
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.