BOM
Все объекты, через которые JavaScript взаимодействует с браузером, описываются таким понятием как Browser Object Model (Объектная Модель Браузера).
Browser Object Model можно представить в виде следующей схемы:
В вершине находится главный объект - объект window, который представляет собой браузер. Этот объект в свою очередь включает ряд других объектов, в частности, объект document, который представляет отдельную веб-страницу, отображаемую в браузере.
- Объект window
Объект window представляет собой окно веб-браузера, в котором размещаются веб-страницы. window является глобальным объектом, поэтому при доступе к его свойствам и методам необязательно использовать его имя. Например, window имеет метод alert(), который отображает окно сообщения. Но нам необязательно писать:
window.alert("Привет мир!");
window можно не использовать:
alert("Привет мир!");
Но так как данный объект глобальный, то это накладывает некоторые ограничения. Например:
var alert = function(message) { document.write("Сообщение: " + message); }; window.alert("Привет мир!"); // Сообщение: Привет мир!
Все объявляемые в программе глобальные переменные или функции автоматически добавляются к объекту window. И поскольку название новой функции будет совпадать с названием метода alert(), то произойдет переопределение этого метода в объекте window новой функцией.
И если мы объявим в программе какую-нибудь глобальную переменную, то она нам доступна как свойство в объекте window:
var message = "hello"; document.write(window.message);
Управление окнами
- Диалоговые окна
Для взаимодействия с пользователем в объекте window определен ряд методов, которые позволяют создавать диалоговые окна.
Метод alert() выводит окно с сообщением.
Метод confirm() отображает окно с сообщением, в котором пользователь должен подтвердить действие двух кнопок OK и Отмена. В зависимости от выбора пользователя метод возвращает true (если пользователь нажал OK) или false (если пользователь нажал кнопку Отмены).
И метод prompt() позволяет с помощью диалогового окна запрашивать у пользователя какие-либо данные. Данный метод возвращает введенное пользователем значение. Если пользователь откажется вводить значение и нажмет на кнопку отмены, то метод возвратит значение null.
- Открытие, закрытие и позиционирование окон
Объект window также предоставляет ряд методов для управления окнами браузера. Так, метод open() открывает определенный ресурс в новом окне браузера:
var popup = window.open('https://microsoft.com', 'Microsoft', 'width=400, height=400, resizable=yes');
Метод open() принимает ряд параметров: путь к ресурсу, описательное название для окна и в качестве третьего параметра набор стилевых значений окна. Метод возвращает ссылку на объект нового окна.
Мы можем установить следующие стилевые характеристики:
С помощью метода close() можно закрыть окно. Например, откроем новое окно и через 5 секунд закроем его:
var popup = window.open('https://microsoft.com', 'Microsoft', 'width=400, height=400, resizable=yes'); function closeWindow() { popup.close(); } setTimeout(closeWindow, 5000);
Метод moveTo() позволяет переместить окно на новую позицию:
var popup = window.open('https://microsoft.com', 'Microsoft', 'width=400, height=400, resizable=yes'); popup.moveTo(50, 50);
В данном случае окно перемещается на позицию с координатами x=50, y=50 относительно левого верхнего угла экрана.
Метод resizeTo() позволяет изменить размеры окна:
var popup = window.open('https://microsoft.com', 'Microsoft', 'width=400, height=400, resizable=yes'); popup.resizeTo(500, 350); // 500 - ширина и 350 - высота
Объект history
Объект history предназначен для хранения истории посещений веб-страниц в браузере. Нам этот объект доступен через объект window.
Все сведения о посещении пользователя хранятся в специальном стеке (history stack). С помощью свойства length можно узнать, как много веб-станиц хранится в стеке:
document.write("В истории " + history.length + " станиц");
Для перемещения по страницам в истории в объекте history определены методы back() (перемещение к прошлой посмотренной странице) и forward() (перемещение к следующей просмотренной странице).
history.back(); // перемещение назад
Также в объекте history определен специальный метод go(), который позволяет перемещаться вперед и назад по истории на определенное число страниц. Например, переместимся на 2 страницы назад:
history.go(-2);
Соответственно если надо переместиться на несколько страниц вперед, то в метод передается положительное значение. Например, переместимся вперед на три страницы:
history.go(3);
Объект location
Объект location содержит информацию о расположении текущей веб-страницы: URL, информацию о сервере, номер порта, протокол. С помощью свойств объекта мы можем получить эту информацию:
Например, пусть есть следующая веб-страница index.html, которая лежит на локальном веб-сервере:
document.write("Строка запроса: " + location.href + "<br />"); document.write("Путь к ресурсу: " + location.pathname + "<br />"); document.write("Схема: " + location.origin + "<br />"); document.write("Протокол: " + location.protocol + "<br />"); document.write("Порт: " + location.port + "<br />"); document.write("Хост: " + location.host + "<br />"); document.write("Имя хоста: " + location.hostname + "<br />"); document.write("Хэш: " + location.hash + "<br />"); document.write("Поиск: " + location.search + "<br />");
Результат:
Строка запроса: http://a-test.com/index.html?a=2&b=5 Путь к ресурсу: /index.html Схема: http://a-test.com Протокол: http: Порт: Хост: a-test.com Имя хоста: a-test.com Хэш: Поиск: ?a=2&b=5
Также объект location предоставляет ряд методов, которые можно использовать для управления путем запроса:
Для перенаправления на другой ресурс мы можем использовать как свойства, так и методы location:
location = "http://google.com"; // аналогично // location.href = "http://google.com"; // location.assign("http://google.com");
Переход на другой локальный ресурс:
location.replace("index.html");
Объект navigator
Объект navigator содержит информацию о браузере и операционной системе, в которой браузер запущен. Он определяет ряд свойств и методов, основным из которых является свойство userAgent, представляющее браузер пользователя:
document.write(navigator.userAgent);
Результат:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36
Чтобы вычленить из этой информации непосредственно браузер, можно попробовать найти в этой информации название браузера:
var browser, uAgent = navigator.userAgent; if(uAgent.indexOf("Chrome") > -1) { browser = "Google Chrome"; } else if (uAgent.indexOf("Safari") > -1) { browser = "Apple Safari"; } else if (uAgent.indexOf("Opera") > -1) { browser = "Opera"; } else if (uAgent.indexOf("Firefox") > -1) { browser = "Mozilla Firefox"; } else if (uAgent.indexOf("MSIE") > -1) { browser = "Microsoft Internet Explorer"; } document.write(browser);
Таймеры
Для выполнения действий через определенные промежутки времени в объекте window предусмотрены функции таймеров. Есть два типа таймеров: одни выполняются только один раз, а другие постоянно через промежуток времени.
- Функция setTimeout
Для одноразового выполнения действий через промежуток времени предназначена функция setTimeout(). Она может принимать два параметра:
var timerId = setTimeout(someFunction, period)
Параметр period указывает на промежуток, через который будет выполняться функция из параметра someFunction. А в качестве результата функция возвращает id таймера.
function timerFunction() { document.write("выполнение функции setTimeout"); } setTimeout(timerFunction, 3000);
В данном случае через 3 секунды после загрузки страницы произойдет срабатывание функции timerFunction.
Для остановки таймера применяется функция clearTimeout().
function timerFunction() { document.write("выполнение функции setTimeout"); } var timerId = setTimeout(timerFunction, 3000); clearTimeout(timerId);
- Функция setInterval
Функции setInterval() и clearInterval() работают аналогично функциям setTimeout() и clearTimeout() с той лишь разницей, что setInterval() постоянно выполняет определенную функцию через промежуток времени.
Например, напишем небольшую программу для вывода текущего времени:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <div id="time"></div> <script> function updateTime() { document.getElementById("time").innerHTML = new Date().toTimeString(); } setInterval(updateTime, 1000); </script> </body> </html>
Здесь через каждую секунду (1000 миллисекунд) вызывается функция updateTime(), которая обновляет содержимое поля <div id="time">, устанавливая в качестве его кода html текущее вемя.
- requestAnimationFrame()
Метод requestAnimationFrame() действует аналогично setInterval() за тем исключением, что он больше заточен под анимации, работу с графикой и имеет ряд оптимизаций, которые улучшают его производительность.
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <style> #rect { margin: 100px; width: 100px; height: 100px; background: #50c878; } </style> </head> <body> <div id="rect"></div> <script> var square = document.getElementById("rect"); var angle = 0; function rotate() { angle = (angle + 2)%360; square.style.transform = "rotate(" + angle + "deg)"; window.requestAnimationFrame(rotate); } var id = window.requestAnimationFrame(rotate); </script> </body> </html>
В метод window.requestAnimationFrame() передается функция, которая будет вызываться определенное количество раз (обычно 60) в секунду. В данном случае в этот метод передается функция rotate, которая изменяет угол поворота блока на странице и затем обращается опять же к методу window.requestAnimationFrame(rotate).
В качестве возвращаемого результата метод window.requestAnimationFrame() возвращает уникальный id, который может потом использоваться для остановки анимации:
window.cancelAnimationFrame(id);
DOM
Одой из ключевых задач JavaScript является взаимодействие с пользователем и манипуляция элементами веб-страницы. Для JavaScript веб-страница доступна в виде объектной модели документа (Document Object Model) или сокращенно DOM. DOM описывает структуру веб-страницы в виде древовидного представления и предоставляет разработчикам способ получить доступ к отдельным элементам веб-станицы.
Важно не путать понятия BOM (Browser Object Model - объектная модель браузера) и DOM (объектная модель документа). Если BOM предоставляет доступ к браузеру и его свойствам в целом, то DOM предоставляет доступ к отдельной веб-странице или html-документу и его элементам.
Например, рассмотрим простейшую страницу:
<!DOCTYPE html> <html> <head> <title>Page Title</title> </head> <body> <h2>Page Header</h2> <div> <h3>Block Header</h3> <p>Text</p> </div> </body> </html>
Дерево DOM для этой страницы будет выглядеть следующим образом:
Таким образом, все компоненты упорядочены в DOM иерархическим образом, где каждый компонент представляет отдельный узел. То есть каждый элемент, например, элемент div, представляет собой узел. Но также и текст внутри элемента представляет отдельный узел.
Существует следующие виды узлов:
Объект document
Для работы со структурой DOM в JavaScript предназначен объект document, который определен в глобальном объекте window. Объект document предоставляет ряд свойств и методов для управления элементами страницы.
- Поиск элементов
Для поиска элементов на странице применяются следующие методы:
Свойства объекта document
Кроме ранее рассмотренных методов объект document позволяет обратиться к определенным элементам веб-страницы через свойства:
Эти свойства не предоставляют доступ ко всем элементам, однако позволяют получить наиболее часто используемые элементы на веб-странице. Например, получим корневой узел документа:
var container = document.documentElement;
Получим все изображения на странице:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <img src="picure1.png" alt="Картинка 1" /> <img src="picure2.png" alt="Картинка 2" /> <img src="picure3.png" alt="Картинка 3" /> <script> var images = document.images; // изменим первое изображение images[0].src="pics/picture_4.jpg"; images[0].alt="Новая картинка"; // перебирем все изображения for(var i=0; i<images.length; i++) { document.write("<br/>" + images[i].src); document.write("<br/>" + images[i].alt); } </script> </body> </html>
Подобно тому, как в коде HTML мы можем установить атрибуты у элемента img, так и в коде JavaScript мы можем через свойства src и alt получить и установить значения этих атрибутов.
Объект node
Каждый отдельный узел, будь то html-элемент, его атрибут или текст, в структуре DOM представлен объектом Node. Этот объект предоставляет ряд свойств, с помощью которых мы можем получить информацию о данном узле:
Создание, добавление и удаление элементов веб-станицы
Для создания элементов объект document имеет следующие методы:
var elem = document.createElement("div"); var elemText = document.createTextNode("Привет мир");
Таким образом, переменная elem будет хранить ссылку на элемент div. Однако одного создания элементов недостаточно, их еще надо добавить на веб-страницу.
Для добавления элементов мы можем использовать один из методов объекта Node:
Используем метод appendChild:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <div class="article"> <h3>Заголовок статьи</h3> <p>Первый абзац</p> <p>Второй абзац</p> </div> <script> var articleDiv = document.querySelector("div.article"); // создаем элемент var elem = document.createElement("h2"); // создаем для него текст var elemText = document.createTextNode("Привет мир"); // добавляем текст в элемент в качестве дочернего элемента elem.appendChild(elemText); // добавляем элемент в блок div articleDiv.appendChild(elem); </script> </body> </html>
Сначала создаем обычный элемент заголовка h2 и текстовый узел. Затем текстовый узел добавляем в элемент заголовка. Затем заголовок добавляем в один из элементов веб-страницы.
Однако нам необязательно для определения текста внутри элемента создавать дополнительный текстовый узел, так как мы можем воспользоваться свойством textContent и напрямую ему присвоить текст:
var elem = document.createElement("h2"); elem.textContent = "Привет мир";
- Копирование элемента
Иногда элементы бывают довольно сложными по составу, и гораздо проще их скопировать, чем с помощью отдельных вызовов создавать их содержимое. Для копирования уже имеющихся узлов у объекта Node можно использовать метод cloneNode():
var articleDiv = document.querySelector("div.article"); // клонируем элемент articleDiv var newArticleDiv = articleDiv.cloneNode(true); // добавляем в конец элемента body document.body.appendChild(newArticleDiv);
В метод cloneNode() в качестве параметра передается логическое значение: если передается true, то элемент будет копироваться со всеми дочерними узлами; если передается false - то копируется без дочерних узлов. То есть в данном случае мы копируем узел со всем его содержимым и потом добавляем в конец элемента body.
- Удаление элемента
Для удаления элемента вызывается метод removeChild() объекта Node. Этот метод удаляет один из дочерних узлов:
var articleDiv = document.querySelector("div.article"); // находим узел, который будем удалять - первый параграф var removableNode = document.querySelectorAll("div.article p")[0]; // удаляем узел articleDiv.removeChild(removableNode);
данном случае удаляется первый параграф из блока div.
- Замена элемента
Для замены элемента применяется метод replaceChild(newNode, oldNode) объекта Node. Этот метод в качестве первого параметра принимает новый элемент, который заменяет старый элемент oldNode, передаваемый в качестве второго параметра.
Объект element
Кроме методов и свойств объекта Node в JavaScript мы можем использовать свойства и методы объектов Element. Важно не путать эти два объекта: Node и Element. Node представляет все узлы веб-станицы, в то время как объект Element представляет непосредственно только html-элементы. То есть объекты Element - это фактически те же самые узлы - объекты Node, у которых тип узла (свойство nodeType) равно 1.
Одним из ключевых свойств объекта Element является свойство tagName, которое возвращает тег элемента. Например, получим все элементы, которые есть на странице:
function getChildren(elem) { for(var i in elem.childNodes) { if(elem.childNodes[i].nodeType === 1) { console.log(elem.childNodes[i].tagName); getChildren(elem.childNodes[i]); } } } var root = document.documentElement; console.log(root.tagName); getChildren(root);
Здесь вначале получаем тело корневого элемента <html> и затем с помощью рекурсивной функции getChildren получаем все вложенные элементы.
- Свойства innerText и innerHTML
Для получения или установки текстового содержимого элемента мы можем использовать свойство innerText, а для получения или установки кода html - свойство innerHTML.
Надо отметить, что свойство innerText во многом аналогично свойству textContent. То есть следующие вызовы будут равноценны:
var pElement = document.querySelectorAll("div.article p")[0]; pElement.innerText = "hello"; pElement.textContent = "hello";
Установка кода html у элемента:
var articleDiv = document.querySelector("div.article"); articleDiv.innerHTML ="<h2>Hello World!!!</h2><p>bla bla bla</p>";
- Методы объекта Element
Среди методов объекта Element можно отметить методы управления атрибутами:
- Размеры и позиция элементов
Элементы имеют ряд свойств, которые позволяют определить размер элемента. Но важно понимать разницу между всеми этими свойствами.
Свойства offsetWidth и offsetHeight определяют соответственно ширину и высоту элемента в пикселях. В ширину и высоту включается граница элемента.
Свойства clientWidth и clientHeight также определяют ширину и высоту элемента в пикселях, но уже без учета границы.
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <style> #rect { width: 100px; height: 100px; background: #50c878; border: 3px solid silver; } </style> </head> <body> <div id="rect"></div> <script> var rect = document.getElementById("rect"); console.log("offsetHeight: " + rect.offsetHeight); // 106 console.log("offsetWidth: " + rect.offsetWidth); // 106 console.log("clientHeight: " + rect.clientHeight); // 100 console.log("clientWidth: " + rect.clientWidth); // 100 </script> </body> </html>
Поскольку у блока div определена граница в 3 пикселя, то по сравнению с clientHeight/clientWidth к offsetHeight/offsetWidth добавляет по 6 пикселей.
Изменение стиля элементов
Для работы со стилевыми свойствами элементов в JavaScript применяются, главным образом, два подхода:
- Свойство style
Свойство style представляет сложный объект для управления стилем и напрямую сопоставляется с атрибутом style html-элемента. Этот объект содержит набор свойств CSS: element.style.свойствоCSS. Например, установим цвет шрифта:
var root = document.documentElement; // устанавливаем стиль root.style.color = "blue"; // получаем значение стиля document.write(root.style.color); // blue
В данном случае название свойства color совпадает со свойством css. Аналогично мы могли бы установить цвет с помощью css:
html { color:blue; }
Однако ряд свойств css в названиях имеют дефис, например, font-family. В JavaScript для этих свойств дефис не употребляется. Только первая буква, которая идет после дефиса, переводится в верхний регистр:
var root = document.documentElement; root.style.fontFamily = "Verdana";
- Свойство className
С помощью свойства className можно установить атрибут class элемента html. Например:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <style> .blueStyle { color:blue; font-family:Verdana; } .article { font-size:20px; } </style> </head> <body> <div class="article"> <h3>Заголовок статьи</h3> <p>Первый абзац</p> <p>Второй абзац</p> </div> <script> var articleDiv = document.querySelector("div.article"); // установка нового класса articleDiv.className = "blueStyle"; // получаем название класса document.write(articleDiv.className); </script> </body> </html>
Благодаря использованию классов не придется настраивать каждое отдельное свойство css с помощью свойства style.
Но при этом надо учитывать, что прежнее значение атрибута class удаляется. Поэтому, если нам надо добавить класс, надо объединить его название со старым классом:
articleDiv.className = articleDiv.className + " blueStyle";
И если надо вовсе удалить все классы, то можно присвоить свойству пустую строку:
articleDiv.className = "";
- Свойство classList
Выше было рассмотрено, как добавлять классы к элементу, однако для управления множеством классов гораздо удобнее использовать свойство classList. Это свойство представляет объект, реализующий следующие методы: