renovations

This commit is contained in:
Ilya Kantor 2015-04-01 19:08:41 +03:00
parent 0e9ceb2b3a
commit 150d92f10f
47 changed files with 290 additions and 110 deletions

View file

@ -135,7 +135,7 @@ function getOffsetSum(elem) {
[pre]
<div style="position:relative;padding:10px;height:80px;width:380px;border:7px red solid">
<div style="border:10px blue solid;padding:2px;position:absolute;left:20%;top:20%">
<div id="getBoundingClientRectEx" style="background-color:yellow;border:4px solid black;margin:2px;cursor:pointer">Кликните, чтобы получить координаты getOffsetSum и getCoords</div>
<div id="getBoundingClientRectEx" style="background-color:yellow;font-size:14px;border:4px solid black;margin:2px;cursor:pointer">Кликните, чтобы получить координаты getOffsetSum и getCoords</div>
</div>
</div>
<div id="getBoundingClientRectExRes">

View file

@ -36,4 +36,3 @@
<li>Напишите код, который получит второй `LI`. Будет ли ваш код работать в IE8-, если комментарий переместить *между* элементами `LI`?</li>
</ul>
[edit src="solution" task/]

View file

@ -0,0 +1,72 @@
Объектом какого класса является `document`, можно выяснить так:
```js
//+ run
alert(document); // [object HTMLDocument]
```
Или так:
```js
//+ run
alert(document.constructor); // function HTMLDocument() { ... }
```
Итак, `document` -- объект класса `HTMLDocument`.
Какое место `HTMLDocument` занимает в иерархии?
Можно поискать в документации. Но попробуем выяснить это самостоятельно.
Вопрос не такой простой и требует хорошего понимания [прототипного наследования](/class-inheritance).
Вспомним, как оно устроено:
<ul>
<li>Методы объекта `document` находятся в `prototype` конструктора, в данном случае -- `HTMLDocument.prototype`.</li>
<li>У `HTMLDocument.prototype` есть ссылка `__proto__` на прототип-родитель.</li>
<li>У прототипа-родителя может быть ссылка `__proto__` на его родитель, и так далее.</li>
</ul>
При поиске свойства в `document`, если его там нет, оно ищется в `document.__proto__`, затем в `document.__proto__.__proto__` и так далее, пока не найдём, или пока цепочка `__proto__` не закончится. Это обычное устройство класса, без наследования.
Нам нужно лишь узнать, что находится в этих самых `__proto__`.
Строго говоря, там могут быть любые объекты. Вовсе не обязательно, чтобы объектам из цепочки прототипов соответствовали какие-то конструкторы.
Вполне может быть цепочка, где родители -- просто обычные JS-объекты:
```js
document -> HTMLDocument.prototype -> obj1 -> obj2 -> ...
```
Однако, здесь мы знаем, что наследование -- "на классах", то есть, эти объекты `obj1`, `obj2` являются `prototype` неких функций-конструкторов:
```js
document -> HTMLDocument.prototype -> F1.prototype -> F2.prototype -> ...
```
Что стоит на месте `F1`, `F2`?
Опять же, если говорить про некие абстрактные объекты, то откуда нам знать, какие функции на них ссылаются через `prototype`? Ниоткуда. Один объект может быть в `prototype` хоть у десятка функций.
Но в стандартном прототипном наследовании один объект является `prototype` ровно у одной функции. Причём при создании функции в её `prototype` уже есть объект со свойством `constructor`, которое ссылается обратно на функцию:
```js
F.prototype = { constructor: F }
```
Это свойство `constructor`, если конечно его не удалить или не перезаписать нечаянно (чего делать не следует), и позволяет из прототипа узнать соответствующий ему конструктор.
```js
//+ run
// цепочка наследования:
alert(HTMLDocument.prototype.constructor); // function HTMLDocument
alert(HTMLDocument.prototype.__proto__.constructor); // function Document
alert(HTMLDocument.prototype.__proto__.__proto__.constructor); // function Node
```
При выводе объекта через `console.dir(document)` в Google Chrome, мы тоже можем, раскрывая `__proto__`, увидеть эти названия (`HTMLDocument`, `Document`, `Node`).
Браузерная консоль их берёт как раз из свойства `constructor`.

View file

@ -0,0 +1,11 @@
# Где в DOM-иерархии document?
[importance 4]
Объектом какого класса является `document`?
Какое место он занимает в DOM-иерархии?
Наследует ли он `Node` или `Element`?
Воспользуйтесь для решения тем фактом, что DOM-узлы образуют стандартную прототипную иерархию классов.

View file

@ -38,35 +38,57 @@
alert( document.body ); // [object HTMLBodyElement]
```
Детальное описание свойств и методов каждого DOM-класса дано в [спецификации](http://www.whatwg.org/specs/web-apps/current-work/multipage/).
Например, [The input element](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#the-input-element) описывает класс, соответствующий `<input>`, включая [interface HTMLInputElement](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#htmlinputelement), который нас как раз и интересует.
Вот из него выдержка:
Можно и проверить при помощи `instanceof`:
```js
interface HTMLInputElement: HTMLElement {
//+ run
alert( document.body instanceof HTMLBodyElement ); // true
alert( document.body instanceof HTMLElement ); // true
alert( document.body instanceof Element ); // true
alert( document.body instanceof Node ); // true
```
Как видно, DOM-узлы -- обычные JavaScript-объекты. Их классы заданы в прототипном стиле. В этом легко убедиться, если вывести в консоли любой элемент через `console.dir(elem)`. Или даже можно напрямую обратиться к методам, которые хранятся в `Node.prototype`, `Element.prototype` и так далее.
[smart header="`console.dir(elem)` против `console.log(elem)`"]
Вывод `console.log(elem)` и `console.dir(elem)` различен.
<ul>
<li>`console.log` выводит элемент в виде, удобном для исследования HTML-структуры.</li>
<li>`console.dir` выводит элемент в виде JavaScript-объекта, удобно для анализа его свойств.</li>
</ul>
Попробуйте сами на `document.body`.
[/smart]
Детальное описание свойств и методов каждого DOM-класса дано в [спецификации](https://html.spec.whatwg.org/multipage/).
Например, [The input element](https://html.spec.whatwg.org/multipage/forms.html#the-input-element) описывает класс, соответствующий `<input>`, включая [interface HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement), который нас как раз и интересует.
При описании свойств и методов используется не JavaScript, а специальный язык [IDL](https://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%BE%D0%B2) (Interface Definition Language), который достаточно легко понять "с ходу".
Вот из него выдержка, с комментариями:
```js
// Объявлен HTMLInputElement
// двоеточие означает, что он наследует от HTMLElement
interface HTMLInputElement: HTMLElement {
// у всех таких элементов есть строковые свойства
// accept, alt, autocomplete, value
attribute DOMString accept;
attribute DOMString alt;
attribute DOMString autocomplete;
attribute DOMString value;
// и логическое свойство autofocus
attribute boolean autofocus;
...
attribute DOMString value;
...
// а также метод select, который значение не возвращает (void)
void select();
...
}
```
При описании свойств и методов используется не JavaScript, а специальный язык [IDL](https://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%BE%D0%B2) (Interface Definition Language), который достаточно легко понять "с ходу".
В частности, выше мы видим, что:
<ul>
<li>`HTMLInputElement` наследует от `HTMLEmenet`.</li>
<li>У всех `<input>`-элементов есть свойства `accept`, `alt`, `autocomplete` и `value`, которые являются строками (`DOMString`), а также также свойство `autofocus` с логическим значением.</li>
<li>Также есть метод `select()`, который значение не возвращает (`void`).</li>
</ul>
Далее в этом разделе мы поговорим о самых главных свойствах узлов DOM, которые используются наиболее часто.
## Тип: nodeType
@ -83,7 +105,7 @@ interface HTMLInputElement: HTMLElement {
```js
interface Node {
// NodeType
// Всевозможные значения nodeType
const unsigned short ELEMENT_NODE = 1;
const unsigned short ATTRIBUTE_NODE = 2;
const unsigned short TEXT_NODE = 3;
@ -277,7 +299,7 @@ chatDiv.innerHTML += "Как дела?";
В примере закрывающий тег `</scr'+'ipt>` разбит на две строки, т.к. иначе браузер подумает, что это конец скрипта. Вставленный скрипт не выполнится.
Исключение -- IE9-, в нем вставляемый скрипт выполняются, если у него есть атрибут `defer`. Но это нестандартная возможность, которой не следует пользоваться.
Исключение -- IE9-, в нем вставляемый скрипт выполняются, если у него есть атрибут `defer`. Но это нестандартная возможность, которой не следует пользоваться.
[/warn]
@ -447,9 +469,9 @@ chatDiv.innerHTML += "Как дела?";
Как правило, видим или невидим узел, определяется через CSS, свойствами `display` или `visibility`.
В стандарте HTML5 предусмотрен специальный атрибут (он же свойство) для этого: `hidden`.
В стандарте HTML5 предусмотрен специальный атрибут и свойство для этого: `hidden`.
Его поддерживают все современные браузеры, кроме старых IE.
Его поддерживают все современные браузеры, кроме IE10-.
В примере ниже второй и третий `<div>` скрыты:

View file

@ -1,6 +1,6 @@
# Порядок обработки событий
События могут возникать не только по очереди, но и "пачкой" по много сразу. Возможно и такое, что во время обработки одного события возникают другие, например пока выполнялся код для `onclick` -- посетитель провёл мышкой, а это уже `mousemove`.
События могут возникать не только по очереди, но и "пачкой" по много сразу. Возможно и такое, что во время обработки одного события возникают другие, например пока выполнялся код для `onclick` -- посетитель нажал кнопку на клавиатуре (событие `keydown`).
Здесь мы разберём, как браузер обычно работает с одновременно возникающими событиями и какие есть исключения из общего правила.
@ -50,8 +50,8 @@
В действии:
```html
<!--+ autorun no-beautify -->
<textarea rows="6" cols="40" id="area">Кликни меня
<!--+ autorun height=150 no-beautify -->
<textarea rows="8" cols="40" id="area">Кликни меня
</textarea>
<script>
@ -79,7 +79,7 @@
Когда посетитель фокусируется на элементе, возникает событие `onfocus`. Обычно оно происходит, когда посетитель кликает на поле ввода, например:
```html
<!--+ run autorun -->
<!--+ run height=80 autorun -->
<p>При фокусе на поле оно изменит значение.</p>
<input type="text" onfocus="this.value = 'Фокус!'" value="Кликни меня">
```
@ -103,7 +103,7 @@
При этом обработчик `onclick` вызовет метод `focus()` на текстовом поле `text`. Код обработчика `onfocus`, который при этом запустится, сработает синхронно, прямо сейчас, до завершения `onclick`.
```html
<!--+ autorun no-beautify -->
<!--+ autorun height=80 no-beautify -->
<input type="button" id="button" value="Нажми меня">
<input type="text" id="text" size="60">
@ -142,7 +142,7 @@
Если это неудобно, можно запланировать `text.focus()` чуть позже через `setTimeout(..., 0)`, вот так
```html
<!--+ autorun -->
<!--+ autorun height=80 -->
<input type="button" id="button" value="Нажми меня">
<input type="text" id="text" size="60">

View file

@ -65,12 +65,14 @@ ball.onmousedown = function(e) { // 1. отследить нажатие*!*
}
```
Если запустить этот код на картинке `#ball`, то мы заметим нечто странное. При начале переноса мяч "раздваивается" и переносится не сам мяч, а его "клон".
Если запустить этот код, то мы заметим нечто странное. При начале переноса мяч "раздваивается" и переносится не сам мяч, а его "клон".
[online]
В действии (внутри ифрейма):
Это можно увидеть в действии внутри ифрейма:
[iframe src="ball" height=230]
Попробуйте перенести мяч мышкой и вы увидите описанное, довольно-таки странное, поведение.
[/online]
Это потому, что браузер имеет свой собственный Drag'n'Drop, который автоматически запускается и вступает в конфликт с нашим. Это происходит именно для картинок и некоторых других элементов.