Перемещение блоков по веб-странице.

Рассмотрим простой пример: перенесем форму поиска со всем ее содержимым из правой колонки в "шапку" этой страницы. Функциональность формы при этом останется прежней. Исходный код документа также не изменится. Изменится лишь структура дерева документа и внешний вид веб-страницы.

Чтобы был понятен именно принцип, не будем усложнять скрипт различными проверками наличия или отсутствия элементов, поддержки методов и пр. Условимся, что "шапку" в документе представляет <div id="header">, у формы поиска: id="searchform", а браузер достаточно современный и поддерживает DOM (объектную модель документа).

Так как проверка наличия элементов в рассматриваемом примере отсутствует, прошу дождаться загрузки формы. И, если вы видите ее над меню в правой колонке, можете проверить как это работает. Кликните по ссылке:

переместить форму поиска!

Получилось? Посмотрим исходный HTML-код примера.


<body>
 <div id="header">
  ..."шапка"...
 </div>
 <div id="content">
  <div id="left">
   ..."левая колонка"...
  </div> 
  <div id="right">
   ..."правая колонка"...
   <form id="searchform">
    <input type="text" name="s" />
    <input type="submit" value="найти" />
   </form>
   ...
  </div> 
 </div>
...
</body>

После клика по ссылке исходный код останется прежним, а страница в окне браузера изменится и станет такой, как если бы он был таким:


<body>
 <div id="header">
   <form id="searchform">
    <input type="text" name="s" />
    <input type="submit" value="найти" />
   </form>
  ..."шапка"...
 </div>
 <div id="content">
  <div id="left">
   ..."левая колонка"...
  </div> 
  <div id="right">
   ..."правая колонка"...
   ...
  </div> 
 </div>
...
</body>

Далее рассмотрим JavaScript примера.


<script type="text/javascript"><!--

function replaceBlock() {
  var mBlock = document.getElementById("searchform");
  var newPlace = document.getElementById("header");
// клонируем перемещаемый блок
  var clonedBlock = mBlock.cloneNode(true);
// и вставляем его в начало "шапки"
  newPlace.insertBefore(clonedBlock, newPlace.firstChild);
// убираем старый блок
  mBlock.parentNode.removeChild(mBlock);
}

// --></script>

Клик по ссылке <a href="#" onclick="replaceBlock(); return false;">переместить форму поиска!</a> вызывает функцию перемещения блока.

Как видите, скрипт получился не таким уж большим, почти половина строк — комментарии. Его можно немного изменить. Например, сделать более универсальным и передавать функции в качестве аргументов значения ID узлов, которыми нужно оперировать. Цель примера показать именно принцип перемещения узлов, поэтому далее я лучше подробнее расскажу, что делает скрипт.

В первой строке в переменной mBlock оставим узел документа, который будем перемещать.

Переменная newPlace — место, в которое переместим форму.

Клонируем узел, т.е. в нашем случае форму. Метод cloneNode() возвращает копию данного узла. Если значение параметра глубина равно true, вместе с узлом клонируется и его поддерево. Таким образом в переменную clonedBlock помещаем форму со всеми полями, кнопками т.е. со всем, что размещено внутри <form>...</form>.

Теперь нужно определиться, в какое место "шапки" поместим форму. Дело в том, что <div id="header"> не пустой, в нем уже есть какое-то содержимое. Поэтому выбираем один из двух методов DOM: appendChild или insertBefore.

Первый разместит блок в конец узла id="header", после его содержимого, т.е. перемещаемый узел окажется lastChild — последним дочерним по отношению к целевому. Зная заранее, что целевой узел пуст, лучше использовать именно этот метод.

Второй метод более интересен. Он позволяет вставить новый узел перед любым уже существующим. Из известнных и легко определяемых узлов это могут быть, например, firstChild (первый дочерний узел) и lastChild (последний дочерний). Итак, в описанном выше примере форма будет размещена перед первым дочерним узлом узла id="header".

В последней строке скрипта удалим исходный блок. Делаем это по двум причинам. Первая — целью примера было перемещение, хотя ничто не мешает так же копировать узлы документа. Вторая — в корректном XHTML-документе не может быть нескольких элементов с одинаковым ID. При копировании узлов не стоит об этом забывать. Нужно обязательно изменить ID либо исходному, либо скопированному узлу.

Таким образом, не изменяя исходный код XHTML-документа и порядок его загрузки, можно совершенно спокойно изменить структуру дерева документа и внешний вид страницы.

Это может быть особенно полезным при внедрении на страницу чего-либо с другого сервера. Например, различные информеры или баннеры. Если они в исходном коде размещены раньше контента, а загружаются с чужого сервера с перебоями или задержками и тормозят отображение страницы, то их спокойно можно спрятать в невидимый контейнер, например, перед закрывающим </body>. А после загрузки всего докумета (событие onload) переместить в определенное дизайном место на странице и сделать видимым.



Много комментариев (8) к “Перемещение блоков по веб-странице.”

  1. Пока лаиер :) :

    круто!!!


  2. Дмитрий К. :

    Не совсем понятно для чего делается клонирование блока, если используется всего один экземпляр этого блока? На мой взгляд следующая реализация скрипта будет работать аналогично приведённой в статье.

    function replaceBlock() {
    var mBlock = document.getElementById(”searchform”);
    var newPlace = document.getElementById(”header”);
    mBlock.parentNode.removeChild(mBlock);
    newPlace.insertBefore(mBlock, newPlace.firstChild);
    }


  3. Баранов Андрей :

    Для Дмитрий К.: не проверял, но должно работать.

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

    В этом случае последняя строка mBlock.parentNode.removeChild(mBlock); в функции не нужна. Но нужно изменить значение ID какому-либо из блоков: исходному или клонированному. Т.е. примерно так:
    mBlock.id = “newID”; – для начального блока или
    clonedBlock.id = “newID”; – для клонированного.


  4. Даниил Зильберман :

    Интересно…
    Жаль нету примеров реальной пользы подобного метода, прикладного, так сказать, применения.
    Где с пользой можно использовать подобную функцию?


  5. Дмитрий К. :

    Для Даниил Зильберман: подобный подход я использовал для переключения между простым и расширенным отображением формы фильтров. Я генерировал в HTML страницу изображение двух форм: простой и расширенной, после этого через myNode.parentNode.removeChild(myNode) “выкусывал” расширенную форму и сохранял её в переменной на странице. А по клику на “расширенном виде фильтров”, вставлял сохранённую расширенную форму и “выкусывал” упрощённый вид формы.

    В отличие от управления видимостью своством display, в данном случае взаимозаменяемые части HTML документа могут содержать пересекающийся набор input-ов внутри form-ы.

    и если не убрать один из div-ов с помощью removeChild, а просто спрятать по display: none, то данные всё-равно будут посылаться на сервер из двух наборов input-ов и поле username прийдёт дважды.


  6. Эдуард :

    Для Дмитрий К., который писал для Даниил Зильберман.

    Думаю в данном случае гораздо быстрее работало бы просто скрытие блока с расширенной информацией или восстановление видимости обратно, а для решения проблемы с одинаковыми именами input-ов выставлять свойство disabled для input-ов невидимой формы в true, а для видимой в false. Если input disabled, то при submit’е его данные на сервер не едут, что и решает проблему с дублированием.

    Best, Ed.


  7. root :

    Может пригодится, спасибо
    Оффтопик:
    Щелкнул на баннер валидатора:
    http://xhtml.ru/ Failed validation, 72 errors


  8. Алексей :

    http://www.google.com/ig?hl=en
    персоналайз ё хомпейдж.. это оно?)



22 queries 0.186 seconds.