Как переместить 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 ответов:
невозможно переместить 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 относительно различных изменений поведения на протяжении многих лет.
Я надеюсь, что кто-то найдет что-то конкретное по этому вопросу, но пока вот мои выводы:
- по данным Риосуке Нива - "это ожидаемое поведение".
- был "волшебный iframe" (webkit, 2010), но это было удалено в 2012 году.
- согласно MS -"ресурсы iframe освобождаются при удалении из DOM". Когда ты
appendChild(node)
существующего узла-тоnode
сначала удаляется из dom.
Интересная вещь здесь -IE<=8
не перезагрузить элементы такого поведения - это (несколько) новых (посколькуIE>=9
).по данным 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, и пришел к выводу, что это все еще невозможно.
//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 может проанализировать данные обратно в предыдущее состояние.