1.10M
Category: programmingprogramming

Веб-разработка. DOM

1.

Веб-разработка
Лекция №5. DOM.
Шумилов Вадим Валерьевич
Тензор, 2016

2.

DOM
2

3.

DOM
DOM – Document Object Model
API для работы со страницей из JavaScript.
• Читать информацию
• Создавать новые элементы
• Манипулировать существующими
• Изменять свойства
• Перемещать
3

4.

DOM
DOM – Document Object Model
Все элементы страницы (тэги, текст, комментарии) являются
элементами DOM.
Часто его называют DOM-дерево.
4

5.

Навигация
5

6.

Навигация
Каждый DOM-элемент имеет следующие навигационные
свойства:
parentNode – родитель
previousSubling – предыдущий сосед
nextSibling – следующий сосед
firstChild, lastChild – первый и последний дочерний элементы
childNodes – коллекция дочерних элементов
6

7.

Навигация
Важные особенности:
1. Коллекция здесь – не настоящий массив.
2. Если какой-то элемент не определен, значение
навигационного свойства будет null.
7

8.

Навигация
<html>
<body>
<h1>Привет</h1>
<p>Текст...</p>
<p>Еще абзац</p>
</body>
</html>
8

9.

Навигация
<html>
<body>
var body = document.body;
<h1>Привет</h1>
<p>Текст...</p>
<p>Еще абзац</p>
</body>
</html>
9

10.

Навигация
<html>
<body>
<h1>Привет</h1>
<p>Текст...</p>
<p>Еще абзац</p>
</body>
</html>
var body = document.body;
body.firstChild
10

11.

Навигация
<html>
<body>[
]<h1>Привет</h1>
<p>Текст...</p>
<p>Еще абзац</p>
</body>
</html>
var body = document.body;
body.firstChild
11

12.

Навигация
<html>
<body>[
]<h1>Привет</h1>
<p>Текст...</p>
<p>Еще абзац</p>[
]</body>
</html>
var body = document.body;
body.firstChild
body.lastChild
12

13.

Навигация
<html>
<body>[
]<h1>Привет</h1>
<p>Текст...</p>
<p>Еще абзац</p>
</body>
</html>
var body = document.body;
var first = body.firstChild;
first.nextSibling;
13

14.

Навигация
<html>
<body>[
]<h1>Привет</h1>
<p>Текст...</p>
<p>Еще абзац</p>
</body>
</html>
var body = document.body;
var first = body.firstChild;
first.nextSibling.nextSibling;
14

15.

Навигация
<html>
<body>[
]<h1>Привет</h1>
<p>Текст...</p>
<p>Еще абзац</p>
</body>
</html>
var body = document.body;
var first = body.firstChild;
first.nextSibling.firstChild
15

16.

Навигация
<html>
<body>[
]<h1>Привет</h1>
<p>Текст...</p>
<p>Еще абзац</p>
</body>
</html>
var body = document.body;
var first = body.firstChild;
first.nextSibling.firstChild;
first.nextSibling.firstChild.parentNode
16

17.

Навигация
Существуют дополнительные навигационные свойства,
не учитывающие текстовые ноды.
parentElementNode
firstElementChild, lastElementChild
previousElementSibling, lastElementSibling
children
17

18.

Навигация
Как работать с коллекциями (childNodes, children)?
Два способа обращения к элементу:
elt.childNodes[i];
elt.childNodes.item(i);
Перебор – по индексу от 0 до elt.childNodes.length
18

19.

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

20.

Поиск элементов
Несколько основных способов найти элемент(ы)
• getElementById()
• getElementsBy*()
• querySelector()/querySelectorAll()
20

21.

Поиск элементов
document.getElementById(‘elt-id’);
1. Вызов – с объекта document
2. Возвращает один элемент с указанным id или null
21

22.

Поиск элементов
anyElement.getElementsBy*(‘query’);
1. Вызов – с любого элемента. Это ограничивает область
поиска
2. Варианты:
• ByName
• ByClassName
• ByTagName
3. Возвращает «живую коллекцию» (возможно, пустую)
22

23.

