Опубликован: 28.02.2016 | Уровень: для всех | Доступ: платный
Лекция 6:

Манипуляции с DOM

< Лекция 5 || Лекция 6 || Лекция 7 >

А теперь я буду долго и нудно рассказывать о том, как с помощью jQuery можно изменять DOM дерево на странице, т.е. добавлять и удалять элементы, но чего это я, глава в действительности не будет объёмной :)

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

var $myDiv = $('<div id="my" class="some"></div>')

Этот пример вполне рабочий, да вот только производительностью он блистать не будет, ведь внутри будет всё это разбираться с помощью метода "jQuery.parseHTML()", который совсем не быстрый. Но мы можем помочь парсеру если атрибуты элемента будем передавать вторым параметром:

var $myDiv = $('<div>', {'id':'my', 'class':'some'})

Можем сделать ещё проще:

var $myDiv = $('<div>').attr({'id':'my', 'class':'some'});

И этот способ будет работать даже быстрее (ну совсем капельку), но почему? Для того, чтобы ответить на данный вопрос – загляните в код jQuery, в самую главную функцию "init()", в её коде можно найти алгоритм разбора предыдущего примера:

  1. Парсим строку, и создаём DOM элемент в jQuery обёртке
  2. Заходим в цикл обработки переданных параметров:
    • Проверяем, а нет ли функции у нашего элемента с таким названием
    • Если нет, то устанавливаем атрибут элемента используя метод attr()

Выводы делайте сами, гдe мы тут время потеряли :)

Ну и на последок опишу самый быстрый способ, который я часто использую:

var myDiv = document.createElement('div'); 
myDiv.id = 'my';
myDiv.className = 'some';

Да, это и есть "чистый" JavaScript, но как по мне – в данном случае он не менее удобен любых фреймворков. И вот вам домашнее задание – оптимизируйте такой скрипт:

$('<div id="my"><div 
id="precious">Ring</div></div>')

Выполняйте тут, бумага стерпит:

Все необходимые нам методы собраны в одном разделе документации – Manipulation, с некоторыми из них мы уже познакомились, и осталось совсем чуть-чуть:

after(content) — вставляет контент после каждого элемента из выборки, т.е. если вы встречаете строку "$("p").after("<hr/>")", читайте её как "после каждого параграфа будет вставлена линия"

insertAfter(element) — вставляет элементы из выборки после каждого элемента переданного в качестве аргумента, т.е. если вы встречаете строку "$("<hr/>").insertAfter("p")" – читайте её как "линия будет вставлена после каждого параграфа"

— Хм, а я разницы не увидел! — тут всё легко, присмотритесь:

$("после чего добавляем").after("что добавляем")
$("что добавляем").insertAfter("после чего добавляем")

before(content) — вставляет контент перед каждым выбранным элементом

insertBefore(element) — вставляет элементы из выборки перед каждым элементом переданным в качестве аргумента

append(content) — вставляет контент в конец каждого элемента из выборки, т.е. строку кода "$("p").append("<hr/>")", следует читать как "в конец каждого параграфа будет добавлена линия"

appendTo(element) — вставляет выбранный контент в конец каждого элемента переданного в качестве аргумента: "$("<hr/>").appendTo("p")" — "линия будет добавлена в конец каждого параграфа"

Опять про разницу:

$("куда добавляем").append("что добавляем")
$("что добавляем").appendTo("куда добавляем")

prepend(content) — вставляет контент в начало каждого элемента из выборки

prependTo(element) — вставляет выбранный контент в начало каждого элемента переданного в качестве аргумента

Так, с этим кусочком документации вроде как разобрались, опять же – почувствуйте разницу перечисленных методов, ведь дальше будут ещё:

replaceWith(content) – заменяет найденные элементы новым

replaceAll(target) – вставляет контент в замен найденному

$("что-то находим").replaceWith("на что меняем")
$("что вставляем").replaceAll("вместо чего")

wrap(element) – оборачиваем каждый найденный элемент новым элементом, т.е. мы конфеты из коробки заворачиваем в фантики

wrapAll(element) – оборачивает найденные элементы новым элементом, мы берём все конфеты, и заворачиваем в один большой фантик

wrapInner(element) – оборачивает контент каждого найденного элемента новым элементом, берём конфеты, убираем фантики, заворачиваем в свой фантик, и сверху заворачиваем в родной фантик

unwrap() – удаляет родительский элемент у найденных элементов, фантики вон

clone(withDataAndEvents) – клонирует выбранные элементы, для дальнейшей вставки копий назад в DOM, позволяет так же копировать и обработчики событий

detach() – удаляет элемент из DOM, но при этом сохраняет все данные о нём в jQuery, следует использовать, если надо удалить элемент, а потом вернуть его обратно

empty() – удаляет текст и дочерние DOM элементы

remove() – удаляет элемент из DOM, насовсем

html() – вернёт HTML заданного элемента

html(newHtml) – заменит HTML в заданном элементе

text() – вернёт текст заданного элемента, если внутри элемента будут другие HTML тэги, то вернётся сборная солянка из текста всех элементов

text(newText) – заменит текст внутри выбранных элементов, при попытке вставить таким образом HTML, будет получен текст, где тэги будут приведены к HTML entities:

$("div").text("Some <strong>text</strong>") >> Some <strong>text</strong>

Переварили? Хорошо, теперь настал черёд методов, которые работают с размерами, и знают координаты элементов:

Но прежде чем продолжить, хотелось бы освежить в памяти информацию о вычислении высоты и ширины блочных элементов ;)

