minor renovations, beautify round 2 (final)

This commit is contained in:
Ilya Kantor 2015-03-12 10:26:02 +03:00
parent fad6615c42
commit 8410ce6421
212 changed files with 1981 additions and 1717 deletions

View file

@ -2,6 +2,6 @@
```html
<!--+ run height=50 -->
<input type="button" onclick="this.style.display='none'" value="Нажми, чтобы меня спрятать"/>
<input type="button" onclick="this.style.display='none'" value="Нажми, чтобы меня спрятать" />
```

View file

@ -5,8 +5,8 @@
Для того, чтобы удалить функцию-обработчик, нужно где-то сохранить ссылку на неё, например так:
```js
function handler() {
alert("1");
function handler() {
alert( "1" );
}
button.addEventListener("click", handler);

View file

@ -9,6 +9,7 @@
Что будет выведено при клике после выполнения кода?
```js
//+ no-beautify
button.addEventListener("click", function() { alert("1"); });
button.removeEventListener("click", function() { alert("1"); });

View file

@ -1,4 +1,3 @@
# Структура HTML/CSS
Для начала, зададим структуру HTML/CSS.
@ -33,41 +32,36 @@
<span style="border: solid red 1px">[Сладости (нажми меня)!]</span>
```
Раскрытие/закрытие делайте путём добавления/удаления класса `.menu-open` к меню, которые отвечает за стрелочку и отображение `UL`.
Раскрытие/закрытие сделаем путём добавления/удаления класса `.menu-open` к меню, которые отвечает за стрелочку и отображение `UL`.
# CSS
CSS для меню:
Обычно меню будет закрыто:
```css
.menu ul {
margin: 0;
list-style: none;
padding-left: 20px;
display: none;
}
.menu .title {
padding-left: 16px;
font-size: 18px;
cursor: pointer;
background: url(...arrow-right.png) left center no-repeat;
.menu .title::before {
content: '▶ ';
font-size: 80%;
color: green;
}
```
Если же меню раскрыто, то есть имеет класс `.menu-open`, то стрелочка слева заголовка меняется и список детей показывается:
```css
.menu-open .title {
background: url(...arrow-down.png) left center no-repeat;
.menu.open .title::before {
content: '▼ ';
}
.menu-open ul {
.menu.open ul {
display: block;
}
```
Теперь сделайте JavaScript.
Для JavaScript остался минимум работы -- только добавить/удалить класс при клике.

View file

@ -26,7 +26,7 @@ p {
position: absolute;
font-size: 110%;
top: 0;
color: red;
color: darkred;
right: 10px;
display: block;
width: 24px;

View file

@ -22,7 +22,7 @@ p {
.remove-button {
font-size: 110%;
color: red;
color: darkred;
right: 10px;
width: 24px;
height: 24px;

View file

@ -106,12 +106,12 @@
Пример установки обработчика `click`:
```html
<input id="elem" type="button" value="Нажми меня"/>
<input id="elem" type="button" value="Нажми меня" />
<script>
*!*
elem.onclick = function() {
alert('Спасибо');
};
elem.onclick = function() {
alert( 'Спасибо' );
};
*/!*
</script>
```
@ -137,12 +137,12 @@ elem.onclick = function() {
```html
<!--+ run height=50 -->
<input type="button" id="button" value="Кнопка"/>
<input type="button" id="button" value="Кнопка" />
<script>
*!*
button.onclick = function() {
alert('Клик!');
};
button.onclick = function() {
alert( 'Клик!' );
};
*/!*
</script>
```
@ -156,12 +156,12 @@ button.onclick = function() {
```html
<!--+ run height=50 autorun -->
<input type="button" id="elem" onclick="alert('До')" value="Нажми меня"/>
<input type="button" id="elem" onclick="alert('До')" value="Нажми меня" />
<script>
*!*
elem.onclick = function() { // перезапишет существующий обработчик
alert('После'); // выведется только это
};
elem.onclick = function() { // перезапишет существующий обработчик
alert( 'После' ); // выведется только это
};
*/!*
</script>
```
@ -170,7 +170,7 @@ elem.onclick = function() { // перезапишет существующий
```js
function sayThanks() {
alert('Спасибо!');
alert( 'Спасибо!' );
}
elem.onclick = sayThanks;
@ -211,7 +211,7 @@ button.onclick = sayThanks;
...А вот в разметке как раз скобки нужны:
```html
<input type="button" id="button" onclick="sayThanks()"/>
<input type="button" id="button" onclick="sayThanks()" />
```
Это различие просто объяснить. При создании обработчика браузером из атрибута, он автоматически создает функцию из его содержимого. Поэтому последний пример -- фактически то же самое, что:
@ -219,7 +219,7 @@ button.onclick = sayThanks;
```js
button.onclick = function() {
*!*
sayThanks(); // содержимое атрибута
sayThanks(); // содержимое атрибута
*/!*
};
```
@ -234,7 +234,7 @@ button.onclick = function() {
Такой вызов работать не будет:
```js
//+ run
//+ run no-beautify
// при нажатии на body будут ошибки
// потому что при назначении в атрибут функция будет преобразована в строку
document.body.setAttribute('onclick', function() { alert(1) });
@ -255,6 +255,7 @@ document.body.setAttribute('onclick', function() { alert(1) });
При этом новый обработчик будет затирать предыдущий. Например, следующий код на самом деле назначает один обработчик -- последний:
```js
//+ no-beautify
input.onclick = function() { alert(1); }
// ...
input.onclick = function() { alert(2); } // заменит предыдущий обработчик
@ -269,7 +270,7 @@ input.onclick = function() { alert(2); } // заменит предыдущий
Назначение обработчика осуществляется вызовом `addEventListener` с тремя аргументами:
```js
element.addEventListener( event, handler[, phase]);
element.addEventListener(event, handler[, phase]);
```
<dl>
@ -285,7 +286,7 @@ element.addEventListener( event, handler[, phase]);
```js
// передать те же аргументы, что были у addEventListener
element.removeEventListener( event, handler[, phase]);
element.removeEventListener(event, handler[, phase]);
```
[warn header="Удаление требует именно ту же функцию"]
@ -294,6 +295,7 @@ element.removeEventListener( event, handler[, phase]);
Вот так `removeEventListener` не сработает:
```js
//+ no-beautify
elem.addEventListener( "click" , function() {alert('Спасибо!')});
// ....
elem.removeEventListener( "click", function() {alert('Спасибо!')});
@ -305,12 +307,12 @@ elem.removeEventListener( "click", function() {alert('Спасибо!')});
```js
function handler() {
alert('Спасибо!');
alert( 'Спасибо!' );
}
input.addEventListener( "click", handler);
input.addEventListener("click", handler);
// ....
input.removeEventListener( "click", handler);
input.removeEventListener("click", handler);
```
Обратим внимание -- если функцию не сохранить где-либо, а просто передать в `addEventListener`, как в предыдущем коде, то потом получить её обратно, чтобы снять обработчик, будет невозможно. Нет метода, который позволяет считать обработчики событий, назанченные через `addEventListener`.
@ -319,7 +321,7 @@ input.removeEventListener( "click", handler);
Метод `addEventListener` позволяет добавлять несколько обработчиков на одно событие одного элемента, например:
```html
<!--+ run -->
<!--+ run no-beautify -->
<input id="elem" type="button" value="Нажми меня"/>
<script>
@ -357,6 +359,7 @@ input.removeEventListener( "click", handler);
transition: width 1s;
width: 100px;
}
.wide {
width: 300px;
}
@ -367,14 +370,14 @@ input.removeEventListener( "click", handler);
</button>
<script>
elem.ontransitionend = function() {
alert("ontransitionend"); // не сработает
elem.ontransitionend = function() {
alert( "ontransitionend" ); // не сработает
};
*!*
elem.addEventListener("transitionend", function() {
alert("addEventListener"); // сработает по окончании анимации
}, false);
alert( "addEventListener" ); // сработает по окончании анимации
});
*/!*
</script>
```
@ -390,24 +393,24 @@ input.removeEventListener( "click", handler);
Назначение обработчика осуществляется вызовом `attachEvent`:
```js
element.attachEvent( "on"+event, handler);
element.attachEvent("on" + event, handler);
```
Удаление обработчика -- вызовом `detachEvent`:
```js
element.detachEvent( "on"+event, handler);
element.detachEvent("on" + event, handler);
```
Например:
```js
function handler() {
alert('Спасибо!');
alert( 'Спасибо!' );
}
button.attachEvent( "onclick" , handler) // Назначение обработчика
// ....
button.detachEvent( "onclick", handler) // Удаление обработчика
button.attachEvent("onclick", handler) // Назначение обработчика
// ....
button.detachEvent("onclick", handler) // Удаление обработчика
```
Как видите, почти то же самое, только событие должно включать префикс `on`.

View file

@ -50,7 +50,7 @@
В действии:
```html
<!--+ autorun -->
<!--+ autorun no-beautify -->
<textarea rows="6" cols="40" id="area">Кликни меня
</textarea>
@ -103,7 +103,7 @@
При этом обработчик `onclick` вызовет метод `focus()` на текстовом поле `text`. Код обработчика `onfocus`, который при этом запустится, сработает синхронно, прямо сейчас, до завершения `onclick`.
```html
<!--+ autorun -->
<!--+ autorun no-beautify -->
<input type="button" id="button" value="Нажми меня">
<input type="text" id="text" size="60">
@ -147,7 +147,6 @@
<input type="text" id="text" size="60">
<script>
button.onclick = function() {
text.value += ' ->в onclick ';
@ -156,10 +155,10 @@
text.focus(); // сработает после onclick
}, 0);
*/!*
text.value += ' из onclick-> ';
};
text.onfocus = function() {
text.value += ' !focus! ';
};

View file

@ -76,7 +76,7 @@ element.onclick = function(event) {
```js
element.onclick = function(e) {
e = e || event;
e = e || event;
// Теперь e - объект события во всех браузерах.
};
@ -93,9 +93,9 @@ element.onclick = function(e) {
```js
element.onclick = function(event) {
event = event || window.event;
event = event || window.event;
// Теперь event - объект события во всех браузерах.
// Теперь event - объект события во всех браузерах.
};
```
@ -103,8 +103,8 @@ element.onclick = function(event) {
```js
element.onclick = function(e) {
e = e || event; // если нет другой внешней переменной event
...
e = e || event; // если нет другой внешней переменной event
...
};
```

View file

@ -24,13 +24,16 @@
```html
<!--+ run autorun -->
<style>
body * { margin: 10px; border: 1px solid blue; }
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
```
@ -166,7 +169,7 @@ JS-код здесь такой:
var elems = document.querySelectorAll('form,div,p');
// на каждый элемент повесить обработчик на стадии перехвата
for(var i=0; i<elems.length; i++) {
for (var i = 0; i < elems.length; i++) {
elems[i].addEventListener("click", highlightThis, true);
}
```
@ -176,7 +179,7 @@ for(var i=0; i<elems.length; i++) {
```js
var elems = document.querySelectorAll('form,div,p');
for(var i=0; i<elems.length; i++) {
for (var i = 0; i < elems.length; i++) {
elems[i].addEventListener("click", highlightThis, true);
elems[i].addEventListener("click", highlightThis, false);
}
@ -218,6 +221,7 @@ elem.onclick = function(event) {
<dd>Кросс-браузерно остановить всплытие можно так:
```js
//+ no-beautify
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);
```

View file

@ -26,7 +26,7 @@ p {
position: absolute;
font-size: 110%;
top: 0;
color: red;
color: darkred;
right: 10px;
display: block;
width: 24px;

View file

@ -22,7 +22,7 @@ p {
.remove-button {
font-size: 110%;
color: red;
color: darkred;
right: 10px;
width: 24px;
height: 24px;

View file

@ -11,18 +11,20 @@
```html
<!--+ autorun height=190 untrusted -->
<style>
li { border: 1px solid green; }
li {
border: 1px solid green;
}
</style>
<ul onclick="alert(event.target)">
<li>Млекопетающие
<ul>
<li>Коровы</li>
<li>Ослы</li>
<li>Собаки</li>
<li>Тигры</li>
</ul>
</li>
<li>Млекопетающие
<ul>
<li>Коровы</li>
<li>Ослы</li>
<li>Собаки</li>
<li>Тигры</li>
</ul>
</li>
</ul>
```
@ -41,9 +43,9 @@ var treeUl = document.getElementsByTagName('ul')[0];
var treeLis = treeUl.getElementsByTagName('li');
for(var i=0; i<treeLis.length; i++) {
for (var i = 0; i < treeLis.length; i++) {
var li = treeLis[i];
var span = document.createElement('span');
li.insertBefore(span, li.firstChild); // добавить пустой SPAN
span.appendChild(span.nextSibling); // переместить в него заголовок
@ -57,18 +59,20 @@ for(var i=0; i<treeLis.length; i++) {
```html
<!--+ autorun height=190 untrusted -->
<style>
span { border: 1px solid red; }
span {
border: 1px solid red;
}
</style>
<ul onclick="alert(event.target.tagName)">
<li><span>Млекопетающие</span>
<ul>
<li><span>Коровы</span></li>
<li><span>Ослы</span></li>
<li><span>Собаки</span></li>
<li><span>Тигры</span></li>
</ul>
</li>
<li><span>Млекопетающие</span>
<ul>
<li><span>Коровы</span></li>
<li><span>Ослы</span></li>
<li><span>Собаки</span></li>
<li><span>Тигры</span></li>
</ul>
</li>
</ul>
```
@ -88,10 +92,10 @@ var tree = document.getElementsByTagName('ul')[0];
tree.onclick = function(event) {
var target = event.target;
if (target.tagName != 'SPAN') {
if (target.tagName != 'SPAN') {
return; // клик был не на заголовке
}
var li = target.parentNode; // получить родительский LI
// получить UL с потомками -- это первый UL внутри LI

View file

@ -19,9 +19,9 @@
<th colspan="3"><em>Bagua</em> Chart: Direction, Element, Color, Meaning</th>
</tr>
<tr>
<td>...<strong>Northwest</strong>...</td>
<td>...</td>
<td>...</td>
<td>...<strong>Northwest</strong>...</td>
<td>...</td>
<td>...</td>
</tr>
<tr>...еще 2 строки такого же вида...</tr>
<tr>...еще 2 строки такого же вида...</tr>
@ -44,7 +44,7 @@ var selectedTd;
*!*
table.onclick = function(event) {
var target = event.target; // где был клик?
if (target.tagName != 'TD') return; // не на TD? тогда не интересует
highlight(target); // подсветить TD
@ -94,13 +94,13 @@ function highlight(node) {
```js
table.onclick = function(event) {
var target = event.target;
// цикл двигается вверх от target к родителям до table
while(target != table) {
while (target != table) {
if (target.tagName == 'TD') {
// нашли элемент, который нас интересует!
highlight(target);
return;
// нашли элемент, который нас интересует!
highlight(target);
return;
}
target = target.parentNode;
}
@ -115,7 +115,7 @@ table.onclick = function(event) {
Кстати, в проверке `while` можно бы было использовать `this` вместо `table`:
```js
while(target != this) {
while (target != this) {
// ...
}
```
@ -128,13 +128,13 @@ while(target != this) {
```js
table.onclick = function(event) {
var target = event.target;
var td = event.target.closest('td');
if (!td) return; // клик вне <td>, не интересует
// если клик на td, но вне этой таблицы (возможно при вложенных таблицах)
// то не интересует
if (!table.contains(td)) return;
if (!table.contains(td)) return;
// нашли элемент, который нас интересует!
highlight(td);
@ -172,25 +172,31 @@ table.onclick = function(event) {
</div>
<script>
function Menu(elem) {
this.save = function() { alert('сохраняю'); };
this.load = function() { alert('загружаю'); };
this.search = function() { alert('ищу'); };
function Menu(elem) {
this.save = function() {
alert( 'сохраняю' );
};
this.load = function() {
alert( 'загружаю' );
};
this.search = function() {
alert( 'ищу' );
};
var self = this;
var self = this;
elem.onclick = function(e) {
var target = e.target;
elem.onclick = function(e) {
var target = e.target;
*!*
var action = target.getAttribute('data-action');
if (action) {
self[action]();
}
var action = target.getAttribute('data-action');
if (action) {
self[action]();
}
*/!*
};
}
};
}
new Menu(menu);
new Menu(menu);
</script>
```

View file

@ -4,7 +4,7 @@
```js
function(event) {
handler() // тело взято из атрибута onclick
handler() // тело взято из атрибута onclick
}
```

View file

@ -8,7 +8,7 @@
<!--+ autorun run -->
<script>
function handler() {
alert("...");
alert( "..." );
return false;
}
</script>

View file

@ -8,12 +8,12 @@
contents.onclick = function(evt) {
var target = evt.target;
function handleLink(href) {
var isLeaving = confirm('Уйти на '+href+'?');
function handleLink(href) {
var isLeaving = confirm('Уйти на ' + href + '?');
if (!isLeaving) return false;
}
while(target != this) {
while (target != this) {
if (target.nodeName == 'A') {
*!*
return handleLink(target.getAttribute('href')); // (*)

View file

@ -10,7 +10,7 @@ var largeImg = document.getElementById('largeImg');
document.getElementById('thumbs').onclick = function(e) {
var target = e.target;
while(target != this) {
while (target != this) {
if (target.nodeName == 'A') {
showThumbnail(target.href, target.title);
@ -34,11 +34,11 @@ function showThumbnail(href, title) {
```js
var imgs = thumbs.getElementsByTagName('img');
for(var i=0; i<imgs.length; i++) {
for (var i = 0; i < imgs.length; i++) {
var url = imgs[i].parentNode.href;
*!*
var img = document.createElement('img');
var img = document.createElement('img');
img.src = url;
*/!*
}

View file

@ -24,7 +24,7 @@
В следующем примере при клике по ссылке переход не произойдет:
```html
<!--+ autorun height=60 -->
<!--+ autorun height=60 no-beautify -->
<a href="/" onclick="return false">Нажми здесь</a>
или
<a href="/" onclick="event.preventDefault()">здесь</a>
@ -68,7 +68,7 @@ menu.onclick = function(event) {
if (event.target.nodeName != 'A') return;
var href = event.target.getAttribute('href');
alert(href); // может быть подгрузка с сервера, генерация интерфейса и т.п.
alert( href ); // может быть подгрузка с сервера, генерация интерфейса и т.п.
*!*
return false; // отменить переход по url
@ -127,7 +127,7 @@ menu.onclick = function(event) {
element.onclick = function(event) {
event = event || window.event;
if (event.preventDefault) { // если метод существует
if (event.preventDefault) { // если метод существует
event.preventDefault(); // то вызвать его
} else { // иначе вариант IE8-:
event.returnValue = false;
@ -138,6 +138,7 @@ element.onclick = function(event) {
Можно записать в одну строку:
```js
//+ no-beautify
...
event.preventDefault ? event.preventDefault() : (event.returnValue=false);
...

View file

@ -37,7 +37,7 @@ var event = new Event(тип события[, флаги]);
При просмотре примера ниже кнопка обработчик `onclick` на кнопке сработает сам по себе, событие генерируется скриптом:
```html
<!--+ run -->
<!--+ run no-beautify -->
<button id="elem" onclick="alert('Клик');">Автоклик</button>
<script>
@ -74,15 +74,17 @@ var event = new Event(тип события[, флаги]);
setTimeout(hide, 2000);
function hide() {
var event = new Event("hide", {cancelable: true});
var event = new Event("hide", {
cancelable: true
});
if (!rabbit.dispatchEvent(event)) {
alert('действие отменено');
alert( 'действие отменено' );
} else {
rabbit.hidden = true;
}
}
rabbit.addEventListener('hide', function(event) {
rabbit.addEventListener('hide', function(event) {
if (confirm("Вызвать preventDefault?")) {
event.preventDefault();
}
@ -112,6 +114,7 @@ var event = new Event(тип события[, флаги]);
Другие свойства события, если они нужны, например координаты для события мыши -- можно присвоить в объект события позже, например:
```js
//+ no-beautify
var event = new Event("click", {bubbles: true, cancelable: false});
event.clientX = 100;
event.clientY = 100;
@ -124,7 +127,7 @@ event.clientY = 100;
Всё, что для этого нужно -- это флаг `bubbles`:
```html
<!--+ run -->
<!--+ run no-beautify -->
<h1 id="elem">Привет от скрипта!</h1>
<script>
@ -179,7 +182,7 @@ var e = new MouseEvent("click", {
});
*!*
alert(e.clientX); // 100
alert( e.clientX ); // 100
*/!*
```
@ -195,7 +198,7 @@ var e = new Event("click", {
});
*!*
alert(e.clientX); // undefined, свойство не присвоено!
alert( e.clientX ); // undefined, свойство не присвоено!
*/!*
```
@ -275,7 +278,10 @@ event.initEvent(type, boolean bubbles, boolean cancelable);
```js
// современный стандарт
var event = new Event("click", { bubbles: true, cancelable: true });
var event = new Event("click", {
bubbles: true,
cancelable: true
});
// старый стандарт
var event = document.createEvent("Event");
@ -291,9 +297,9 @@ event.initEvent("click", true, true);
<h1 id="elem">Привет от скрипта!</h1>
<script>
document.addEventListener("hello", function(event) {
alert("Привет");
event.preventDefault();
document.addEventListener("hello", function(event) {
alert( "Привет" );
event.preventDefault();
}, false);
*!*
@ -302,9 +308,8 @@ event.initEvent("click", true, true);
*/!*
if (elem.dispatchEvent(event) === false) {
alert('Событие было отменено preventDefault');
alert( 'Событие было отменено preventDefault' );
}
</script>
```
@ -318,22 +323,22 @@ event.initEvent("click", true, true);
Выглядят они немного страшновато, например (взято из [спецификации](http://www.w3.org/TR/DOM-Level-3-Events/#idl-interface-MouseEvent-initializers)):
```js
void initMouseEvent (
DOMString typeArg, // тип
boolean bubblesArg, // всплывает?
boolean cancelableArg, // можно отменить?
AbstractView? viewArg, // объект window, null означает текущее окно
long detailArg, // свойство detail и другие...
long screenXArg,
long screenYArg,
long clientXArg,
long clientYArg,
boolean ctrlKeyArg,
boolean altKeyArg,
boolean shiftKeyArg,
boolean metaKeyArg,
unsigned short buttonArg,
EventTarget? relatedTargetArg);
void initMouseEvent(
DOMString typeArg, // тип
boolean bubblesArg, // всплывает?
boolean cancelableArg, // можно отменить?
AbstractView ? viewArg, // объект window, null означает текущее окно
long detailArg, // свойство detail и другие...
long screenXArg,
long screenYArg,
long clientXArg,
long clientYArg,
boolean ctrlKeyArg,
boolean altKeyArg,
boolean shiftKeyArg,
boolean metaKeyArg,
unsigned short buttonArg,
EventTarget ? relatedTargetArg);
};
```
@ -345,7 +350,7 @@ void initMouseEvent (
<script>
elem.onclick = function(e) {
alert('Клик на координатах ' + e.clientX + ':' + e.clientY);
alert( 'Клик на координатах ' + e.clientX + ':' + e.clientY );
};
var event = document.createEvent("MouseEvent");
@ -371,9 +376,9 @@ try {
window.CustomEvent = function(event, params) {
var evt;
params = params || {
bubbles: false,
bubbles: false,
cancelable: false,
detail: undefined
detail: undefined
};
evt = document.createEvent("CustomEvent");
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
@ -399,15 +404,15 @@ try {
<script>
document.body.onclick = function() {
alert("Клик, event.type=" + event.type);
alert( "Клик, event.type=" + event.type );
return false;
};
*!*
var event = document.createEventObject();
if( !elem.fireEvent("onclick", event) ) {
alert('Событие было отменено');
}
if (!elem.fireEvent("onclick", event)) {
alert( 'Событие было отменено' );
}
*/!*
</script>
```