Зміст

    Нотатки з Javascript (частина 2)

    09.06.2025

    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');
    });