Javascript / dom: как удалить все события объекта dom?

Методы для добавления и удаления элементов массива

Итак, допустим у вас есть массив, в который вам необходимо добавить новый элемент. Для этого в JavaScript есть несколько методов.

push()

Этот метод добавляет новые элементы в конец массива. Принимает как аргумент элементы, которые нужно добавить, а возвращает длину нового массива:

  let arr = ;
  arr.push("Banana"); // добавление одного элемента
  arr.push("Cherry", "Lemon"); // добавление сразу нескольких элементов

  console.log(arr); // 

  let arrLength = arr.push("Lime"); // В переменной arrLength будет сохранена длина нашего массива - 6 элементов

  console.log('Length', arrLength); // Length 6

pop()

С помощью данного метода можно удалить последний элемент массива, а возвращает он значение этого элемента

Допустим вы хотите удалить элемент Lime, который мы добавили в массив раннее.

  let arr = ;
  let removedEl = arr.pop(); // Удаляем элемент массива и получаем его значение, если это нужно для дальнейшей работы.
  console.log('Удаленный элемент - ', removedEl); // Lime
  
  arr.pop() // А так мы просто удалим последний элемент

shift()

С помощью данного метода мы можем извлечь элемент из начала массива.

Также есть «зеркальный» метод для добавления элемента в начало массива — . Только тут при добавлении нового элемента возвращается длинна нового массива (см. строку 9):

  let arr = ;
  let firstEl = arr.shift();

  console.log('Первый элемент - ', firstEl);
  console.log('Массив', arr); // 

  let lengthArr = arr.unshift('Apple 2');
  console.log('Новый массив', arr); // 
  console.log('Длинна нового массива', lengthArr); // 6

splice()

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

Итак, он принимает в качестве аргумента:

— индекс элемента, с которого нужно начать изменения

— количество элементов для удаления. Если вы не хотите удалять, тогда нужно передать 0 в этот аргумент.

— добавляемый элемент массива. Если третьим параметром ничего не передать, тогда будет произведено просто удаление

Теперь давайте рассмотрим на примере как удалить несколько элементов из массива:

  let arr = ;
  arr.splice(0, 3); // удалит с 0 (включительно) по 3 элемент (не включая его)

  console.log(arr); // 

Чтобы удалить например элементы Bannana, Cherry нам нужно начать с индекса 2 и передать 2 (количество удаляемых элементов):

  let arr = ;
  arr.splice(2, 2); // удалим элементы "Banana" и "Cherry"

  console.log(arr); // 

Теперь давайте добавим эти же элементы в середину массива:

  let arr = ;
  arr.splice(2, 0, "Banana", "Cherry");

  console.log(arr); // 

slice()

Этот метод возвращает новый массив, «вырезанный» по заданным в аргументах индексам. При этом оригинальный массив остается неизменным.

— необязательный — индекс элемента, от которого следует начинать отсчет. Если задать отрицательное число, отсчет пойдет с конца массива.

— необязательный — индекс последнего элемента «вырезаемого» из массива. Если этот аргумент не передан, будет вырезан отрезок от start до конца массива.

  let arr = ;

  let newArr = arr.slice(1, 3); // 

  let newArr2 = arr.slice(3); // 

concat()

Возвращает новый массив, к которому добавлены новые элементы, переданные как аргументы в данный метод.

  let arr1 = ;
  let arr2 = ;

  let arr3 = arr1.concat(arr2); 

  console.log(arr3); // 

Мы взяли массив arr2 и с помощью метода соединили его с arr1. В итоге мы получили новый массив из 6 элементов.

Вы можете передать столько аргументов, сколько необходимо. Например,

Несколько слов о «document.write»

Есть ещё один, очень древний метод добавления содержимого на веб-страницу: .

Синтаксис:

Вызов записывает на страницу «прямо здесь и сейчас». Строка может быть динамически сгенерирована, поэтому метод достаточно гибкий. Мы можем использовать JavaScript, чтобы создать полноценную веб-страницу и записать её в документ.

Этот метод пришёл к нам со времён, когда ещё не было ни DOM, ни стандартов… Действительно старые времена. Он всё ещё живёт, потому что есть скрипты, которые используют его.

В современных скриптах он редко встречается из-за следующего важного ограничения:

Вызов работает только во время загрузки страницы.

Если вызвать его позже, то существующее содержимое документа затрётся.

