Як перемістити iFrame в DOM, не втрачаючи його стану?


93

Погляньте на цей простий HTML:

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

Скажімо, я хотів перенести обгортання так, щоб це #wrap2було до #wrap1. Вбудовані рамки забруднені 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/…
Manse

Поточна помилка піднята за допомогою 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()однак це не призведе до збережених даних javascript, його потрібно було б відправити на батьківську сторінку iframe. (Або батьківській сторінці довелося б захопити його з the iframe)
Кевін Б

1
РадийD0D, нагороду відкрив @djechlin - "Цікаво, чи це все ще відповідає дійсності у 2016 році", щоб побачити, чи щось змінилося за останні 5 років щодо цього питання. Ви можете переглянути резюме в моїй відповіді щодо змін за ці роки.
Декель

40

Ця відповідь пов'язана з щедрістю @djechlin

Багато пошуків за специфікаціями w3 / dom не знайшов нічого остаточного, що конкретно говорить про те, що iframe слід перезавантажувати під час переміщення по дереву DOM, однак я знайшов багато посилань та коментарів у trac / bugzilla / microsoft webkit щодо різні зміни поведінки протягом багатьох років.

Сподіваюсь, хтось знайде щось конкретне щодо цього питання, але наразі ось мої висновки:

  1. За словами Рйосуке Ніва - "Це очікувана поведінка".
  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
Будемо вдячні за відповідь голосуючих із поясненнями.
Декель

14

Щоразу, коли додається iframe і застосовується атрибут src, він запускає дію завантаження подібно до створення тегу Image за допомогою JS. Отже, коли ви видаляєте, а потім додаєте їх, це абсолютно нові сутності, і вони оновлюються. Це такий спосіб window.location = window.locationперезавантаження сторінки.

Єдиний спосіб перестановки iframes- це CSS. Ось приклад, який я зібрав, показуючи один із способів вирішити це flex-box: https://jsfiddle.net/3g73sz3k/15/

Основна ідея - створити flex-boxобгортку, а потім визначити конкретний порядок для фреймів, використовуючи атрибут order на кожній обгортці 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>

Як ви можете бачити в скрипці JS, ці orderстилі вбудовані для спрощення flipкнопки, тому обертайте iframes.

Я отримав рішення з цього питання StackOverflow: поміняйте позицію DIV лише на CSS

Сподіваюся, це допомагає.


1
Баунті за 1-й абзац та пояснення його подібності до img та створення нової сутності. not the css: P
djechlin

Такий простий та ефективний! Щиро дякую!
Стен

8

Якщо ви створили iFrame на сторінці і вам просто потрібно перемістити його позицію пізніше, спробуйте такий підхід:

Додайте iFrame до корпусу та використовуйте високий z-індекс та верхню, ліву, ширину та висоту, щоб поставити iFrame туди, де ви хочете.

Навіть масштабування CSS працює на тілі без перезавантаження, що чудово!

Я підтримую два стани для свого "віджета", і він або вводиться на місце в DOM, або в тіло, використовуючи цей метод.

Це корисно, коли інший вміст або бібліотеки стискають або стискають ваш iFrame.

БУМ!


5

На жаль, parentNodeвластивість елемента HTML DOM доступна лише для читання. Звичайно, ви можете налаштувати положення фреймів, але ви не можете змінити їх розташування в DOM і зберегти їх стан.

Дивіться цей jsfiddle, який я створив, який забезпечує хороший тест. http://jsfiddle.net/RpHTj/1/

Клацніть на поле, щоб змінити значення. Клацніть на "перемістити", щоб запустити javascript.


4

Це питання досить давнє ... але я знайшов спосіб перемістити iframe без його перезавантаження. Тільки CSS. У мене є кілька фреймів з потоками камер, мені не подобається, коли вони перезавантажуються, коли я їх міняю місцями. Тому я використав комбінацію float, position: absolute та деякі фіктивні блоки, щоб переміщати їх, не перезавантажуючи та не маючи бажаного макету на вимогу (зміна розміру та все).


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 для доступу до контрольованих вами сторінок, ви можете створити деякий javascript, щоб дозволити вашим батькам спілкуватися з iframe через postMessage

Звідти ви можете побудувати логін усередині iframe, щоб записати зміни стану, і перед переміщенням dom попросіть це як об’єкт json.

Після переміщення iframe перезавантажиться, ви зможете передати дані стану в iframe, а прослуховування iframe може проаналізувати дані назад у попередній стан.


Звичайно, це багато коду, передбачає, що ви контролюєте всі дані, які будуть відображатися у кадрі, і все ще технічно не "підтримує стан під час переміщення в DOM"
Drew Major
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.