Нотатки з Javascript (частина 2)
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');
Як створити і додати 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. Але для таких ситуацій функція, яку ми спочатку призначаємо, не може бути анонімною.
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. Після кліка по об'єкту всі батьківські об'єкти отримують ту саму подію, наприклад натискання на кнопку мишки.
Щоб зупинити поширення події на батьківські елементи, необхідно у функції, яка перехоплює події, викликати метод 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');
});