Например:

Так что после того, как страница загружена, он уже непригоден к использованию, в отличие от других методов DOM, которые мы рассмотрели выше.

Это его недостаток.

Есть и преимущество. Технически, когда запускается во время чтения HTML браузером, и что-то пишет в документ, то браузер воспринимает это так, как будто это изначально было частью загруженного HTML-документа.

Поэтому он работает невероятно быстро, ведь при этом нет модификации DOM. Метод пишет прямо в текст страницы, пока DOM ещё в процессе создания.

Так что, если нам нужно динамически добавить много текста в HTML, и мы находимся на стадии загрузки, и для нас очень важна скорость, это может помочь. Но на практике эти требования редко сочетаются. И обычно мы можем увидеть этот метод в скриптах просто потому, что они старые.

Действие браузера по умолчанию

Браузер имеет своё собственное поведение по умолчанию для различных событий.

В ряде случаев реакцию браузера на событие можно убрать в обработчике.Для этого у IE и W3C есть, как и раньше, два по сути близких, но по виду разных способа:

element.onclick = function(event) {
    event = event || window.event 

    if (event.preventDefault) {
        // Вариант стандарта W3C: 
        event.preventDefault()
    } else {
        // Вариант Internet Explorer:
        event.returnValue = false
    }
}

Вместо можно записать одну строчку:

..
event.preventDefault ? event.preventDefault() : (event.returnValue=false)
...

Некоторые поведения по умолчанию происходят до вызова обработчика события. В этом случае их, конечно же, отменить нельзя.

Например, при фокусировке на ссылке — браузер выделяет ее пунктирной рамочкой.
Это действие выполняется до события , поэтому отменить выделение в обработчике нельзя.

При клике перехода не произойдет, а рамка вокруг ссылки появится.

Код примера:

var a = document.getElementById('my-focus-a')
a.onfocus = a.onclick = function(e) {
    e = e || window.event
    // другая кроссбраузерная запись остановки события
    e.preventDefault ? e.preventDefault() : (e.returnValue=false)
}

Дети: childNodes, firstChild, lastChild

Здесь и далее мы будем использовать два принципиально разных термина:

  • Дочерние узлы (или дети) – элементы, которые являются непосредственными детьми узла. Другими словами, элементы, которые лежат непосредственно внутри данного. Например, и являются детьми элемента .
  • Потомки – все элементы, которые лежат внутри данного, включая детей, их детей и т.д.

В примере ниже детьми тега являются теги и (и несколько пустых текстовых узлов):

…А потомки – это и прямые дети , и вложенные в них: (потомок ) и (потомок ) – в общем, все элементы поддерева.

Коллекция содержит список всех детей, включая текстовые узлы.

Пример ниже последовательно выведет детей :

Обратим внимание на маленькую деталь. Если запустить пример выше, то последним будет выведен элемент

На самом деле, в документе есть ещё «какой-то HTML-код», но на момент выполнения скрипта браузер ещё до него не дошёл, поэтому скрипт не видит его.

Свойства и обеспечивают быстрый доступ к первому и последнему дочернему элементу.

Они, по сути, являются всего лишь сокращениями. Если у тега есть дочерние узлы, условие ниже всегда верно:

Для проверки наличия дочерних узлов существует также специальная функция .

Как мы уже видели, похож на массив. На самом деле это не массив, а коллекция – особый перебираемый объект-псевдомассив.

И есть два важных следствия из этого:

  1. Для перебора коллекции мы можем использовать :

Это работает, потому что коллекция является перебираемым объектом (есть требуемый для этого метод ).

  1. Методы массивов не будут работать, потому что коллекция – это не массив:

Первый пункт – это хорошо для нас. Второй – бывает неудобен, но можно пережить. Если нам хочется использовать именно методы массива, то мы можем создать настоящий массив из коллекции, используя :

DOM-коллекции – только для чтения

DOM-коллекции, и даже более – все навигационные свойства, перечисленные в этой главе, доступны только для чтения.

Мы не можем заменить один дочерний узел на другой, просто написав .

Для изменения DOM требуются другие методы. Мы увидим их в следующей главе.

DOM-коллекции живые

Почти все DOM-коллекции, за небольшим исключением, живые. Другими словами, они отражают текущее состояние DOM.

Если мы сохраним ссылку на и добавим/удалим узлы в DOM, то они появятся в сохранённой коллекции автоматически.