offset() – вернёт позицию DOM элемента относительно document'а, данные будут получены в виде объекта: "{ top: 10, left: 30 }"

offset({ top: 10, left: 30 }) – устанавливаем расположение DOM элемента по указанным координатам

position() – вернёт позицию DOM элемента относительно родительского элемента

height() – возвращает высоту элемента за вычетом отступов и границ; если у нас несколько элементов в выборке, вернётся первый; значение, в отличии от метода "css('height')", возвращается без указания единиц измерения

height(height) — устанавливает высоту всех элементов в выборке, если значение высоты передано без указания единиц измерения, то это будут "px"

// в качестве памятки, взято из мануала
$(window).height(); // высота окна
$(document).height(); // высота HTML документа

width() и width(width) – ведут себя аналогично методу "height()", но работают с шириной элемента

Методы "height()" и "width()" не изменяют своего поведения в зависимости от выбранной блочной модели, т.е. они всегда возвращают параметры области внутри margin, padding и border'а элемента.

innerHeight() и innerWidth() – вернут соответственно высоту и ширину элемента, включая "padding"

outerHeight() и outerWidth() – вернут высоту и ширину элемента, включая "padding" и "border"

outerHeight(true) и outerWidth(true) – высота и ширина, включая "padding", "border" и "margin"

Для наглядности различий между методами "height()", "innerHeight()" и "outerHeight()" я создал страничку, а ещё переделал несколько картинок из официальной документации в одну полноценную иллюстрацию:

<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Разбор высот</title>
    <link rel="profile" href="http://gmpg.org/xfn/11"/>
    <link rel="shortcut icon" href="http://anton.shevchuk.name/favicon.ico"/>
    <link rel="stylesheet" href="css/styles.css"/>
	<script type="text/javascript" src="js/jquery.js"></script>
	<script type="text/javascript" src="js/code.js"></script>
    <style>
        article {
            border: 1px solid #000;
        }
        #block {
            width:400px;
            height:40px;
            margin:40px;
            padding:40px;
            border:40px solid #777;
            background: #ddd;
        }
        #text {
            background: #fff;
            font-size: 20px;
            line-height: 40px;
            text-indent: 8px;
        }
        .contentBox {
            box-sizing: content-box;
            -moz-box-sizing: content-box;
            -webkit-box-sizing: content-box;
        }
        .borderBox {
            box-sizing: content-box;
            -moz-box-sizing: content-box;
            -webkit-box-sizing: content-box;
        }
        @media screen and (max-width: 480px) {
            article {
                border: 0;
            }
            #block {
                width:auto;
            }
            #text {
                font-size: 16px;
            }
        }
    </style>
