renovations

This commit is contained in:
Ilya Kantor 2015-02-07 12:34:26 +03:00
parent 66e2f0919d
commit 25fc5d8650
19 changed files with 268 additions and 88 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Before After
Before After

View file

@ -0,0 +1,41 @@
В стандартном режиме IE8 можно получить текущую прокрутку так:
```js
//+ run
alert( document.documentElement.scrollTop );
```
Самым простым, но неверным было бы такое решение:
```js
//+ run
// "полифилл"
window.pageYOffset = document.documentElement.scrollTop;
// использование "полифилла"
alert( window.pageYOffset );
```
Код выше не учитывает текущую прокрутку. Он присваивает `window.pageYOffset` один раз и в дальнейшем, чтобы получить текущую прокрутку, нужно снова обратиться к `document.documentElement.scrollTop` не меняет его. А задача как раз -- сделать полифилл, то есть дать возможность использовать `window.pageYOffset` для получения текущего состояния прокрутки без "танцев бубном", так же как в современных браузерах.
Для этого создадим свойство через геттер.
В IE8 для DOM-объектов работает `Object.defineProperty`:
```js
//+ run
// полифилл
Object.defineProperty(window, 'pageYOffset', {
get: function() {
return document.documentElement.scrollTop;
}
});
// использование полифилла
alert( window.pageYOffset );
```

View file

@ -0,0 +1,12 @@
# Полифилл для pageYOffset в IE8
[importance 3]
Обычно в IE8 не поддерживается свойство `pageYOffset`. Напишите полифилл для него.
При подключённом полифилле такой код должен работать в IE8:
```js
// текущая прокрутка страницы в IE8
alert( window.pageYOffset );
```

View file

