Как переместить 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 и события.
Допустим, что следующим текстом был iFrame HTML:
<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/variables/etc остаются неизменными?
Ответы
Ответ 1
Невозможно переместить 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);
Ответ 2
Этот ответ связан с щедростью by @djechlin
Множество поисков по спецификациям w3/dom и не нашли ничего окончательного, что, в частности, говорит о том, что iframe следует перезагружать при перемещении в дереве DOM, однако я нашел много ссылок и комментариев в webkit trac/bugzilla/microsoft относительно различных изменений поведения за эти годы.
Надеюсь, что кто-то найдет что-то конкретное в этом вопросе, но сейчас вот мои выводы:
- Согласно Ryosuke Niwa - "Это ожидаемое поведение".
- Был "волшебный iframe" (webkit, 2010), но он был удален в 2012 году.
- Согласно MS - "ресурсы iframe освобождаются при удалении из DOM". Когда вы
appendChild(node)
существующего node - то node
сначала удаляется из dom.
Интересная вещь здесь - IE<=8
не перезагружает iframe - это поведение (несколько) новое (с IE>=9
).
-
В соответствии с Hallvord RM Steen комментарий, это цитата из спецификаций iframe
Когда элемент iframe вставлен в документ, в котором есть контекст просмотра, пользовательский агент должен создать новый контекст просмотра, установить контекстный контекст просмотра элемента в недавно созданный контекст просмотра, а затем обработать iframe атрибуты для "первого раза" .
Это самая близкая вещь, которую я нашел в спецификациях, однако она по-прежнему требует некоторой интерпретации (поскольку, когда мы перемещаем элемент iframe
в DOM, мы действительно не делаем полного remove
, даже если браузеры использует метод node.removeChild
).
Ответ 3
Всякий раз, когда 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
Надеюсь, что это поможет.
Ответ 4
Если вы создали iFrame на странице и вам просто нужно переместить его, попробуйте этот подход:
Приложите iFrame к телу и используйте высокий индекс z и верхний, левый, ширина и высоту, чтобы разместить iFrame там, где вы хотите.
Даже CSS-масштабирование работает на теле без перезагрузки, что является удивительным!
Я поддерживаю два состояния для своего "виджета", и он либо вводится на место в DOM, либо в тело, используя этот метод.
Это полезно, когда другой контент или библиотеки будут хлюпать или раздавить ваш iFrame.
BOOM!
Ответ 5
К сожалению, свойство parentNode
элемента HTML DOM доступно только для чтения. Конечно, вы можете отрегулировать позиции фреймов, но вы не можете изменить их местоположение в DOM и сохранить свои состояния.
См. этот jsfiddle, который я создал, который обеспечивает хорошую тестовую кровать. http://jsfiddle.net/RpHTj/1/
Нажмите на поле, чтобы переключить значение. Нажмите "move", чтобы запустить javascript.
Ответ 6
Этот вопрос довольно старый... но я нашел способ переместить iframe без его перезагрузки. Только CSS. У меня есть несколько iframe с потоками камеры, мне не нравится, когда они перезагружаются, когда меняют их. Поэтому я использовал комбинацию float, position: absolute и некоторых фиктивных блоков, чтобы перемещать их без перезагрузки и иметь желаемый макет по требованию (изменение размера и все).
Ответ 7
В ответ на щедрость @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);
}
Ответ 8
Если вы используете iframe для доступа к страницам, которые вы контролируете, вы можете создать некоторый javascript, чтобы позволить вашему родителю общаться с iframe через postMessage
Оттуда вы можете создать логин внутри iframe для записи изменений состояния, а перед перемещением dom запросите это как объект json.
После перемещения iframe перезагрузится, вы можете передать данные состояния в iframe, и прослушивание iframe может проанализировать данные обратно в предыдущее состояние.