Замечательный JavaScript ч. 3: Работа с DOM и BOM
декабря 10, 2011 | Published in ClientSide, JavaScript
BOM — Browser Object Model — объектная модель браузера
BOM — представляет собой древовидную структуру, иерархию объектов браузера. Во главе этой структуры стоит объект window и представляет он собой само окно браузера. window также является глобальным объектом, то есть внутри него расположена глобальная область видимости и любая глобальная функция или переменная является соответственно методом или свойством объекта window.
Наиболее интересными функциями и свойствами window являются следующие:
window.navigator — информация о браузере.
window.innerHeight, window.innerWidth — внутренняя высота и ширина браузера, то есть размер области, которая отображает сайт.
window.outerHeight, window.outerWidth — внешняя высота и ширина, то есть размер самого окна браузера.
window.load() — функция-обработчик события загрузки сайта.
window.location — объект предоставляет информацию об адресе страницы и методы для редиректа, обновления страницы и т.д.
screen — объект предоставляющий информацию о пользовательском дисплее.
screenLeft(screenX), screenTop(screenX) — положение верхнего левого угла окна браузера.
scrollY, scrollX — положения горизонтальной и вертикальной полос прокрутки.
В этой статье мы рассматриваем BOM достаточно поверхностно так как для разработки веб-приложений нам это не сильно нужно знать. Интерес представляют только свойства дающие информацию о браузере пользователя, размерах экрана/браузера и локация.
DOM — Document Object Model — объектная модель документа.
DOM является структурой вложенной в BOM. DOM содержит дерево всех элементов страницы и методы для работы с ними. Самыми популярными методами являются:
document.getElementById() — позволяет получить элемент по его ID.
document.getElementsByClassName() — позволяет получить элементы по их классу.
document.getElementsByName() — позволяет получить элементы по их имени.
document.getElementsByTagName() — позволяет получить элементы по имени тега.
document.getElementsByTagNameNS() — позволяет получить элементы по их имени, которые содержатся в определенной области видимости (оптимизированная версия getElementsByTagName).
Прежде, чем мы продолжим знакомится с остальными методами и свойствами для работы с DOM давайте подробнее рассмотрим что это такое и из чего DOM состоит. DOM описывается сразу тремя спецификациями разработанными W3C (W3C Level 1 DOM, W3C Level 2 DOM, W3C Level 3 DOM), которые были разработаны в разное время и соответственно в разной степени поддерживаются браузерами. В этой статье мы в первую очередь будем обращать внимание на DOM Level 1 так как он поддерживается полностью (или почти полностью) всеми современными (и не очень современными) браузерами. Вообще каждый Leve l является наслоением над предыдущим и добавляет определение новых свойств и методов для работы с DOM.
DOM состоит из узлов (node). О типах узлов позже.
<div> <p> <a>link</a> some text </p> </div>
Можно изобразить так:
Я буду концентрировать внимание в статье только на реально необходимых вещах, то есть работать мы будем всего с 3 типами узлов: ELEMENT_NODE(1), ATTRIBUTE_NODE(2), TEXT_NODE(3). Все остальные узлы необходимы очень-редко и то в очень-очень специальных приложениях.
ELEMENT_NODE(1) — узел представляющий собой элемент (тег).
ATTRIBUTE_NODE(2) — узел представляющий собой атрибут элемента.
TEXT_NODE(3) — узел представляющий собой текст (текст параграфа, текст ссылки и т.д.).
CDATA_SELECTION_NODE(4) — узел представляет содержание CDATA.
ENTITY_REFERENCE_NODE(5) — представляет ссылку на сущность.(XML)
ENTITY_NODE(6) — представляет сущность.(XML)
PROCESSING_INSTRUCTION_NODE(7) — узел представляет инструкцию обработки (XML)
COMMENT_NODE(8) — узел представляет собой комментарий в HTML коде.
DOCUMENT_NODE(9) — узел представляет собой документ, является корнем остальных узлов.
DOCUMENT_TYPE_NODE(10) — узел представляет собой <!DOCTYPE> документа.
DOCUMENT_FRAGMENT_NODE(11) — узел представляет упрощенный или урезанный document.
NOTATION_NODE(12) — узел представляет описание не-XML данных используемых внутри XML
Приведенное в скобках число — индекс узла, который возвращается при вызове для узла метода .nodeType(). .nodeType() — представляет достаточно поверхностную информацию об узле — один только ID, часто бывает полезно получить больше информации — для этого следует использовать метод .nodeName.
Существует также полезнейшие get, set аксессоры .nodeValue, которые предоставляют содержимое узла или позволяют установить это содержимое.
Поскольку узлы вложены друг в друга и представляют собой достаточно сложную иерархическую структуру, программистам требуется специальное API для перемещению по этому дереву.
Обращение к родительскому услу и дочерним узлам происходит через свойства parentNode и childNodes соответственно. Поскольку childNodes возвращает массив вложенных узлов, мы можем обращаться к конкретному потомку следующим образом:
element.childNodes[0]; element.childNodes[100500];
и т.д.
Имеются также специальные свойства доступа к первому и последнему потомкам: firstChild и lastChild соответственно.
Для перемещения по одному уровню (по дочерним элементам одного родителя) существуют специальные свойства nextSibling и previousSibling.
Умение перемешаться по дереву DOM очень важно, однако чаще всего приходится обращаться к определенному элементу, позиция которого заранее может быть не известна. Для такой работы предназначены описанные выше методы getElementsByTagName, getElementsByTagNameNS, getElementsByClassName, getElementsByName, getElementById.
Еще важной возможность в работе с DOM является возможность добавлять и удалять элементы. Для добавления элемента необходимо использовать метод .appendChild(), но предварительно элемент необходимо создать используя метод .createElement(). Для удаления вложенного элемента следует использовать метод .removeChild().
Давайте остановимся и попрактикуемся в работе с DOM. Для этого мы будем использовать совсем простой HTML код:
<!DOCTYPE html> <html> <head> <title>JavaScript on RubyDev</title> <style> body{background:#a5a9aa;font-size:14px;margin:0;padding:0;} #wrapper{margin:20px auto;background:#f8f8f8;width:720px;padding:20px;border:1px solid #999;} </style> </head> <body> <div id='wrapper'> <div id="header"> <h1>hello!</h1> </div> <div id="content"> <div> <p>Text1</p> <p><b>BoldText2</b> and <a href="#">Link</a></p> </div> </div> </div> </body> </html>
И инструменты разработчика в браузере. Chrome уже поставляется с замечательным набором разработчика, который включает в себя JavaScript REPL (его еще называют просто консолью), отладчик, профайлер и просмотрщик HTML и CSS. В Firefox нет встроенного инструмента разработчика (он появился только в FireFox Aurora), но имеется замечательный аддон — FireBug.
1. Обращаемся к элементам.
1.1. Получаем список всех элементов в именем div:
var divs = document.getElementsByTagName("div"); divs.length // 4
1.2. Получаем список всех элементов с классом paragraphs:
var paragraphs = document.getElementsByClassName("paragraphs"); paragraphs.length //1
1.3. Получаем div с ID = content:
var content = document.getElementById("content"); content //<div id="content">
1.4. Использование CSS-селекторов для выборки элементов
content.querySelector("p"); //<p> content.querySelectorAll("p"); //NodeList { 0=p, 1=p, 2=p, more...} document.querySelectorAll("#content p"); //NodeList { 0=p, 1=p, 2=p, more...}
2. Путешествуем по дереву DOM
2.1. Дочерние узлы
//имеет ли элемент дочерние элементы (узлы)? content.hasChildNodes() //true document.childNodes[0] //DocumentType document.childNodes[1] //<html> document.childNodes[1].nodeType //1 document.childNodes[1].childNodes //NodeList { 0=head, 1=textNode, 2=body }
2.2. Соседние узлы
document.childNodes[1].childNodes[0].nextSibling //<TextNode textContent="\n"> document.childNodes[1].childNodes[0].nextSibling.nextSibling //<body> document.childNodes[1].childNodes[0].nextSibling.previousSibling //<head> document.firstChild //DocumentType { constructor=DocumentType, nodeName="html", nodeType=10, ...} document.lastChild //<html>
2.3. Родительский узел
document.childNodes[1].childNodes[0].parentNode // <html> document.childNodes[1].childNodes[1].parentNode // <html>
3. Работа с атрибутами и содержимым узла
3.1. Работа с текстовым узлом: содержание узла
var textNode = content.childNodes[0] textNode.data //"\n " textNode.nodeValue //"\n "
3.2. Работа с текстовым узлом: меняем значение
textNode.nodeValue = "Hey!" //"Hey!" textNode.data = "Bye!" //"Bye!"
3.3. Работа с узлом атрибутов
content.attributes //[id="content"] content.attributes[0] //id="content" content.attributes.id //id="content" content.attributes //[id="content"] content.attributes[0].nodeType //2 content.attributes[0].nodeName //"id" content.attributes[0].value //"content" content.attributes[0].nodeValue = 'wrapper'
3.4. Аксессоры к атрибутам
var a = document.getElementsByTagName("a")[0]; a.classList//{ length=0, item=item(), contains=contains(), more...} a.id //"" a.href //"file:///home/vladimir/dom.html#" a.target //""
3.5. Аксессоры к inline-стилям
var h1 = document.getElementsByTagName("h1")[0]; h1.style //CSSStyleDeclaration { length=0, background="", backgroundAttachment="", more...} h1.style.font; //"" h1.style.size; //"" h1.style.color; //"" h1.style.color = "#333"; h1.style.color; //"rgb(51, 51, 51)" h1.style.color = "#cc4"; h1.style.color; //"rgb(204, 204, 68)"
3.6. Работа с атрибутами
//имеет ли элемент атрибуты? content.hasAttributes() //true //имеет ли элемент определенный атрибут? content.hasAttribute("id") //true content.setAttribute('class', 'super-class'); //устанавливаем атрибут content.attributes //[id="wrapper",] content.getAttribute("class") //"super-class" content.removeAttribute("class"); //удаляем атрибут content.getAttribute("class"); //null
4. Работа с потомками
4.1. Добавление узлов
//создаем новый узел - <p> var p1 = document.createElement('p'); p1.textContent = "Super-duper paragraph."; //помещаем узел <p> в родителя content (<div id="content">) content.appendChild(p1); //<p> var p2 = document.createElement('p'); p2.textContent = "First paragraph."; //вставляем p2 перед p1 content.insertBefore(p2, p1); var p3 = document.createElement('p'); p3.textContent = "Second paragraph."; //вставляем p3 после p2. content.insertBefore(p3, p2);
4.2. Удаление дочерних узлов
content.removeChild(p3);
4.3. Замена узла
//заменяем p2 на p3 content.replaceChild(p3, p2);
5.Дополнительно
5.1. innerHTML
var paragraph = document.getElementsByTagName("p")[1]; paragraph.textContent //"BoldText2 and Link" paragraph.innerHTML //"<b>BoldText2</b> and <a href="#">Link</a>"
Метод innerHTML позволяет легко манипулировать содержимым узла — вложенными ELEMENT_NODE и TEXT_NODE. Проще говоря, вы можете легко получить кусок HTML кода или вставить его.
В следующей статье поговорим о событиях и их обработке в JavaScript.
Лучшая благодарность автору — ваши комментарии!