Как переместить iFrame в DOM, не теряя его состояние? - PullRequest
82 голосов
/ 30 ноября 2011

Взгляните на этот простой 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 оставалось неизменным, а события iFrame / переменные / и т.д. остаются прежними?

Ответы [ 8 ]

42 голосов
/ 30 ноября 2011

Невозможно переместить 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);
36 голосов
/ 06 октября 2016

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

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

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

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

    Когда элемент iframe вставляется в документ, имеющий контекст просмотра, пользовательский агент должен создать новый контекст просмотра, установить вложенный контекст просмотра элемента в только что созданный контекст просмотра, а затем обработать iframe атрибуты для «первого раза» .

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

13 голосов
/ 12 октября 2016

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

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

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

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

7 голосов
/ 15 апреля 2013

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

Добавьте iFrame к телу и используйте высокий z-index и top, left, width,Высота для размещения iFrame, где вы хотите.

Даже масштабирование CSS работает на теле без перезагрузки, что потрясающе!

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

Это полезно, когда другой контент или библиотеки будут сжимать или сдавливать ваш iFrame.

BOOM!

5 голосов
/ 30 ноября 2011

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

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

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

4 голосов
/ 17 июня 2016

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

1 голос
/ 11 октября 2016

В ответ на щедрость @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 голосов
/ 12 октября 2016

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...