Манипуляции с DOM
А теперь я буду долго и нудно рассказывать о том, как с помощью 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()", в её коде можно найти алгоритм разбора предыдущего примера:
- Парсим строку, и создаём DOM элемент в jQuery обёртке
- Заходим в цикл обработки переданных параметров:
- Проверяем, а нет ли функции у нашего элемента с таким названием
- Если нет, то устанавливаем атрибут элемента используя метод 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>
Ну и последняя пара методов:
scrollLeft() – возвращает значение "проскроленности" по горизонтали первого элемента из выборки
scrollLeft(value) – устанавливает значение горизонтального скрола для каждого элемента из выборки
scrollTop() – возвращает значение "проскроленности" по вертикали первого элемента из выборки
scrollTop(value) – устанавливает значение вертикального скрола для каждого элемента из выборки
Значение "scrollTop" и "scrollLeft" поддаются анимации и не работают для спрятанных элементов DOM
Методов реально много, я и сам не всегда помню что и для чего (особенно это касается wrap-семейства), так что не утруждайте себя запоминанием всего перечисленного, главное помнить что таковые имеются и держать под рукой документацию