DOM
Для обращения к объекту document недостаточно просто указать его название, так как document не является объектом DOM. Для вызова DOM объекта Document используйте document.documentElement:
document.documentElement;
document.head;
document.body;Получение объекта на странице
document.querySelector('.nav');
document.getElementById('home-button');
document.getElementsByTagName('button');
document.getElementsByClassName('my-class');При выполнении поиска всех элементов на странице, которые соответствуют условию поиска будет возвращен список нод, который не является массивом и поэтому методы объекта Array к нему не применимы. Для преобразования node list в массив используется [...nodeList]
const menu_items = [...document.querySelectorAll('.nav.items')];
menu_items.foreach(function(el, i) {
if (i % 2 === 0) el.style.backgroundColor = 'green';
});Метод document.getElementsByTagName() и document.getElementsByClassName() возвращают объект HTMLCollection, который отличается от NodeList тем, что он автоматически меняется в зависимости от изменений, которые происходят на странице. Например если удалить кнопку на странице, то при чтении HTMLCollection ее там уже не будет, даже если информация об этой кнопке была, когда выполняли метод document.getElementsByTagName('button');
Выбор дочерних элементов DOM
const h1 = documnet.querySelector('h1');
// Child Nodes
h1.querySelectorAll('.light');
h1.childNodes;
h1.children;
h1.firstElementChild;
h1.lastElementChild;h1.childNodes возвращает все части, страницы, которые находятся ниже по иерархии. Это включает в себя и текст и комментарии. Если же надо работать только с HTML элементами, то в таком случае используйте h1.children, который вернет HTMLCollection, а не NodeList.
Родительские элементы
h1.parentNode;
h1.parentElement;В случае, если нам нужно получить родительский элемент не зависимо насколько далеко он находится от текущего элемента, то для этого используется:
h1.closest('.header');Метод closest работает так же и принимает такую же поисковую строку, как и querySelector, только по направлению к родительским элементам.
Соседние элементы
Для перехода к соседним элементам, которые находятся на том же уровне используются следующие методы:
h1.previousSibling;
h1.nextSibling;
h1.previousElementSibling;
h1.nextElementSibling;Как создать и добавить DIV на страницу
Не смотря на то, что в приведенном ниже примере выполняется добавление элемента и в начало и в конец страницы, он появится только в конце, так как это один и тот же элемент DOM, который мы просто перемещаем в пределах страницы.
let el = document.createElement('DIV');
el.classList.add('footer');
el.textContent = 'Bottom page text';
el.innerHTML = 'Bottom page text <button></button>';
const body = document.querySelector('.body');
// add to top of the page
body.prepend(el);
// move element from the top to the bottom
body.append(el);
если необходимо скопировать элемент для размещения в нескольких местах, то элемент DOM необходимо клонировать:
el2 = el.cloneNode();
body.append(el2);
body.before(el);
body.after(el);
// Remove element from DOM structure
el.remove();
el.parentElement.removeChild(el);Добавление HTML элементов на страницу
menu.insertAdjacentHTML('afterbegin', '<div class="menu">One more item</div>');
<!-- beforebegin -->
<div class="nav">
<!-- afterbegin -->
...
text
...
<!-- beforeend -->
</div>
<-- afterend -->Изменение содержимого элемента:
menu.innerHTML = '';Чтение нестандартных атрибутов HTML
К стандартным атрибутам HTML можно обращаться как к свойствам объекта в JavaScript.
// HTML
< img src="photo.jpg" alt="My family" class="rounded" author="John">
// JavaScript
img.src;
// http://127.0.0.1/photo.jpg
img.alt;
// My family
img.className;
// rounded
img.author;
// undefinedДля чтения нестандартного атрибута author используется метод getAttribute(). Так же этот метод полезен для получения данных, которые указаны в HTML свойствах img.src и a.href, так как если обращаться к этим свойствам напрямую, то получим абсолютные URL, а getAttribute() вернет именно то значение, которое указано в HTML теге.
img.getAttribute('author');
// John
img.getAttribute('src');
// photo.jpgУстанавливать значения нестандартных аттрибутов можно с помощь метода element.setAttribute():
img.setAttribute('author', 'John');Для чтения специальной группы аттрибутов, которые начинаются с data-* можно использовать свойство dataset:
< img src="img.webp" data-version-number="1.0">
img.dataset.versionNumber;
// 1.0Работа со стилями
Для чтения стилей, которые применяются к DOM элементу используется функция getComputedStyles, которая вернет значение стиля объекта, который выводится в DOM. Если же использовать el.style.height, то такое значение будет пустым, если оно не было прописано в HTML или CSS для данного объекта.
el.style.backgroundColor = 'red';
// list of all styles applied to DOM element
getComputedStyles(el);
getComputedStyles(el).height;Работа с классами
Не стоит указывать класс для объекта явным указанием значения для свойства
img.className = 'rounded';так как это перезапишет все классы, назначенные картинке. Правильней для управления классами использовать методы:
div.classList.add('ui', 'red', 'mini', 'button');
div.classList.remove('red', 'mini');
div.classList.toggle('red');
div.classList.contains('ui');Управления свойствами CSS
// CSS
:root {
--main-color: 'silver';
}
// JS
document.documentElement.style.setProperty('--main-color', 'white');
Как определить размеры окна в JS
document.documentElement.clientHeight;
// 768
document.documentElement.clientWidth;
// 1024Получение координат объекта на странице
button.getBoundingClientRect();
// DOMRect {x: 274.9375, y: 341.859375, width: 207.2578125,
// height: 41.140625, top: 341.859375, …}
// Scrolling offset
window.pageYOffset;
// 421.54
Как сделать плавный скроллинг
Обратите внимание на то, что в window.scrollTo() передается объект.
let coord = document.querySelector('h1').getBoundingBoxRect();
window.scrollTo({
left: coord.left + window.pageXOffset,
top: coord.top + window.pageYOffset,
behavior: 'smooth'
});Более современный способ плавно проскролить окно браузера до нужного элемента:
document.querySelector('h1').scrollIntoView({behavior: 'smooth'});События
Для перехвата и обработки события используется метод addEventListener.
const button = document.querySelector('button');
button.addEventlistener('click', function(e) {
// Prevent form from submitting
e.preventDefault();
...
});или же можно использовать устаревший метод и назначить функцию свойству элемента:
button.onclick = function(e) {
console.log(e.target);
}Рекомендуется использовать addEventListener так как это более современный способ перехвата событий. Так же addEventlistener позволяет указывать несколько функций, которые будут перехватывать событие.
Отключить перехват события можно методом removeEventListener. В качестве параметров метод принимает тип события и название функции, которую надо отключить в обработчике событий. Поэтому не забывайте вместо анонимной функции в addEventListener использовать именованную, так как анонимную функцию не получится удалить из обработчика.
const testFunction = function (e) {
alert('Click event!');
e.target.removeEventListener('click', testFunction);
}
button.addEventListener('click', testFunction);Функция, которая обрабатывает события принимает параметр, который содержит информацию о произошедшем событии. Свойство e.target указывает на элемент, на котором произошло событие. Свойство e.currentTarget и объект this, указывают на элемент, к которому привязано событие. В большинстве случаев это один и тот же элемент. Но если перехват события происходит элементом, который является родительским для элемента на котором было нажатие кнопки мышки, то e.currentTarget и e.target будут отличаться. Например есть div, внутри которого находится button и мы слушаем событие не на кнопке, а на находящемся ниже в иерархии DOM слое, то e.target будет указывть на button, а e.currentTarget или this - на элемент div.
< div>
< button>Test</ button>
< /div>
// JavaScript
document.querySelector('div').addEventListener('click', function(e) {
console.log('The user clicked: ' + e.target);
console.log('The eventListener connected to ' + this);
})
// The user clicked on button
// The event listener connected to div
Передача информации о событии в родительские элементы описана в системе обработке событий JavaScript и называется event capturing and bubbling. После клика по объекту, все родительские объекты получают то же самое событие, например нажатие на кнопку мышки. Стоит заметить, что не все события имеют bubbling и передают информацию о событии родителям. Например mouseenter.
Чтобы остановить распространение события на родительские элементы необходимо в функции, которая перехватывает события вызвать метод e.stopPropagation().
< div>
< button>Test</ button>
< /div>
// JavaScript
document.querySelector('button').addEventListener('click', function(e) {
console.log('The user clicked on button');
e.stopPropagation();
});
document.querySelector('div').addEventListener('click', function(e) {
console.log('The click propagate to div');
});
Как ускорить работу JS если на странице много элементов, которые обрабатывают события
Если в интерфейсе находится много кнопок, к каждой из которых привязано событие, например открытие контекстного меню, то в таких случаях это может привести к замедлению работы страницы. Это связано с тем, что мы назначаем на каждую кнопку перехватчик события и функцию, которая будет его обрабатывать. Чтобы ускорить работу браузера используется техника, называемая event delegation, когда событие назначается родительскому элементу всех кнопок, а не каждой кнопке по отдельности. Это позволяет вместо десятков событий обрабатывать только одно. В самом же событии определяем кнопку, которая была нажата при помощи e.target:
div.addEventListener('click', function(e) {
const clickedButton = e.target;
console.log(clickedButton);
});Как передать в событие дополнительные параметры
Иногда функция, которая обрабатывает события должна принимать дополнительные параметры. Например есть функция, которая меняет цвет фона и размер шрифта при нажатии на разные кнопки. Поэтому в каждый обработчик события неплохо было бы передать еще цвет.
function bg(e) {
console.log(this);
document.body.style.backgroundColor = this.color;
document.body.style.fontSize = this.size;
}
document.querySelector('button').addEventListener('click', bg.bind({
color:'red',
size: '14px'
}));