Поиск элементов
anyElement.querySelector(‘#css .selector’);
1. Вызов – с любого элемента. Это ограничивает область
поиска
2. Возвращает один первый элемент, подходящий под
указанный селектор или null, если не найден
3. Бросает исключение, если селектор некорректный
23

24.

Поиск элементов
anyElement.querySelectorAll(‘#css .selector’);
1. Вызов – с любого элемента. Это ограничивает область
поиска
2. Возвращает коллекцию элементов (возможно, пустую),
подходящих под указанный селектор
3. Бросает исключение, если селектор некорректный
24

25.

Поиск элементов
Разница между getElementsBy* и querySelectorAll
Оба метода возвращают коллекцию, но их действие не
равнозначно.
getElementsBy* возвращают «живую» коллекцию
25

26.

Поиск элементов
<body>
<p>Первый</p>
<p>Второй</p>
</body>
liveCol = document.getElementsByTagName(‘p’);
col = document.querySelectorAll(‘p’);
26

27.

Поиск элементов
liveCol = document.getElementsByTagName(‘p’);
col = document.querySelectorAll(‘p’);
liveCol.length; // 2
col.length; // 2
27

28.

Поиск элементов
liveCol = document.getElementsByTagName(‘p’);
col = document.querySelectorAll(‘p’);
document.body.innerHTML = ‘’; // удалит все из body
liveCol.length; // ??
col.length; // ??
28

29.

Поиск элементов
liveCol = document.getElementsByTagName(‘p’);
col = document.querySelectorAll(‘p’);
document.body.innerHTML = ‘’; // удалит все из body
liveCol.length; // 0
col.length; // 2
29

30.

Атрибуты
30

31.

Атрибуты
Для работы с атрибутами у каждого элемента есть
следующие методы:
getAttribute(‘name’);
setAttribute(‘name’, ‘value’);
hasAttribute(‘name’);
removeAttribute(‘name’);
31

32.

Атрибуты
Особенности:
• Значения атрибутов – строки. Все что не строки –
конвертируется в строку
• Имена атрибутов - регистронезависимы
• Изменение атрибутов приводит к изменению DOM и
HTML
32

33.

Атрибуты
Атрибуты и свойства
• Элементы это объекты.
• Как и у любого объекта, у элементов есть свойства
• Некоторые свойства синхронизируются с атрибутами
• Некоторые – в обе стороны, некоторые – только в одну
33

34.

Атрибуты
<div id=“some”></div>
var elt = document.getElementById(‘some’);
elt.id; // ‘some’
elt.getAttribute(‘id’); // ‘some’
34

35.

Атрибуты
<div id=“some”></div>
var elt = document.getElementById(‘some’);
elt.id = “foo”;
elt.getAttribute(‘id’); // ‘foo’
elt.outerHTML; // ‘<div id=“foo”></div>’
35

36.

Атрибуты
Не все атрибуты и свойства синхронизируются
<input type=“text” value=“foo” />
var elt = document.getElementsByTagName(‘input’)[0];
elt.value; // ‘foo’
elt.getAttribute(‘value’); // ‘foo’
36

37.

Атрибуты
Не все атрибуты и свойства синхронизируются
<input type=“text” value=“foo” />
var elt = document.getElementsByTagName(‘input’)[0];
elt.value = ‘bar’;
elt.getAttribute(‘value’); // ‘foo’
elt.innerHTML; // ‘<input type=“text” value=“foo” />’
Но на экране в поле ввода будет “bar”...
37

38.

Модификация дерева
38

39.

Модификация дерева
Можно создавать ноды дерева
var div = document.createElement(‘div’);
var text = document.createTextNode(‘Это текстовая нода’);
39

40.

Модификация дерева
Можно добавлять ноды в другие ноды
div.appendChild(text);
document.body.appendChild(div);
40

41.

Модификация дерева
Можно читать что получилось в виде строки:
document.body.innerHTML;
<div>Это текстовая нода</div>
41

42.

Модификация дерева
Можно читать что получилось в виде строки:
document.body.outerHTML;
<body><div>Это текстовая нода</div></body>
42

43.

Модификация дерева
Создавать содержимое документа можно с помощью
innerHTML.
document.body.innerHTML = “<p>Параграф текста</p>”;
«Перезапись» innerHTML приводит к удалению всего
содержимого, которое ранее было внутри.
43

44.

Модификация дерева
Можно управлять местом вставки
parent.insertBefore(elem, nextSibling);
parent.replaceChild(newElem, elem);
44

45.

Модификация дерева
insertBefore
<body>
<div id=“ref”></div>
</body>
45

46.

Модификация дерева
insertBefore
<body>
<div id=“ref”></div>
</body>
var ref = document.getElementById(‘ref’);
var newDiv = document.createElement(‘div’);
document.body.insertBefore(newDiv, ref);
46

47.

Модификация дерева
insertBefore
var ref = document.getElementById(‘ref’);
var newDiv = document.createElement(‘div’);
document.body.insertBefore(newDiv, ref);
<body>
<div></div>
<div id=“ref”></div>
</body>
47

48.

Модификация дерева
Если указать последний параметр null – вставка будет
эквивалентна appendChild.
insertBefore(newChild, null) == appendChild(newChild)
48

49.

Модификация дерева
replaceChild
<body>
<div id=“ref”></div>
</body>
var ref = document.getElementById(‘ref’);
var newDiv = document.createElement(‘div’);
document.body.replaceChild(newDiv, ref);
49

50.

Модификация дерева
replaceChild
var ref = document.getElementById(‘ref’);
var newP = document.createElement(‘p’);
document.body.replaceChild(newDiv, ref);
<body>
<p></p>
</body>
50

51.

Модификация дерева
Элементы можно удалять методом removeChild
<body>
<div id=“ref”></div>
</body>
var ref = document.getElementById(‘ref’);
document.body.removeChild(ref);
51

52.

Модификация дерева
Элементы можно удалять методом removeChild
var ref = document.getElementById(‘ref’);
document.body.removeChild(ref);
<body>
</body>
52

53.

Модификация дерева
Элементы можно клонировать методом cloneNode
<body>
<p>Абзац</p>
</body>
var p = document.body.firstElementChild;
var pClone = p.cloneNode();
document.body.appendChild(pClone);
53

54.

Модификация дерева
Элементы можно клонировать методом cloneNode
var p = document.body.firstElementChild;
var pClone = p.cloneNode();
document.body.appendChild(pClone);
<body>
<p>Абзац</p>
???
</body>
54

55.

Модификация дерева
Элементы можно клонировать методом cloneNode
var p = document.body.firstElementChild;
var pClone = p.cloneNode();
document.body.appendChild(pClone);
<body>
<p>Абзац</p>
<p></p>
</body>
55

56.

Модификация дерева
Элементы можно клонировать методом cloneNode
var p = document.body.firstElementChild;
var pClone = p.cloneNode(true);
document.body.appendChild(pClone);
<body>
<p>Абзац</p>
<p>Абзац</p>
</body>
56

57.

События
57

58.

События
DOM Events. События. Какие они бывают?
58

59.

События
DOM Events. События. Какие они бывают?
Click
Mousedown, Mousemove
Focus
Keydown, Keyup
Sumbit
59

60.

События
Как добавить обработчик события.
<p onclick=“alert(‘Нажали на текст’)”>...</p>
p.onclick=function() {
alert(‘Нажали на текст’);
};
60

61.

События
Как добавить обработчик события.
function handleClick() { ... };
<p onclick=“handleClick()”>...</p>
p.onclick=handleClick;
61

62.

События
<p onclick=“handleClick()”>...</p>
p.onclick=handleClick;
p.setAttribute(‘onclick’, handleClick);
62

63.

События
<p onclick=“handleClick()”>...</p>
p.onclick=handleClick;
p.setAttribute(‘onclick’, handleClick);
63

64.

События
p.onclick = f1;
p.onclick = f2;
64

65.

События
p.onclick = f1;
p.onclick = f2;
Проблема. Второй обработчик «затрет» первый!
65

66.

События
addEventListener!
p.addEventListener(‘click’, f1);
p.addEventListener(‘click’, f2);
66

67.

События
Обратите внимание!
p.onclick = ...
p.addEventListener(‘click’, ...);
При навешивании через атрибут нужно добавить on!
67

68.

События
elt.addEventListener vs elt.on*
1. Позволяет добавить несколько обработчиков
2. Есть события, которые нельзя добавить через
свойство/разметку. Можно только через addEventListener
68

69.

События
Как удалить обработчик?
elt.onclick = null;
elt.removeEventListener(‘click’, f);
69

70.

События
elt.addEventListener(‘click’, function() { doSmth(); });
elt.removeEventListener(‘click’, function() { doSmth();});
70

71.

События
elt.addEventListener(‘click’, function() { doSmth(); });
elt.removeEventListener(‘click’, function() { doSmth();});
71

72.

События
Важно! Требуется указывать всегда одну и ту же функцию!
function handler() {
doSmth();
}
elt.addEventListener(‘click’, handler);
elt.removeEventListener(‘click’, handler);
72

73.

Объект события
73

74.

Объект события
p.onclick = function(event) {
// event???
}
74

75.

Объект события
Объект-дескриптор события. Содержит свойства и методы,
позволяющие получить дополнительную информацию о
событии, управлять им и т.п.
75

76.

Объект события
event.type – тип события (click, mousedown, keyup, etc.)
event.target – объект, на котором случилось событие
Есть разные специфические свойства
event.clientX, event.clientY – координаты курсора в момент клика
76

77.

Объект события
Как получить доступ к событию, если обработчик навешивается
через атрибут?
77

78.

Объект события
Как получить доступ к событию, если обработчик навешивается
через атрибут?
<div onclick=“alert(event.clientX)”>...</div>
78

79.

Объект события
Как получить доступ к событию, если обработчик навешивается
через атрибут?
<div onclick=“alert(event.clientX)”>...</div>
Это эквивалентно ...
div.onclick = function(event) {
alert(event.clientX);
}
79

80.

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

81.

Всплытие
<div onclick=“alert(‘Click!’)”>
<p>Первый
<span>параграф</span>
</p>
</div>
81

82.

Всплытие
<div onclick=“alert(‘Click!’)”>
<p>Первый
<span>параграф</span>
</p>
</div>
82

83.

Всплытие
<div onclick=“alert(‘Click!’)”>
<p>Первый
<span>параграф</span>
</p>
</div>
83

84.

Всплытие
<div onclick=“alert(‘Click!’)”>
<p>Первый
<span>параграф</span>
</p>
</div>
84

85.

Всплытие
event.target – элемент, на котором изначально случилось событие
event.currentTarget – элемент, на котором событие было поймано
85

86.

Всплытие
Всплытие можно заблокировать
<div onclick=“alert(‘Click!’)”>
<p onclick=“event.stopPropagation()”>
<span>....</span>
</p>
</div>
86

87.

Всплытие
Всплытие можно заблокировать
<div onclick=“alert(‘Click!’)”>
<p onclick=“event.stopPropagation()”>
<span>....</span>
</p>
</div>
В этом примере мы не увидим alert();
87

88.

Всплытие
Что если обработчиков несколько?
<div onclick=“alert(‘Click!’)”>
<p><span>....</span></p>
</div>
var p = document.getElementsByTagName(‘p’)[0];
p.addEventListener(‘click’, stopsPropagation);
p.addEventListener(‘click’, showsAlert);
88

89.

Всплытие
function stopsPropagation(event) {
event.stopPropagation();
}
function showAlert(event) {
alert(event.target.tagName); // SPAN
}
89

90.

Всплытие
<div onclick=“alert(‘Click!’)”>
<p>
<span>....</span>
</p>
</div>
90

91.

Всплытие
<div onclick=“alert(‘Click!’)”>
<p>
<span>....</span>
</p>
</div>
91

92.

Всплытие
<div onclick=“alert(‘Click!’)”>
<p>
<span>....</span>
</p>
</div>
92

93.

Всплытие
function stopsPropagation(event) {
event.stopImmediatePropagation();
}
function showAlert(event) {
alert(event.target.tagName); // SPAN
}
93

94.

Всплытие
<div onclick=“alert(‘Click!’)”>
<p>
<span>....</span>
</p>
</div>
94

95.

Всплытие
<div onclick=“alert(‘Click!’)”>
<p>
<span>....</span>
</p>
</div>
95

96.

Всплытие
Не все события всплывают!
Пример такого события – focus.
96

97.

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

98.

Всплытие
Фазой, на которой будет обрабатываться событие, управляет
третий, необязательный аргумент addEventListener
elt.addEventListener(‘click’, handler, true);
Для того, чтобы поймать событие на стадии «погружения», нужно
передать его == true
98

99.

Всплытие
Кстати, событие focus...
Оно не всплывает, но погружается.
99

100.

Всплытие
Кстати, событие focus...
Оно не всплывает, но погружается.
100

101.

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

102.

Делегирование
Задача: хотим при нажатии на каждый абзац в документе считать
сколько в нем слов.
102

103.

Делегирование
Решение 1 (плохое)
var pCol = document.getElementsByTagName(‘p’);
for(var i = 0, l = pCol.length; i < l; i++) {
pCol.addEventListener(‘click’, countWords);
}
103

104.

Делегирование
Чем плохо это решение?
104

105.

Делегирование
Чем плохо это решение?
1. Если элементов будет много их перебор может занять время
2. Навешивается обработчиков по количеству параграфов
3. Если в документ добавятся новые параграфы для них код
работать не будет, ведь они появились позже!
105

106.

Делегирование
Решение 2 (почти правильное). Делегирование!
document.body.addEventListener(‘click’, function(event) {
if (event.target.nodeName == ‘P’) {
countWords(event.target);
}
});
106

107.

Делегирование
Решение 2 (почти правильное). Делегирование!
1. Если элементов будет много их перебор может занять время
2. Навешивается обработчиков по количеству параграфов
3. Если в документ добавятся новые параграфы для них код
работать не будет, ведь они появились позже!
107

108.

Делегирование
Решение 2 (почти правильное). Делегирование!
1. Если элементов будет много их перебор может занять время
2. Навешивается обработчиков по количеству параграфов
3. Если в документ добавятся новые параграфы для них код
работать не будет, ведь они появились позже!
108

109.

Делегирование
Решение 2 (почти правильное). Делегирование!
1. Если элементов будет много их перебор может занять время
2. Навешивается обработчиков по количеству параграфов
3. Если в документ добавятся новые параграфы для них код
работать не будет, ведь они появились позже!
109

110.

Делегирование
Решение 2 (почти правильное). Делегирование!
110

111.

Делегирование
Решение 2 (почти правильное). Делегирование!
<p>
Текст, часть которого
<strong>выделена жирным</strong>
</p>
111

112.

Делегирование
Решение 3 (правильное)
function (event) {
var target = event.target;
while (target) {
if (target.nodeName == ‘P’) break;
target = target.parentNode
}
if (target) countWords(target);
}
112

113.

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

114.

Действие по умолчанию
У многих событий есть действия по умолчанию:
• Click по ссылке – переход
• Mousedown на поле ввода – фокусировка
• Keydown – при нажатии клавиши в поле ввода там
появляется символ
114

115.

Действие по умолчанию
Действие по умолчанию можно отменить
elt.addEventListener(‘click’, function(event) {
event.preventDefault();
});
115

116.

Действие по умолчанию
Действие по умолчанию можно отменить
Если событие навешено через атрибут, можно короче
elt.onclick = function() {
return false;
};
ВНИМАНИЕ! Это не работает, если обработчик навешен через
addEventListener!
116

117.

Действие по умолчанию
Для чего это может применяться?
• Для отмены перехода по ссылке и выполнения вместо этого
какого-либо другого действия.
• Для отмены ввода в <input ...>, например, с целью коррекции
ввода
117

118.

Полезные ссылки
118

119.

Учебник
• http://javascript.ru/
• http://learn.javascript.ru/
• http://learn.javascript.ru/document
• http://learn.javascript.ru/events-and-interfaces
119

120.

Вопросы есть?
120

121.

Спасибо за внимание!
English     Русский Rules