Браузер и JS

Олег Мохов

Из этой лекции можно сделать отдельный курс, а мы пробежим по верхам, т.к есть реакт
Это не значит что всё эти знания вам не пригодятся

Learn JavaScript. Часть 2

Браузер

  • JavaScript
  • Глобальный объект window
  • Document Object Model
  • Browser Object Model

Проблемы JavaScript в браузере?

  • Мы не можем выбирать браузер пользователя
  • Мы не можем выбирать версию браузера пользователя
  • Мы не можем менять настройки пользователя

window

  • Содержит свойства и методы для управления окном браузера, открытия новых окон
  • window.open('http://urfu.ru')

BOM

  • Объект navigator: navigator.userAgent, navigator.platform
  • Объект location: текущий урл и разные перенаправления
  • Функции alert/prompt/confirm

DOM

Типы узлов

  • В DOM 12 типов узлов, но мы работаем с 4
  • Документ – объект document
  • Элементы – теги
  • Текст
  • Комментарии – в них можно включить информацию, которая будет доступна из JS

Навигация по узлам


<div>
    <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</div>

null

  • Если узла нет или узел не найден, то это null
  • document есть всегда, document.body может быть равен null

childNodes – это коллекция, а не массив

Навигация по узлам

Поиск элементов

document.getElementById('id')

  • Ищет элемент с заданным идентификатором
  • Возращает первый найденный элемент

getElementsByClassName(class)

  • Есть не только у document, но и у любого элемента
  • Ищет элементы с соответствующим классом
  • Возращает коллекцию
  • document.getElementsByClassName('class class2')
    не вернет
    <div class="class class2">

getElementsByTagName('tag')

  • Есть не только у document, но и у любого элемента
  • Ищет элементы соответствующего тега
  • Возращает коллекцию

jQuery

querySelectorAll(selector)

  • Возвращает коллекцию по заданному CSS селектору
  • Псевдоселекторы тоже работают, т.е :hover вернет всё дерево элементов на которые мы навелись

Пример



var menu = document.querySelectorAll('.menu')[0];
var listItems = menu.querySelectorAll('li');

querySelector(selector)

  • Возвращает первый найденный элемент по заданному селектору
  • document.querySelector('.class.class2')
    вернет
    <div class="class class2">

matches(selector)

  • Проверяет соответствует ли текущий элемент селектору
  • Возвращает true или false

closest(selector)

  • Ищет ближайший элемент, соответствующий селектору вверх по DOM-дереву относительно текущего

Внутреннее устройство поисковых методов

Свойства узлов

node.nodeType

  • Тип узла
  • Это число
  • Всего 12, но пользуемся 2 (Остальные)
  • 1 – ELEMENT_NODE
  • 3 – TEXT_NODE

node.nodeName и node.tagName

  • Оба свойства содержат имя тега
  • nodeName вернет имя тега ближайшего ELEMENT_NODE родителя для TEXT_NODE

innerHTML

  • Содержит содержимое элемента в виде строки
  • innerHTML += осуществляет перезапись
  • Скрипты не выполняются

outerHTML

  • Содержит HTML элемента целиком
  • Доступно на запись, но в результате получается новый элемент

Пример


var div = document.querySelector('div');
console.log(div); // <div>Привет</div>
div.innerHTML = 'Hi!'
console.log(div); // <div>Hi!</div>
div.outerHTML = '<div>Здарова</div>'
console.log(div) // <div>Hi!</div>

textContent

  • Содержит только текст внутри элемента, за вычетом всех <тегов>

hidden

  • Виден ли элемент
  • Работает как для CSS, так и для соответствующего атрибута

Атрибуты

  • element.[get/has/set/remove]Attribute
  • attributes – коллекция всех атрибутов элемента

Классы

  • className – в виде строки
  • classList – объект для работы с классами
  • classList.[add/remove/toggle] – добавить/удалить класс
  • classList.contains – есть ли класс

data-*

  • Все data-* атрибуты доступны в объекте dataset
  • data-user-location будет доступно в element.dataset.userLocation

Добавление и удаление узлов

document.createElement


var div = document.createElement('div');
div.className = "alert alert-success";
div.innerHTML = "Ура!";

appendChild


  1. 0
  2. 1
  3. 2
<script> var newLi = document.createElement('li'); newLi.innerHTML = '3'; // newLi.appendChild(document.createTextNode('3')) list.appendChild(newLi); </script>

insertBefore


  1. 0
  2. 1
  3. 2
<script> var newLi = document.createElement('li'); newLi.innerHTML = '0.5'; list.insertBefore(newLi, list.children[1]); </script>

Удаление

  • parentElem.removeChild(elem) – удаляет elem из детей parentElem
  • elem.remove() – то же самое, но не поддерживается IE11-
  • parentElem.replaceChild(newElem, elem) – удаляет elem из детей parentElem и вставляет на его место newElem
  • classList.contains – есть ли класс