Не используйте цикл для перебора коллекций

Коллекции перебираются циклом . Некоторые начинающие разработчики пытаются использовать для этого цикл .

Не делайте так. Цикл перебирает все перечисляемые свойства. А у коллекций есть некоторые «лишние», редко используемые свойства, которые обычно нам не нужны:

Удаление всех элементов внутри родителя

Часто бывает такая ситуация, что внутри родительского элемента необходимо удалить все узлы-потомки. Например, в том же списке нужно оставить или с каким-либо , но удалить все вложенные . Для этого можно воспользоваться свойством или , или же , присвоив в него пустую строку:

Замена содержимого элемента пустой строкой

JavaScript

someElem.innerHTML = »;
//или
someElem.innerText = »;
//или
someElem.textContent= »;

1
2
3
4
5

someElem.innerHTML=»;

//или

someElem.innerText=»;

//или

someElem.textContent=»;

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

Удаление всех потомков-детей в элементе

JavaScript

while (node.firstChild) {
node.removeChild(node.firstChild);
}
//или
while (node.lastChild) {
node.removeChild(node.lastChild);
}
//или
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
//или с использованием метода remove()
//для node.firstChild
while (node.firstChild) {
node.firstChild.remove();
}
//для node.lastChild
while (node.lastChild) {
node.lastChild.remove();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

while(node.firstChild){

node.removeChild(node.firstChild);

}
//или

while(node.lastChild){

node.removeChild(node.lastChild);

}
//или

while(node.hasChildNodes()){

node.removeChild(node.lastChild);

}
//или с использованием метода remove()
//для node.firstChild

while(node.firstChild){

node.firstChild.remove();

}
//для node.lastChild

while(node.lastChild){

node.lastChild.remove();

}

Переменная в приведенных примерах — это тот элемент (узел), в котором нужно удалить вложенные (дочерние) элементы.

В примере ниже мы используем различные виды удаления вложенных элементов списка с возможностью его восстановить и попробовать другие.

  • Элемент списка 1
  • Элемент списка 2
  • Элемент списка 3
  • Элемент списка 4
  • Элемент списка 5

Заменить пустой строкой
innerHTML
innerText
textContent
Вернуть список
Удалить все элементы li

Удаляем всех детей внутри элемента

JavaScript

<div class=»test»>
<ul id=»forRemove»>
<li>Элемент списка 1</li>
<li>Элемент списка 2</li>
<li>Элемент списка 3</li>
<li>Элемент списка 4</li>
<li>Элемент списка 5</li>
</ul>
<fieldset style=»margin: 10px 0″>
<legend>Заменить пустой строкой</legend>
<button class=»btn» onclick=»forRemove.innerHTML = »»>innerHTML</button>
<button class=»btn» onclick=»forRemove.innerText = »»>innerText</button>
<button class=»btn» onclick=»forRemove.textContent = »»>textContent</button>
</fieldset>
<button class=»btn btn-primary» id=»reList» onclick=»myNode.innerHTML = liElems»>Вернуть список</button>

<button class=»btn» onclick=»removeLiElements()»>Удалить все элементы li</button>

<script>
var myNode = document.getElementById(«forRemove»),
liElems = myNode.innerHTML;

function removeLiElements() {
while (myNode.firstChild) {
myNode.removeChild(myNode.firstChild);
}
}
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

<div class=»test»>

<ul id=»forRemove»>

<li>Элементсписка1<li>

<li>Элементсписка2<li>

<li>Элементсписка3<li>

<li>Элементсписка4<li>

<li>Элементсписка5<li>

<ul>

<fieldset style=»margin: 10px 0″>

<legend>Заменитьпустойстрокой<legend>

<button class=»btn»onclick=»forRemove.innerHTML = »»>innerHTML<button>

<button class=»btn»onclick=»forRemove.innerText = »»>innerText<button>

<button class=»btn»onclick=»forRemove.textContent = »»>textContent<button>

<fieldset>

<button class=»btn btn-primary»id=»reList»onclick=»myNode.innerHTML = liElems»>Вернутьсписок<button>

<button class=»btn»onclick=»removeLiElements()»>Удалитьвсеэлементыli<button>

 
<script>

varmyNode=document.getElementById(«forRemove»),

liElems=myNode.innerHTML;

functionremoveLiElements(){

while(myNode.firstChild){

myNode.removeChild(myNode.firstChild);

}

}

</script>

Особые ссылки для таблиц

У конкретных элементов DOM могут быть свои дополнительные ссылки для большего удобства навигации.

Здесь мы рассмотрим таблицу, так как это важный частный случай и просто для примера.

В списке ниже выделены наиболее полезные:

  • – ссылки на элементы таблицы , , .
  • – коллекция элементов таблицы , по спецификации их может быть несколько.
  • – номер строки в текущей секции
  • – номер строки в таблице

Пример использования:

Спецификация: HTML5: tabular data.

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

Конечно же, таблицы – не исключение.

Аналогичные полезные свойства есть у HTML-форм, они позволяют из формы получить все её элементы, а из них – в свою очередь, форму. Мы рассмотрим их позже.

Создание и добавление элементов

Чтобы создать новый элемент — используется метод .

var newDiv = document.createElement('div')

Тут же можно и проставить свойства и содержание созданному элементу.

var newDiv = document.createElement('div')
newDiv.className = 'my-class'
newDiv.id = 'my-id'
newDiv.style.backgroundColor = 'red'

newDiv.innerHTML = 'Привет, мир!'

Добавить новый элемент к детям существующего элемента можно методом , который в DOM есть у любого тега.

Код из следующего примера добавляет новые элементы к списку:

<ul id="list">
<li>Первый элемент</li>
</ul>

Список:

Первый элемент

// элемент-список UL
var list = document.getElementById('list')

// новый элемент
var li = document.createElement('LI')
li.innerHTML = 'Новый элемент списка'

// добавление в конец
list.appendChild(li)

Метод всегда добавляет элемент последним в список детей.

Новый элемент можно добавить не в конец детей, а перед нужным элементом.
Для этого используется метод родительского элемента.

Он работает так же, как и , но принимает вторым параметром элемент, перед которым нужно вставлять.

parentElem.insertBefore(newElem, target)

Например, в том же списке добавим элементы перед первым .

<ul id="list2">
<li>Первый элемент</li>
</ul>

Первый элемент

// родительский элемент UL
var list = document.getElementById('list2')
// элемент для вставки перед ним (первый LI)
var firstLi = list.getElementsByTagName('LI')

// новый элемент
var newListElem = document.createElement('LI')
newListElem.innerHTML = 'Новый элемент списка'

// вставка
list.insertBefore(newListElem, firstLi)

Метод позволяет вставлять элемент в любое место, кроме как в конец. А с этим справляется . Так что эти методы дополняют друг друга.

Метода нет, но нужную функцию легко написать на основе комбинации и .

Чтобы убрать узел из документа — достаточно вызвать метод из его родителя.

list.removeChild(elem)

Если родителя нет «на руках», то обычно используют . Получается так:

elem.parentNode.removeChild(elem)

Неуклюже, но работает.

insertAdjacentHTML/Text/Element

С этим может помочь другой, довольно универсальный метод: .

Первый параметр – это специальное слово, указывающее, куда по отношению к производить вставку. Значение должно быть одним из следующих:

  • – вставить непосредственно перед ,
  • – вставить в начало ,
  • – вставить в конец ,
  • – вставить непосредственно после .

Второй параметр – это HTML-строка, которая будет вставлена именно «как HTML».

Например:

…Приведёт к:

Так мы можем добавлять произвольный HTML на страницу.

Варианты вставки:

Мы можем легко заметить сходство между этой и предыдущей картинкой. Точки вставки фактически одинаковые, но этот метод вставляет HTML.

У метода есть два брата:

  • – такой же синтаксис, но строка вставляется «как текст», вместо HTML,
  • – такой же синтаксис, но вставляет элемент .

Они существуют, в основном, чтобы унифицировать синтаксис. На практике часто используется только . Потому что для элементов и текста у нас есть методы – их быстрее написать, и они могут вставлять как узлы, так и текст.

Так что, вот альтернативный вариант показа сообщения:

Проверка правильности внесения данных формы

Не осталось ли поле пустым?

Вводимым пользователями данным доверять нельзя. Предполагать, что пользователи при вводе данных будут их проверять, неразумно. Значит необходимо для этого использовать javascript.

Для того, чтобы проверить, не осталось ли текстовое поле пустым (например, после заполнения пользователем данных какой-либо анкеты), следует обратиться к свойству . Если значением свойства является пустая строка (), значит необходимо как-то оповестить об этом пользователя.

<input type="text" id="name" value="">

Т.е, проверка того, осталось ли поле пустым будет выглядеть так:

if(document.getElementById("name").value=="")
{
    какие-то действия, например, вывод сообщения с требованием заполнить поле
};

Кроме того, можно обойтись и без скрипта. У тега текстового поля есть атрибут . в качестве его значения указывается регулярное выражение для проверки данных в данном текстовом поле формы. Если присутствует атрибут pattern, то форма не будет отправляться, пока это текстовое поле не будет заполнено правильно.Например, для проверки, не осталось ли поле пустым:

<form>
<!--  \w - любой алфавитно-цифровой символ, + должен быть найден хотя бы 1 раз -->
<input type="text" pattern="\w+">
<input type="submit">
<form>

Текст вместо числового значения: функция

Если поле предполагает введение числового значения, а вместо этого пользователь вводит текст, то необходимо использовать функцию (с англ. «является ли не числом?»), которая проверяет тип вводимых данных и возвращает в случае введения текстовых данных вместо числовых.

Т.о. если возвращено , то необходимо оповестить пользователя о том, чтобы он ввел правильный формат, т.е. число.

минут: <input type="text" id="monutes" value="">

Т.е. проверка будет выглядеть следующим образом:

if(isNaN(document.getElementById("minutes").value)){
  оповещение с требованием ввести числовые данные
};

И последнее, если все таки пользователь ввёл в текстовое поле, предназначенное для числа, и число и текст одновременно, то при помощи javascript можно вычленить из текста число:

alert(parseInt(document.getElementById("cake").value)); // 10

Задание Js8_3. Дана страница с элементами для заполнения:Фрагмент кода html:

1
2
3
4
5
6
7
8
9
10
11
12
<form>
Имя: <input type="text" id="name"><br>
Кол-во пончиков: <input type="text" id="donuts"><br>
Минут: <input type="text" id="minutes"><br>
Подытог: <input type="text" id="poditog"><br>
Налог: <input type="text" id="tax"><br>
Итог:<input type="text" id="itog"><br>
<input type="submit" value="заказать" onclick="placeOrder();">
<form>
<script type="text/javascript">
...
<script>

Необходимо:
Дополните пустые места фрагмента кода, расположенного ниже, проверяющего правильность заполнения двух текстовых полей: имя () и минут (). Используйте проверку на оставление поля пустым () и правильного формата заполнения числового поля ().

* Выполнить задание также с помощью атрибута текстовых полей, используя регулярные выражения.
  Фрагмент скрипта:

В коде используются для построения сложных условий, пройденные раннее.

Новым понятием для вас является вызов функции в качестве обработчика события кнопки:
По щелчку на кнопке будет вызываться функция

Пример — показ сообщения

Сделаем что-нибудь посложнее.

В качестве реального примера рассмотрим добавление сообщения на страницу.
Чтобы показывалось посередине экрана и было красивее, чем обычный alert.

Сообщение в HTML-варианте (как обычно, можно посмотреть, нажав кнопку):

<style>
.my-message {
   width:300px;
   height:110px;
   background-color:#F08080;
   text-align: center;
   border: 2px groove black;
}
.my-message-title {
  height:20px;
  font-size:120%;
  background-color:red;
}
.my-message-body {
  padding: 5px;
  height: 50px;
}
</style>

<div class="my-message">
  <div class="my-message-title">Заголовок</div>
  <div class="my-message-body">Текст Сообщения</div>
  <input class="my-message-ok" type="button" value="OK"/>
</div>

Как видно — сообщение вложено в DIV фиксированного размера и состоит из заголовка , тела и кнопки OK, которая нужна, чтобы сообщение закрыть.

Кроме того, добавлено немного простых стилей, чтобы как-то смотрелось.

Показ сообщения состоит из нескольких этапов.

  1. Создание DOM-элементов для показа сообщения
  2. Позиционирование на экране
  3. Запуск функции удаления сообщения по клику на ОК

Для создания сколько-нибудь сложных структур DOM, как правило, используют либо готовые шаблоны и метод , создающий копию узла, либо свойство .

Следующая функция создает сообщение с указанным телом и заголовком.

function createMessage(title, body) {
  // (1)
  var container = document.createElement('div') 
  
  // (2)
  container.innerHTML = '<div class="my-message"> \
    <div class="my-message-title">'+title+'</div> \
    <div class="my-message-body">'+body+'</div> \
    <input class="my-message-ok" type="button" value="OK"/> \
  </div>'

  // (3)
  return container.firstChild
}

Как видно, она поступает довольно хитро. Чтобы создать элемент по текстовому шаблону, она сначала создает временный элемент (1), а потом записывает (2) его как innerHTML временного элемента (1). Теперь готовый элемент можно получить и вернуть (3).

Сообщение будем позиционировать абсолютно, в центре по ширине и на 200 пикселов ниже верхней границы экрана.

function positionMessage(elem) {
  elem.style.position = 'absolute'

  var scroll = document.documentElement.scrollTop || document.body.scrollTop
  elem.style.top = scroll + 200 + 'px'

  elem.style.left = Math.floor(document.body.clientWidth/2) - 150 + 'px'
}

Не вдаваясь в тонкости позиционирования — заметим, что для свойства 200 пикселов прибавляются к текущей вертикальной прокрутке, которую браузер отсчитывает либо от либо от — зависит от DOCTYPE и типа браузера.

При установке от центра экрана вычитается половина ширины DIV’а с сообщением (у него стоит width:300).

Наконец, следующая функция вешает на кнопку OK функцию, удаляющую элемент с сообщением из DOM.

function addCloseOnClick(messageElem) {

  var input = messageElem.getElementsByTagName('INPUT')

  input.onclick = function() {
    messageElem.parentNode.removeChild(messageElem)
  }

}

Обратите внимание, при получении элемента функции не используют DOM-свойства. Этому есть две причины

Первая — надежность. Мы можем изменить шаблон сообщения, вставить дополнительный элемент — и ничего не должно сломаться.
Вторая — это наличие текстовых элементов. Свойства будут перечислять их наравне с остальными элементами, и придется их отфильтровывать

Этому есть две причины. Первая — надежность. Мы можем изменить шаблон сообщения, вставить дополнительный элемент — и ничего не должно сломаться.
Вторая — это наличие текстовых элементов. Свойства будут перечислять их наравне с остальными элементами, и придется их отфильтровывать.

Создадим одну функцию, которая выполняет все необходимые для показа сообщения операции.

function setupMessageButton(title, body) {

  // создать
  var messageElem = createMessage(title, body)

  // позиционировать
  positionMessage(messageElem)

  // добавить обработчик на закрытие
  addCloseOnClick(messageElem)

  // вставить в документ
  document.body.appendChild(messageElem)
}

Протестировать то, что получилось, нам поможет следующая кнопка:

<input 
  type="button" 
  value="Показать" 
  onclick="setupMessageButton('Привет!', 'Ваше сообщение')"
/>

Для этого примера вы можете:

  • Скачать файл со стилями
  • Скачать файл с javascript
  • Посмотреть на отдельной странице все вместе

Как строится DOM-дерево документа

Как уже было описано выше браузер строит дерево на основе HTML-элементов и других сущностей исходного кода страницы. При выполнении этого процесса он учитывает вложенность элементов друг в друга.

В результате браузер полученное DOM-дерево использует не только в своей работе, но также предоставляет нам API для удобной работы с ним через JavaScript.

При строительстве DOM браузер создаёт из HTML-элементов, текста, комментариев и других сущностей этого языка объекты (узлы DOM-дерева).

В большинстве случаев веб-разработчиков интересуют только объекты (узлы), образованные из HTML-элементов.

При этом браузер не просто создаёт объекты из HTML-элементов, а также связывает их между собой определёнными связями в зависимости от того, как каждый из них относится к другому в коде.

Элементы, которые находятся непосредственно в некотором элементе являются по отношению к нему детьми. А он для каждого из них является родителем. Кроме этого, все эти элементы по отношению друг к другу являются сиблингами (братьями).

При этом в HTML любой элемент всегда имеет одного родителя (HTML-элемент, в котором он непосредственно расположен). В HTML у элемента не может быть несколько родителей. Исключение составляет только элемент . У него нет родителя.

Чтобы получить DOM-дерево так как его строит браузер, необходимо просто «выстроить» все элементы в зависимости от их отношения друг к другу.

Создание DOM-дерева выполняется сверху вниз.

При этом корнем DOM-дерева всегда является сам документ (узел ). Далее дерево строится в зависимости от структуры HTML кода.

Например, HTML-код, который мы рассматривали выше будет иметь следующее DOM-дерево:

В самом верху этого дерева находится узел . Данный узел связан с , он является его ребёнком. Узел образован элементом (). Узлы () и body () имеют родительскую связь с . По отношению друг ту другу они являются сиблингами, т.к. имеют одного родителя. Узел связан с (), он является его ребёнком. Узлы и связаны с , для них он является родителем. Узел связан с () и (), они являются его детьми.

Начинается дерево как было уже отмечено выше с объекта (узла) . Он в свою очередь имеет один дочерний узел, образованный элементом (). Элементы () и () находятся в и, следовательно, являются его детьми. Далее узел является родительским для (). Элементы и вложены в , значит они являются его детьми. В непосредственно расположены элементы () и (). Это значит, что узел для каждого из них является родительским.

Вот так просто строится DOM-дерево в браузере на основании HTML-кода.

Зачем нужно знать, как строится DOM дерево? Во-первых, это понимание той среды, в которой вы хотите что-то изменять. Во-вторых, большинство действий при работе с DOM сводится к поиску (выбору) нужных элементов. Не зная как устроено DOM-дерево и связи между узлами найти какой-то определенный элемент в нём будет достаточно затруднительно.

Пример с атрибутами и DOCTYPE

Рассмотрим чуть более сложный документ.


ДокументData

  • Осторожно
  • Информация

Made in Russia ©

Верхний тег — , у него дети и , и так далее. Получается дерево тегов:

Атрибуты

В этом примере у узлов есть атрибуты: , , . Вообще говоря, атрибуты тоже считаются узлами в DOM-модели, родителем которых является элемент DOM, у которого они указаны.

Однако, в веб-программировании в эти дебри обычно не лезут, и считают атрибуты просто свойствами DOM-узла, которые, как мы увидим в дальнейшем, можно устанавливать и менять по желанию программиста.

DOCTYPE

Вообще-то это секрет, но DOCTYPE тоже является DOM-узлом, и находится в дереве DOM слева от HTML (на рисунке этот факт скрыт).

P.S. Насчет секрета — конечно, шутка, но об этом и правда далеко не все знают. Сложно придумать, где такое знание может пригодиться…

Пример с удалением и скрытием/отображением элемента

Допустим вам нужно удалить некий div с анимацией, которая запускается по клику на этом div-е и всего один раз

Для одноразовой обработки собвтия можно использовать событие jQuery или метод — в конце важно указать. Для удаления div-а используем метод , который есть как в нативном JavaScript, так и jQuery, а скрыть/показать элемент можно простым переключением между класса hidden с единственным свойством

Код примера с удалением div-а и изменением его отображения

<style>
#animation {
width: 400px;
margin: 20px auto;
position: relative;
text-align: center;
}
#frame {
width: 50px;
height: 72px;
margin: 15px auto;
border: 1px solid transparent;
background: url(https://s.cdpn.io/79/sprite-steps.png) no-repeat left top;
}
@keyframes frame-animation {
0% { background-position: 0px 0; }
100% { background-position: -500px 0; }
}
.hidden {display: none;}
</style>
<div class=»test»>
<div id=»animation»>
<div id=»frame»></div>
<button class=»button» id=»showHide»>Показать/спрятать</button> &nbsp;
<button class=»button» id=»removeDiv»>Удалить div совсем</button>
</div>
<script>
frame.addEventListener(‘click’, function(){
this.style.animation = ‘frame-animation 1s steps(10) infinite’;
}, {once: true})
showHide.addEventListener(‘click’, function(){
frame.classList.toggle(‘hidden’);
})
removeDiv.addEventListener(‘click’, function(){
frame.remove();
})
</script>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

