Объект window в браузере обеспечивает доступ:
Window как глобальный объект пользовательских скриптов мы рассматривали ранее.
К BOM относится все, что не относится к DOM:
Document Object Model («объектная модель документа») — это программный интерфейс доступа к содержимому XML-документов, а также изменять содержимое, структуру и оформление таких документов.
В JavaScript DOM используется для доступа и манипуляций с узлами HTML через свойство document.
Дерево DOM — это представление совокупности узлов HTML-страницы в виде древовидной иерархии с учетом вложенности узлов друг в друга.
Рассмотрим код простейшей страницы:
<!DOCTYPE html>
<html>
<head>
<title>Page</title>
</head>
<body><!-- myPage body -->
<main>Hello, <span>word</span></main>
</body>
</html>
DOM-дерево для такой страницы будет выглядеть так:
html
HTML
HEAD
#text
: TITLE
#text
: Page#text
: #text
: BODY
#comment
: myPage body #text
: MAIN
#text
: Hello, SPAN
#text
: word#text
: Похожую структуру можно увидеть, если открыть вкладку Elements инструментов разработчика Google Chrome.
Данное дерево состоит из:
Особенности построения дерева: пробелы перед <head> игнорируются, а все узлы после </body> попадают внутрь тела страницы. Также при построении дерева браузеры используют "исправление вестки": закрытие тегов или добавление недостающих.
Помимо наглядной визуализации структуры документа DOM-дерево дает возможность навигации по документу, используя отношения "родительский/дочерний узел" и "соседний узел".
Прежде, чем применить какие-то изменения к элементам страницы, к ним нужно получить доступ.
Своими свойствами объект document обеспечивает доступ к следующим узлам:
Для перемещению по дереву узлов используют следующие свойства:
Данные свойства работают только для чтения, т.е. напрямую переопределить узел (например, document.body.firstChild = null) нельзя.
Кроме того, навигация происходит по всем узлам независимо от их типа, а чаще всего интересна навигация и взаимодествие с узлами типа "элемент".
Узлы-элементы можно отфильтровать по типу, т.к. у каждого элемента есть собственные свойства:
Типы узлов
Код типа (nodeType) | Тип узла | Описание |
---|---|---|
1 | ELEMENT_NODE | Узел элемента |
3 | TEXT_NODE | Текстовый узел (#text) |
7 | PROCESSING_INSTRUCTION_NODE | Узел инструкции обработки |
8 | COMMENT_NODE | Узел комментария (#comment) |
9 | DOCUMENT_NODE | Узел документа (#document) |
10 | DOCUMENT_TYPE_NODE | Узел типа документа |
11 | DOCUMENT_FRAGMENT_NODE | Узел фрагмента документа |
Для получения только узлов-элементов можно воспользоваться код:
var els = document.documentElement.childNodes;
for(var i = 0; i < els.length; i++) {
if(els[i].nodeType == 1) {
console.log( els[i].nodeName );
}
}
Но есть другой способ получать только узлы-элементы — использовать свойства, привязанные к элементам:
Из особенностей: IE8 и ниже поддерживает только children и в него, вопреки стандарту, попадают узлы-комментарии.
Document так же имеет дополнительные навигационные ссылки:
Элемент формы также имеет ссылку на коллекцию элементов формы через elements
Для получения конкретного элемента неудобно проходить по всему дереву. Верстка может меняться, из-за чего скрипты, привязанные к конкретному расположению элемента в дереве, могут перестать работать. Потому для на практике для обращения к элементам-потомкам используют поисковые методы DOM:
* — современные методы, перед использованием необходимо проверять поддержку браузерами
Для изменения элементов есть следующие свойства:
При интерпретации HTML браузер создает DOM-модель. При этом многие стандартные HTML-атрибуты становятся свойствами элементов.
Для манипуляций с атрибутами используют методы:
Все атрибуты элемента можно получить через свойство attributes в виде коллекции.
Атрибуты всегда имеют строковые значения, имя можно передавать в любом регистре. Атрибуты элемента видны в innerHTML всех его родительских элементов.
Синхронизация между свойствами и атрибутами происходит только для стандартных свойств, но и она не всегда точна. Из типичных примеров можно выделить:
Атрибуту class соответствую два объекта: className (строка) и classList (коллекция). ClassList поддерживается IE10 и выше.
ClassList удобен своими методами для проверки и изменения классов: contains, add/remove, toggle.
В html элементы могут иметь универсальные атрибуты, такие как id, style, class, т.е. атрибуты, общие для всех элементов. Также элементы могут иметь специфические атрибуты, например, for у <label>, href у <a> и т.д. Если элементу добавить нестандартный атрибут, то соответствующее свойство не будет создано. Для управления такими атрибутами нужно использовать только методы *Attribute
Для пользовательских атрибутов используются атрибуты с именем, начинающимся на data-. Доступ к таким атрибутам есть через свойство dataset.
Изменение стилевого оформления элемента доступно через его свойство style. Названия стилевых свойств соответствуют названиям в CSS, но вместо дефиса используется запись свойств в camelCase-формате (кроме float, для которого в style другое свойство).
var body = document.body;
body.style.borderRadius = "20px"; // border-radius: 20px;
body.style.fontSize = "3em"; // font-size: 3em;
body.style.cssFloat = "none"; // float: none; исключение!
Вместе с числовым значением следует всегда явно указывать единицы измерения.
Для добавления свойств с вендорными префиксами префикс добавляеся с большой буквы:
body.style.WebkitTransform = "rotate(30deg)"; // -webkit-transform: rotate(30deg);
body.style.MsTransform = "rotate(30deg)"; // -ms-transform: rotate(30deg);
body.style.transform = "rotate(30deg)"; // transform: rotate(30deg);
Присвоеннное значение стилевого свойства можно сбросить, присвоив пустую строку. Это бывает удобно, например, в случае, если для какого-то элемента на странице мы указали el.style.display = "none";, а затем надо вернуть элементу его исходное состояние. Достаточно написать el.style.display = ""; чтобы удалить назначенное ранее через JavaScript значение.
Следует помнить, что самый более простым способом поменять внешний вид элемента является добавление ему класса. Таким образ код короче, к тому же мы перекладываем всю ответственность за отображение элемента на CSS-стили. Редактирование стилевых свойств через JavaScript целесообразно в случаях, когда необходимо задать параметры элементы исходяиз каких-то других параметров, значения которых неизвесны либо завистят размеров окна браузера, времени суток и т.д.
Все присвоенные стили можно прочитать из специального свойства cssText в виде одной строки. С помощью него же можно переопределить эти стили.
var body = document.body;
body.style.backgroundColor = "#F00";
body.style.fontSize = "3em";
console.log(body.style.cssText); // 'background-color: rgb(255, 0, 0); font-size: 3em;'
body.style.cssText = "background-color: #0F0; font-size: 16px;";
При назначении стилевых свойств (не только через cssText) внутреннее представление значений может меняться. В частности, при указании цвета в любом формате в свойстве он все равно будет храниться в формате rgb(rgba).
При получении свойств из style отобразятся только свойства, заданные через JavaScript. Для получения стилевых свойств элемента с учетом CSS и каскада используется функция getComputedStyle:
<style>
div { color: #F00; }
</style>
<div></div>
<script>
var computed = getComputedStyle(document.querySelector("div"));
console.log(computed.color); // rgb(255, 0, 0)
</script>
Для добавления элементов на страницу используется два метода: append и insertBefore. Оба метода вызываются для родительского элемента, append вставляет самым последним дочерним элементом, а insertBefore — перед элементом, указанным в качестве второго параметра.
Добавлять можно как уже существующий элемент, в этом случае он просто переместится, так и вновь созданный. За создание элементов отвечает метод createElement, который запускается с одним аргументом - типом создаваемого элемента.
var body = document.body;
var newDiv = document.createElement("div"); // создали новый div
newDiv.innerText = "I`m the last div";
body.appendChild(newDiv); // и добавили его в конец body
var oldDiv = body.querySelector("div"); // нашли самый первый div на странице
body.insertBefore(oldDiv, newDiv); // и вставили его перед вновь созданным
При передаче в качестве второго аргумента null метод insertBefore сработает аналогично вызову appendChild.
В случае необходимости удалить элемент со страницы используют метод removeChild:
body.removeChild( oldDiv );
Удалить элемент можно также через замену его новым элементом:
// удаляем oldDiv и вставляем на его место newDiv
body.replaceChild( newDiv, oldDiv );
При использований операций вставки над уже созданными элементами не нужно предварительно удалять их со "старого" места, они просто переместятся по дереву DOM в указанную позицию.