Замечательный 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.

 

Лучшая благодарность автору — ваши комментарии!

Tags: , , ,

Leave a Response

Для подсветки кода используйте BB - коды: [language]...[/language], где language может быть: ruby, javascript, css, html.