<style>

#animation {

width400px;

margin20pxauto;

positionrelative;

text-aligncenter;

}

#frame {

width50px;

height72px;

margin15pxauto;

border1pxsolidtransparent;

backgroundurl(https//s.cdpn.io/79/sprite-steps.png)no-repeatlefttop;

}

@keyframes frame-animation {

0% {background-position0px;}

100% {background-position-500px;}

}

.hidden {displaynone;}

</style>

<div class=»test»>

<div id=»animation»>

<div id=»frame»><div>

<button class=»button»id=»showHide»>Показатьспрятать<button>&nbsp;

<button class=»button»id=»removeDiv»>Удалитьdivсовсем<button>

<div>

<script>

frame.addEventListener(‘click’,function(){

this.style.animation=’frame-animation 1s steps(10) infinite’;

},{oncetrue})

showHide.addEventListener(‘click’,function(){

frame.classList.toggle(‘hidden’);

})

removeDiv.addEventListener(‘click’,function(){

frame.remove();

})

</script>

<div>

Протестировать пример можно прямо сейчас. Для запуска анимации щелкните на картинке.

Показать/спрятать   Удалить div совсем

Просмотров:
10 293

События в DOM

Добавляем слушателей событий:

События выполняются в порядке их добавления.

Всплытие события