</head>
<body>
    <div id="content" class="wrapper box">
        <menu>
            <a href="property.html" title="go prev" class="button alignleft" rel="prev">← Prev </a>
            <a href="index.html" title="back to Index" class="button alignleft" rel="index">Index §</a>
            <a href="#" title="reload" class="button alignleft" onclick="window.location.reload();return false">Reload ¤</a>
            <a href="form.html" title="go next" class="button alignright" rel="next">Next →</a>
            <hr/>
            <h3>Style</h3>
            <pre><code>#block {
    height:40px;
    margin:40px;
    padding:40px;
    border:40px solid #777;
}</code></pre>
            <!--<h3>Switch <em>box-sizing</em></h3>-->
            <!--<pre><code contenteditable="true">$(<span>'#block'</span>).addClass(<span>'borderBox'</span>)</code></pre>-->
            <!--<button type="button" class="code">Run Code</button>-->
            <!--<pre><code contenteditable="true">$(<span>'#block'</span>).addClass(<span>'contentBox'</span>)</code></pre>-->
            <!--<button type="button" class="code">Run Code</button>-->
            <h3>Получаем высоту</h3>
            <p>Лишь значение height</p>
            <pre data-out="1"><code>$(<span>'#block'</span>).height()</code></pre>
            <button type="button" class="code">Run Code</button>
            <p>Значение height + padding</p>
            <pre data-out="1"><code>$(<span>'#block'</span>).innerHeight()</code></pre>
            <button type="button" class="code">Run Code</button>
            <p>Значение height + padding + border</p>
            <pre data-out="1"><code>$(<span>'#block'</span>).outerHeight()</code></pre>
            <button type="button" class="code">Run Code</button>
            <p>Значение height + padding + border + margin</p>
            <pre data-out="1"><code>$(<span>'#block'</span>).outerHeight(true)</code></pre>
            <button type="button" class="code">Run Code</button>
        </menu>
        <header>
            <h1>Пример вычисление «высот»</h1>
        </header>
        <div id="output">
            <h3>Output</h3>
            <pre></pre>
        </div>
        <article>
            <div id="block">
                <div id="text">Content</div>
            </div>
        </article>
        <footer>
            ©copyright 2014 Anton Shevchuk — <a href="http://anton.shevchuk.name/jquery-book/">jQuery Book</a>
        </footer>
        <script type="text/javascript">
            var _gaq = _gaq || [];
            _gaq.push(['_setAccount', 'UA-1669896-2']);
            _gaq.push(['_trackPageview']);
            (function() {
             var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
             ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
             var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
            })();
         </script>
	</div>
</body>
</html>
блочная модель

Рис. 6.1. блочная модель

Ну и последняя пара методов:

scrollLeft() – возвращает значение "проскроленности" по горизонтали первого элемента из выборки

scrollLeft(value) – устанавливает значение горизонтального скрола для каждого элемента из выборки

scrollTop() – возвращает значение "проскроленности" по вертикали первого элемента из выборки

scrollTop(value) – устанавливает значение вертикального скрола для каждого элемента из выборки

Значение "scrollTop" и "scrollLeft" поддаются анимации и не работают для спрятанных элементов DOM

Методов реально много, я и сам не всегда помню что и для чего (особенно это касается wrap-семейства), так что не утруждайте себя запоминанием всего перечисленного, главное помнить что таковые имеются и держать под рукой документацию

< Лекция 5 || Лекция 6 || Лекция 7 >
Наталья Маркова
Наталья Маркова
Ярослав Гаевой
Ярослав Гаевой

10 марта 2016 c 20:13 до 22:39 я сдавал экзамен. Однако, за два месяца статус не изменился: "Задание не проверено"

Когда ожидать проверки?

Руслан Жанбосынов
Руслан Жанбосынов
Россия
Дмитрий Молокоедов
Дмитрий Молокоедов
Россия, Новосибирск, НГПУ, 2009