Как переместить iFrame в DOM без потери его состояния?


взгляните на этот простой 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 будет...изменить, если пользователь нажал на тело. Эта переменная и событие click должны оставаться после перемещения iFrame (наряду с любыми другими переменными / событиями, которые были запущены)

мой вопрос заключается в следующем: с JavaScript (с jQuery или без него), как я могу переместить узлы обертки в DOM (и их дочерние элементы iframe), чтобы окно iFrame оставалось прежним, а события/переменные/etc iFrame оставались прежними?

8 76

8 ответов:

невозможно переместить iframe из одного места в dom в другое без его перезагрузки.

вот пример, чтобы показать, что даже с помощью собственного 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);

этот ответ связан с щедростью @djechlin

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

Я надеюсь, что кто-то найдет что-то конкретное по этому вопросу, но пока вот мои выводы:

  1. по данным Риосуке Нива - "это ожидаемое поведение".
  2. был "волшебный iframe" (webkit, 2010), но это было удалено в 2012 году.
  3. согласно MS -"ресурсы iframe освобождаются при удалении из DOM". Когда ты appendChild(node) существующего узла-то node сначала удаляется из dom.
    Интересная вещь здесь - IE<=8 не перезагрузить элементы такого поведения - это (несколько) новых (поскольку IE>=9).
  4. по данным Hallvord R. M. Steen комментарий, Это цитата из спецификации iframe

    когда элемент iframe вставляется в документ, который имеет контекст просмотра, агент пользователя должен создать новый контекст просмотра, установить вложенный контекст просмотра элемента во вновь созданный контекст просмотра, а затем обработать iframe атрибуты для "первого раза".

    это самая близкая вещь, которую я нашел в спецификациях, однако она все еще требует некоторой интерпретации (с тех пор, когда мы перемещаем iframe элемент в DOM мы действительно не делаем полный remove, даже если браузеры использует node.removeChild метод).

всякий раз, когда iframe добавляется и имеет атрибут src, он запускает действие загрузки аналогично созданию тега изображения через JS. Поэтому, когда вы удаляете, а затем добавляете их, они являются совершенно новыми сущностями, и они обновляются. Его вид как window.location = window.location перезагрузит страницу.

единственный способ, который я знаю, чтобы переместить iframes через CSS. Вот пример, который я собрал, показывая один из способов справиться с этим flex-box: https://jsfiddle.net/3g73sz3k/15/

основная идея заключается в создании flex-box оболочка, а затем определить определенный порядок для iframes с помощью атрибута 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 только

надеюсь, что это поможет.

Если вы создали iFrame на странице и просто нужно переместить его положение позже попробуйте этот подход:

добавьте iFrame к телу и используйте высокий Z-индекс и верхнюю,левую,ширину,высоту, чтобы поместить iFrame туда, где вы хотите.

даже CSS zoom работает на теле без перезагрузки, что является удивительным!

Я поддерживаю два состояния для моего "виджета", и он либо вводится на место в DOM, либо в тело, используя этот метод.

Это полезно когда другой контент или библиотеки будут хлюпать или раздавить ваш iFrame.

бум!

к сожалению,parentNode свойство элемента HTML DOM доступно только для чтения. Конечно, вы можете настроить позиции iframes, но вы не можете изменить их местоположение в DOM и сохранить их состояния.

см. этот jsfiddle, который я создал, который обеспечивает хороший тестовый стенд. http://jsfiddle.net/RpHTj/1/

нажмите на поле, чтобы переключить значение. Нажмите на кнопку "Переместить", чтобы запустить javascript.

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

в ответ на щедрость @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);
}

Если вы используете iframe для доступа к страницам, которые вы контролируете, вы можете создать некоторый javascript, чтобы ваш родитель мог общаться с iframe через postMessage

оттуда вы можете создать логин внутри iframe для записи изменений состояния и перед перемещением dom запросить его как объект json.

после перемещения iframe перезагрузится, вы можете передать данные состояния в iframe, и прослушивание iframe может проанализировать данные обратно в предыдущее состояние.