Это значение, которое принимается по умолчанию в браузерах, передается третьим параметром. При нем событие как бы поднимается вверх, от самого глубокого DOM-узла — к самому верхнему и заканчивается на объекте document, который описывает весь наш HTML документ.

Погружение события

При этом обработчике событий событие погружается от самого верхнего эле- мента к самому глубокому, самому нижнему, на котором оно могло бы про- изойти, и сначала срабатывает на объекте document и постепенно погружается вниз. Для того, чтобы событие перехватывалось, в качестве последнего параметра в addEventListener вам нужно передать true.

Остановка всплытия или погружения

Иногда вы хотите остановить событие на каком-то конкретном участке и не хотите, чтобы оно всплывало или погружалось далее. Для того, чтобы остановить всплытие, существует метод stopPropagation, который вызывается у объекта «событие».

Объект «событие» (event)

Объект событие всегда передается обработчику и содержит массу полезной информации о том где и какое событие произошло.

Способов передачи этого объекта обработчику существует ровно два, и они зависят от способа его установки и от браузера.

В браузерах, работающих по рекомендациям W3C, объект события всегда передается в обработчик первым параметром.

Например:

function doSomething(event) {
	// event - будет содержать объект события
}

element.onclick = doSomething;

При вызове обработчика объект события будет передан ему первым аргументом.