elem.cloneNode

  • Создаёт копию текущего элемента
  • Если в качестве аргумента передать true, то создаст глубокую копию элемента, включая атрибуты и подэлементы

События

События мыши

  • click – происходит, когда кликнули на элемент левой кнопкой мыши
  • contextmenu – происходит, когда кликнули на элемент правой кнопкой мыши
  • mouseover – возникает, когда на элемент наводится мышь
  • mousedown и mouseup – когда кнопку мыши нажали (down) или отжали (up)
  • mousemove – при движении мыши над элементом

События пальцев

  • touchstart – происходит, когда элемента коснулись
  • touchmove – происходит, когда по элементу провели пальцем
  • touchend – возникает, когда касание закончилось и палец убрали
  • touchcancel – палец переместился на интерфейс браузера или тач-событие нужно отменить

Ещё события

  • submit – отправка формы
  • focus – фокус на элементе
  • keyup/keydown – печать на клавиатуре
  • DOMContentLoaded
  • transitionend – закончена CSS-анимация

Ещё больше событий

Назначение обработчика событий


  • Щелкни меня

  • 
    var li = document.getElementByTagName('li')[0];
    li.onclick = function () { alert('привет'); }
    

    
    li.addEventListener('click', () => {
        alert('привет');
    });
    

    Удаление обработчика событий

    
    var li = document.getElementByTagName('li')[0];
    li.addEventListener('click', ()=>alert('привет'));
    // не работает
    li.removeEventListener('click', ()=>alert('привет'));
    

    
    var li = document.getElementByTagName('li')[0];
    var onClickHandler = () => {
        alert('привет');
    }
    li.addEventListener('click', onClickHandler);
    li.removeEventListener('click', onClickHandler);
    

    Особенности событий

    
    
    
    FORM
    DIV

    P

    FORM
    DIV

    P

    Event

    
    var li = document.getElementByTagName('li')[0];
    var onClickHandler = (event) => {}
    li.addEventListener('click', onClickHandler);
    li.removeEventListener('click', onClickHandler);
    

    Не все события всплывают, но при этом их можно поймать на этапе захвата.
    Например, focus

    Самый глубокий элемент, который вызывает событие, называется «целевым» или «исходным» элементом и доступен как event.target.

    event.target

    
    
    

    event.target

    
    
    

    event.target

    Работа с событием

    • event.preventDefault – отменяет обработчик по-умолчанию
    • event.stopPropagation – прекращает всплытие
    • event.stopImmediatePropagation – прекращает всплытие и не выполняет оставшиеся обработчики события

    Паттерны работы с событиями

    Делегирование

    
    var links = document.querySelectorAll('.menu a');
    var clicked = {};
    var onClick = function () {
        clicked[this.href] = clicked[this.href] || 0;
        clicked[this.href]++;
    
        console.log(clicked);
    };
    for (var i = 0; i < links.length; i++) {
        links[i].addEventListener('click', onClick);
    }
    

    Делегирование

    Делегирование

    
    var menu = document.querySelector('.menu');
    var clicked = {};
    var onClick = function (e) {
        var href = e.target.href;
        clicked[href] = clicked[href] || 0;
        clicked[href]++;
    
        console.log(clicked);
    };
    menu.addEventListener('click', onClick);
    

    Делегирование

    
    var menu = document.querySelector('.menu');
    var clicked = {};
    var onClick = function (e) {
        if (e.target.nodeName !== 'A') return;
    
        var href = e.target.href;
        clicked[href] = clicked[href] || 0;
        clicked[href]++;
    
        console.log(clicked);
    };
    menu.addEventListener('click', onClick);
    
    
    
    var menu = document.querySelector('input');
    var onKeyDown = function (e) {
        var text = e.target.value;
    
        makeRequest(text, function (response) {
            showSuggest(response); <-
        });
    };
    menu.addEventListener('keydown', onKeyDown);
    
    

    debounce

    
    function debounce(func, wait, immediate) {
        var timeout;
        return function() {
            var context = this, args = arguments;
            var later = function() {
                timeout = null;
                if (!immediate) func.apply(context, args);
            };
            var callNow = immediate && !timeout;
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
            if (callNow) func.apply(context, args);
        };
    };
    
    
    var menu = document.querySelector('input');
    var onKeyDown = debounce(function (e) {
        var text = e.target.value;
    
        makeRequest(text, function (response) {
            showSuggest(response);
        });
    }, 300);
    menu.addEventListener('keydown', onKeyDown);
    

    Ajax

    Asynchronous JavaScript + XML

    XMLHttpRequest

    Fetch

    
    new Fetch('https://mysite.com/getdata')
        .then((response) => console.log(response));
    

    Ссылки