@ -107,9 +107,9 @@ function getOffsetSum(elem) {
var top = 0, left = 0;
while(elem) {
top = top + parseInt(elem.offsetTop);
left = left + parseInt(elem.offsetLeft);
elem = elem.offsetParent;
top = top + parseInt(elem.offsetTop);
left = left + parseInt(elem.offsetLeft);
elem = elem.offsetParent;
}
return {top: top, left: left};

View file

@ -1,35 +1,50 @@
# Итого
В этой главе кратко перечислены основные свойства и методы DOM, которые мы изучили.
В этой главе кратко перечислены основные свойства и методы DOM, которые мы изучили. Их уже довольно много.
Используйте её, чтобы получить быстрый итоговый обзор того, что изучали ранее.
Используйте её, чтобы по-быстрому вспомнить и прокрутить в голове то, что изучали ранее. Все ли эти свойства вам знакомы?
Кое-где стоит ограничение на версии IE, но на все свойства можно найти или сделать или найти полифилл, с которым их можно использовать везде.
[cut]
## Создание
<dl>
<dt>`document.createElement(tag)`</dt><dd>создать элемент с тегом `tag`</dd>
<dt>`document.createTextNode(txt)`</dt><dd>создать текстовый узел с текстом `txt`</dd>
<dt>`node.cloneNode(deep)`</dt><dd>клонировать существующий узел, если `deep=false`, то без потомков.</dd>
<dt>`document.createElement(tag)`</dt><dd>Создать элемент с тегом `tag`</dd>
<dt>`document.createTextNode(txt)`</dt><dd>Создать текстовый узел с текстом `txt`</dd>
<dt>`node.cloneNode(deep)`</dt><dd>Клонировать существующий узел, если `deep=false`, то без потомков.</dd>
</dl>
## Свойства узлов
<dl>
<dt>`node.nodeType`</dt><dd>тип узла: 1(элемент) / 3(текст) / другие.</dd>
<dt>`elem.tagName`</dt><dd>тег элемента.</dd>
<dt>`node.nodeType`</dt><dd>Тип узла: 1(элемент) / 3(текст) / другие.</dd>
<dt>`elem.tagName`</dt><dd>Тег элемента.</dd>
<dt>`elem.innerHTML`</dt><dd>HTML внутри элемента.</dd>
<dt>`node.data`</dt><dd>содержимое любого узла любого типа, кроме элемента.</dd>
<dt>`elem.outerHTML`</dt><dd>Весь HTML элемента, включая сам тег. На запись использовать с осторожностью, так как не модифицирует элемент, а вставляет новый вместо него.</dd>
<dt>`node.data` / `node.nodeValue`</dt><dd>Содержимое узла любого типа, кроме элемента.</dd>
<dt>`node.textContent`</dt><dd>Текстовое содержимое узла, для элементов содержит текст с вырезанными тегами (IE9+).</dd>
<dt>`elem.hidden`</dt><dd>Если поставить `true`, то элемент будет скрыт (IE10+).</dd>
</dl>
## Атрибуты
<dl>
<dt>`elem.getAttribute(name)`, `elem.hasAttribute(name)`, `elem.setAttribute(name, value)`</dt>
<dd>Чтение атрибута, проверка наличия и запись.</dd>
<dt>`elem.dataset.*`</dt><dd>Значения атрибутов вида `data-*` (IE10+).</dd>
</dl>
## Ссылки
<dl>
<dt>`document.documentElement`</dt>
<dd>элемент `<HTML>`</dd>
<dd>Элемент `<HTML>`</dd>
<dt>`document.body`</dt>
<dd>элемент `<BODY>`</dd>
<dd>Элемент `<BODY>`</dd>
<dt>`document.head`</dt>
<dd>Элемент `<HEAD>` (IE9+)</dd>
</dl>
По всем узлам:
@ -42,14 +57,15 @@
Только по элементам:
<ul>
<li>`children`</li>
<li>`parentElement`</li>
<li>`nextElementSibling` `previousElementSibling`</li>
<li>`firstElementChild` `lastElementChild`</li>
<li>`children`, `firstElementChild` `lastElementChild`</li>
</ul>
В IE8- из них работает только `children`, причём содержит не только элементы, но и комментарии (ошибка в браузере).
Все они IE9+, кроме `children`, который работает в IE8-, но содержит не только элементы, но и комментарии (ошибка в браузере).
### Таблицы
Дополнительно у некоторых типов элементов могут быть и другие ссылки, свойства, коллекции для навигации,
например для таблиц:
<dl>
<dt>`table.rows[N]`</dt>
@ -62,17 +78,6 @@
<dd>номер ячейки в строке.</dd>
</dl>
### Формы
<dl>
<dt>`document.forms[N/name]`</dt>
<dd>форма по номеру/имени.</dd>
<dt>`form.elements[N/name]`</dt>
<dd>элемент формы по номеру/имени</dd>
<dt>`element.form`</dt>
<dd>форма для элемента.</dd>
</dl>
## Поиск
@ -84,16 +89,28 @@
<dt>`document.getElementById(id)`</dt>
<dd>По уникальному `id`</dd>
<dt>`document.getElementsByName(name)`</dt>
<dd>По атрибуту `name`, в IE<10 работает только для элементов, где `name` предусмотрен стандартом.</dd>
<dd>По атрибуту `name`, в IE9- работает только для элементов, где `name` предусмотрен стандартом.</dd>
<dt>`*.getElementsByTagName(tag)`</dt>
<dd>По тегу `tag`</dd>
<dt>`*.getElementsByClassName(class)`</dt>
<dd>По классу, IE9+, корректно работает с элементами, у которых несколько классов.</dd>
</dl>
При поддержки IE только версии 8 и выше, можно использовать только `querySelector/querySelectorAll`.
Если не нужно поддерживать IE7-, то можно использовать только `querySelector/querySelectorAll`. Методы `getElement*` работают быстрее (за счёт более оптимальной внутренней реализации), но в 99% случаев это различие очень небольшое и роли не играет.
Дополнительно есть методы:
<dl>
<dt>`elem.matches(css)`</dt>
<dd>Проверяет, подходит ли элемент под CSS-селектор.</dd.
<dt>`elem.closest(css)`</dt>
<dd>Ищет ближайший элемент сверху по иерархии DOM, подходящий под CSS-селектор. Первым проверяется сам `elem`. Этот элемент возвращается.</dd>
<dt>`elemA.contains(elemB)`</dt>
<dd>Возвращает `true`, если `elemA` является предком (содержит) `elemB`.</dd>
<dt>`elemA.compareDocumentPosition(elemB)`</dt>
<dd>Возвращает битовую маску, которая включает в себя отношение вложенности между `elemA` и `elemB`, а также -- какой из элементов появляется в DOM первым.</dd>
</dl>
Для более старых IE нужен либо фреймворк, который сам умеет искать узлы по селектору, наподобие jQuery, либо пользоваться методами `get*`, все из которых, кроме `...ByClassName`, поддерживаются с древних времён.
## Изменение
@ -102,6 +119,19 @@
<li>`parent.removeChild(child)`</li>
<li>`parent.insertBefore(newChild, refNode)`</li>
<li>`parent.insertAdjacentHTML("beforeBegin|afterBegin|beforeEnd|afterEnd", html)`</li>
<li>`parent.insertAdjacentElement("beforeBegin|...|afterEnd", text)` (кроме FF)</li>
<li>`parent.insertAdjacentText("beforeBegin|...|afterEnd", text)` (кроме FF)</li>
<li>`document.write(...)`</li>
</ul>
Скорее всего, понадобятся полифиллы для:
<ul>
<li>`node.append(...nodes)`</li>
<li>`node.prepend(...nodes)`</li>
<li>`node.after(...nodes)`,</li>
<li>`node.before(...nodes)`</li>
<li>`node.replaceWith(...nodes)`</li>
</ul>
## Классы и стили
@ -110,7 +140,7 @@
<dt>`elem.className`</dt>
<dd>Атрибут `class`</dt>
<dt>`elem.classList.add(class) remove(class) toggle(class) contains(class)`</dt>
<dd>Управление классами в HTML5, для IE8+ есть [эмуляция](https://github.com/eligrey/classList.js/blob/master/classList.js).</dd>
<dd>Управление классами, для IE9- есть [эмуляция](https://github.com/eligrey/classList.js/blob/master/classList.js).</dd>
<dt>`elem.style`</dt>
<dd>Стили в атрибуте `style` элемента</dd>
<dt>`getComputedStyle(elem, "")`</dd>

View file

@ -23,7 +23,7 @@ DOM позволяет делать что угодно с HTML-элементо
<dd>Вторая точка входа -- `document.body`, который соответствует тегу `<body>`.</dd>
</dl>
В современных браузерах (кроме старых IE) также действует `document.head` -- прямой доступ к `<head>`
В современных браузерах (кроме IE8-) также есть `document.head` -- прямая ссылка на `<head>`
[warn header="Есть одна тонкость: `document.body` может быть равен `null`"]
Нельзя получить доступ к элементу, которого еще не существует в момент выполнения скрипта.

View file

@ -6,9 +6,11 @@
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="dom-links-elements.svg" sketch:type="MSArtboardGroup">
<rect id="Rectangle-8" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="131" y="5" width="194" height="24"></rect>
<text id="document.documentEle" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" sketch:alignment="middle" fill="#8A704D">
<tspan x="137.692383" y="22">document.documentElement &lt;HTML&gt;</tspan>
</text>
<rect id="Rectangle-7" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="165" y="73" width="113" height="24"></rect>
<text id="document.body-(если-" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" sketch:alignment="middle" fill="#8A704D">
<tspan x="172.84375" y="90">document.body (если внутри body)</tspan>
</text>
@ -21,8 +23,6 @@
<tspan x="221.183594" y="165" fill="#EE6B47">Element</tspan>
</text>
<rect id="Rectangle-6" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="183" y="208" width="75" height="24"></rect>
<rect id="Rectangle-7" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="165" y="73" width="113" height="24"></rect>
<rect id="Rectangle-8" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="131" y="5" width="194" height="24"></rect>
<text id="&lt;DIV&gt;" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
<tspan x="201.051859" y="225">&lt;DIV&gt;</tspan>
</text>

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Before After
Before After

View file

@ -6,6 +6,9 @@
<defs></defs>
<g id="combined" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="dom-links.svg" sketch:type="MSArtboardGroup">
<rect id="Rectangle-9" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="153" y="2" width="113" height="24"></rect>
<rect id="Rectangle-7" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="153" y="136" width="113" height="24"></rect>
<rect id="Rectangle-8" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="119" y="68" width="194" height="24"></rect>
<text id="document" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="bold" sketch:alignment="middle" fill="#8A704D">
<tspan x="177.710938" y="18">document</tspan>
</text>
@ -25,9 +28,6 @@
<tspan x="172" y="228">parentNode</tspan>
</text>
<rect id="Rectangle-6" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="171" y="271" width="75" height="24"></rect>
<rect id="Rectangle-7" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="153" y="136" width="113" height="24"></rect>
<rect id="Rectangle-9" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="153" y="2" width="113" height="24"></rect>
<rect id="Rectangle-8" stroke="#E8C48E" stroke-width="4" fill="#FFF9EB" sketch:type="MSShapeGroup" x="119" y="68" width="194" height="24"></rect>
<text id="&lt;DIV&gt;" sketch:type="MSTextLayer" font-family="Open Sans" font-size="14" font-weight="526" sketch:alignment="middle" fill="#8A704D">
<tspan x="189.051859" y="288">&lt;DIV&gt;</tspan>
</text>

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Before After
Before After

View file

@ -260,12 +260,13 @@ alert( articles.length ); // 2, найдёт оба элемента
## closest
Метод `elem.closest(css)` ищет ближайшего предка, подходящего под CSS-селектор `css`.
Метод `elem.closest(css)` ищет ближайший элемент выше по иерархии DOM, подходящий под CSS-селектор `css`. Сам элемент тоже включается в поиск.
Иначе говоря, метод `closest` бежит от текущего элемента вверх по цепочке родителей и проверяет, подходит ли каждый элемент под CSS-селектор. Если подходит -- останавливается и возвращает его.
Он самый новый из методов, рассмотренных в этой главе, поэтому не все браузеры его поддерживают. Это, конечно, легко поправимо, как мы увидим позже в главе [](/dom-polyfill).
Пример использования:
Пример использования (браузер должен поддерживать `closest`):
```html
<!--+ run -->
@ -282,10 +283,15 @@ alert( articles.length ); // 2, найдёт оба элемента
<script>
var numberSpan = document.querySelector('.num');
// браузер должен поддерживать этот метод
// ближайший элемент сверху подходящий под селектор li
alert( numberSpan.closest('li').className ) // subchapter
// ближайший элемент сверху подходящий под селектор .chapter
alert( numberSpan.closest('.chapter').tagName ) // LI
// ближайший элемент сверху, подходящий под селектор span
// это сам numberSpan, так как поиск включает в себя сам элемент
alert( numberSpan.closest('span') === numberSpan ) // true
</script>
```

View file

@ -407,7 +407,7 @@ chatDiv.innerHTML += "Как дела?";
**Иными словами, `elem.textContent` возвращает конкатенацию всех текстовых узлов внутри `elem`.**
Не сказать, чтобы эта информация была часто востребована.
Не сказать, чтобы эта информация была часто востребована.
**Гораздо полезнее возможность записать текст в элемент, причём именно как текст!**

View file

@ -372,7 +372,7 @@ div.classList.add('order-state-canceled');
Проще говоря, значение атрибута -- произвольная строка, значение класса -- это "есть" или "нет", поэтому естественно, что атрибуты "мощнее" и бывают удобнее классов как в JS так и в CSS.
## Свойство dataSet, data-атрибуты
## Свойство dataset, data-атрибуты
С помощью нестандартных атрибутов можно привязать к элементу данные, которые будут доступны в JavaScript.