Можно назначить и вот так:

element.onclick = function(event) {
	// event - объект события
}

Интересный побочный эффект — в возможности использования переменной при назначении обработчика в HTML:

<input type="button" onclick="alert(event)" value="Жми сюда не ошибешься"/>

Это работает благодаря тому, что браузер автоматически создает функцию-обработчик с данным телом, в которой первый аргумент .

В Internet Explorer существует глобальный объект , который хранит в себе информацию о последнем событии. А первого аргумента обработчика просто нет.

То есть, все должно работать так:

// обработчик без аргументов
function doSomething() {
	// window.event - объект события
}

element.onclick = doSomething;

Обратите внимание, что доступ к при назначении обработчика в HTML (см. пример выше) по-прежнему будет работать

Такой вот надежный и простой кросс-браузерный доступ к объекту события.

Можно кросс-браузерно получить объект события, использовав такой приём:

function doSomething(event) {
    event = event || window.event

    // Теперь event - объект события во всех браузерах.
}

element.onclick = doSomething

Как мы уже говорили раньше, при описании обработчика события в HTML-разметке для получения события можно использовать переменную с названием .

<input type="button" onclick="alert(event.type)" value="Нажми меня"/>

Этот код в действии:

Это совершенно кросс-браузерный способ, так как по стандарту — название первого аргумента функции-обработчика, которую автоматом создаст браузер; ну а в IE значение будет взято из глобального объекта .

Итого

Только те события пересекают границы теневого DOM, у которых флаг установлен в значение .

У большинства встроенных событий стоит , это описано в соответствующих спецификациях:

  • UI Events https://www.w3.org/TR/uievents.
  • Touch Events https://w3c.github.io/touch-events.
  • Pointer Events https://www.w3.org/TR/pointerevents.
  • …И так далее.

У некоторых встроенных событий всё же стоит :

  • , (вообще не всплывают),
  • , , , ,
  • ,
  • .

Эти события могут быть пойманы только на элементах, принадлежащих тому же DOM-дереву.

Если мы генерируем своё событие , то должны явно поставить флаг .

Обратите внимание, что в случае вложенных компонентов теневые DOM могут быть вложены друг в друга. События с флагом всплывают через границы всех теневых DOM

Поэтому, если событие предназначено только для ближайшего внешнего компонента-родителя, мы можем инициировать его на элементе-хозяине и установить флаг . Тогда оно будет уже вне теневого DOM компонента, но не выплывает наружу в «ещё более внешний» DOM.

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: