minor renovations, beautify round 2 (final)
This commit is contained in:
parent
fad6615c42
commit
8410ce6421
212 changed files with 1981 additions and 1717 deletions
|
|
@ -95,7 +95,7 @@ var border_left_width;
|
|||
|
||||
Есть причина и поважнее. Поскольку именно это имя переменной пришло в голову -- скорее всего, оно больше соответствует хранимым там данным, чем то, которое было мы придумали изначально. Исключения бывают, но в любом случае -- такое несовпадение -- это повод задуматься.
|
||||
|
||||
Чтобы удобно переименовывать переменную, нужно использовать [хороший редактор JavaScript](/editors), тогда этот процесс будет очень простым и быстрым.
|
||||
Чтобы удобно переименовывать переменную, нужно использовать [хороший редактор JavaScript](/editor), тогда этот процесс будет очень простым и быстрым.
|
||||
|
||||
[smart header="Если коротко..."]
|
||||
Смысл имени переменной -- это "имя на коробке", по которому мы сможем максимально быстро находить нужные нам данные.
|
||||
|
|
|
|||
BIN
1-js/4-data-structures/7-array/9-eratosthenes-sieve/sieve.gif
Normal file
BIN
1-js/4-data-structures/7-array/9-eratosthenes-sieve/sieve.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -15,7 +15,7 @@
|
|||
<li>Все оставшиеся незачеркнутыми числа -- простые.</li>
|
||||
</ol>
|
||||
|
||||
Посмотрите также <a href="/files/tutorial/intro/array/sieve.gif">анимацию алгоритма</a>.
|
||||
Посмотрите также [анимацию алгоритма](sieve.gif).
|
||||
|
||||
Реализуйте "Решето Эратосфена" в JavaScript, используя массив.
|
||||
|
||||
|
|
|
|||
|
|
@ -22,4 +22,4 @@ coffeeMachine.setOnReady(function() {
|
|||
});
|
||||
```
|
||||
|
||||
Исходный код возьмите из решения [предыдущей задачи](/task/setter-onReady).
|
||||
Исходный код возьмите из решения [предыдущей задачи](/task/setter-onready).
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
У такого выделения есть два эффекта:
|
||||
<ol>
|
||||
<li>Он позволяет выделить часть совпадения в отдельный элемент массива при поиске через [:String#match] или [:RegExp#exec].</li>
|
||||
<li>Он позволяет выделить часть совпадения в отдельный элемент массива при поиске через [String#match](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/match) или [RegExp#exec](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec).</li>
|
||||
<li>Если поставить квантификатор после скобки, то он применится *ко всей скобке*, а не всего лишь к одному символу.</li>
|
||||
</ol>
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ alert( 'Gogogo now!'.match( /(go)+/i ); // "Gogogo"
|
|||
|
||||
Для удобства заключим его в скобки: <code class="pattern"><(.*?)></code>. Тогда содержимое скобок можно будет получить отдельно.
|
||||
|
||||
Используем метод [:String#match]. В результирующем массиве будет сначала всё совпадение, а далее -- скобочные группы, в данном случае -- только одна:
|
||||
Используем метод [String#match](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/match). В результирующем массиве будет сначала всё совпадение, а далее -- скобочные группы, в данном случае -- только одна:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
|
@ -35,7 +35,7 @@ var reg = /<(.*?)>/
|
|||
alert(str.match(reg)) // массив: <h1>, h1
|
||||
```
|
||||
|
||||
Для поиска всех совпадений, как мы обсуждали ранее, используется метод [:RegExp#exec].
|
||||
Для поиска всех совпадений, как мы обсуждали ранее, используется метод [RegExp#exec](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec).
|
||||
|
||||
**Скобки могут быть и вложенными. В этом случае нумерация также идёт слева направо.**
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# Регулярные выражения [в работе]
|
||||
|
||||
Регулярные выражения -- мощный способ поиска и замены для строк.
|
||||
|
||||
В JavaScript они поддерживаются в простом варианте, менее мощном, чем в большинстве других языков. Но зато нам будет проще их изучить.
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@
|
|||
alert( document.cookie );
|
||||
```
|
||||
|
||||
Эта строка состоит из пар `ключ=значение`, которые перечисляются через точку с запятой с пробелом `; `.
|
||||
Эта строка состоит из пар `ключ=значение`, которые перечисляются через точку с запятой с пробелом `"; "`.
|
||||
|
||||
Значит, чтобы прочитать cookie, достаточно разбить строку по `; `, и затем найти нужный ключ. Это можно делать либо через `split` и работу с массивом, либо через регулярное выражение.
|
||||
Значит, чтобы прочитать cookie, достаточно разбить строку по `"; "`, и затем найти нужный ключ. Это можно делать либо через `split` и работу с массивом, либо через регулярное выражение.
|
||||
|
||||
### Функция getCookie(name)
|
||||
## Функция getCookie(name)
|
||||
|
||||
Следующая функция `getCookie(name)` возвращает cookie с именем `name`:
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ document.cookie="name=; path=/; expires="+date.toUTCString();
|
|||
|
||||
При удалении значение не важно. Можно его не указывать, как сделано в коде выше.
|
||||
|
||||
### Функция setCookie(name, value, options)
|
||||
## Функция setCookie(name, value, options)
|
||||
|
||||
Если собрать все настройки воедино, вот такая функция ставит куки:
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ function setCookie(name, value, options) {
|
|||
<dt>expires</dt><dd>Время истечения cookie. Интерпретируется по-разному, в зависимости от типа:
|
||||
<ul>
|
||||
<li>Число -- количество секунд до истечения. Например, `expires: 3600` -- кука на час.</li>
|
||||
<li>Объект типа [:Date] -- дата истечения.</li>
|
||||
<li>Объект типа [Date](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Date) -- дата истечения.</li>
|
||||
<li>Если expires в прошлом, то cookie будет удалено.</li>
|
||||
<li>Если expires отсутствует или `0`, то cookie будет установлено как сессионное и исчезнет при закрытии браузера.</li>
|
||||
</ul>
|
||||
|
|
@ -149,13 +149,15 @@ function setCookie(name, value, options) {
|
|||
</dd>
|
||||
</dl>
|
||||
|
||||
### Функция deleteCookie(name)
|
||||
## Функция deleteCookie(name)
|
||||
|
||||
Здесь всё просто -- удаляем вызовом `setCookie` с датой в прошлом.
|
||||
|
||||
```js
|
||||
function deleteCookie(name) {
|
||||
setCookie(name, "", { expires: -1 })
|
||||
setCookie(name, "", {
|
||||
expires: -1
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -248,6 +250,6 @@ if (!navigator.cookieEnabled) {
|
|||
...Конечно, предполагается, что включён JavaScript. Впрочем, посетитель без JS и cookie с большой вероятностью не человек, а бот.</li>
|
||||
</ul>
|
||||
|
||||
## Cookie.js
|
||||
## Итого
|
||||
|
||||
Файл с функциями для работы с cookie: [cookie.js](/files/tutorial/browser/cookie/cookie.js).
|
||||
Файл с функциями для работы с cookie: [cookie.js](cookie.js).
|
||||
|
|
@ -131,7 +131,9 @@ alert( collator.compare("ёжик", "яблоко") ); // -1 (ёжик мень
|
|||
var collator = new Intl.Collator();
|
||||
alert( collator.compare("ЁжиК", "ёжик") ); // 1, разные
|
||||
|
||||
var collator = new Intl.Collator(undefined, { sensitivity: "accent" } );
|
||||
var collator = new Intl.Collator(undefined, {
|
||||
sensitivity: "accent"
|
||||
});
|
||||
alert( collator.compare("ЁжиК", "ёжик") ); // 0, одинаковые
|
||||
```
|
||||
|
||||
|
|
@ -454,7 +456,7 @@ alert( str.localeCompare("яблоко", "ru") ); // -1
|
|||
<dd>Форматирует дату в соответствии с локалью, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var date = new Date(2014, 11, 31, 12, 00);
|
||||
|
||||
alert( date.toLocaleString("ru", { year: 'numeric', month: 'long' }) ); // Декабрь 2014
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Регулярные выражения в javascript немного странные. Вроде - перловые, обычные, но с подводными камнями, на которые натыкаются даже опытные javascript-разработчики.
|
||||
|
||||
Эта статья ставит целью перечислить неожиданные фишки и особенности [:RegExp] в краткой и понятной форме.
|
||||
Эта статья ставит целью перечислить неожиданные фишки и особенности `RegExp` в краткой и понятной форме.
|
||||
|
||||
|
||||
[cut]
|
||||
|
|
@ -120,7 +120,7 @@ P.S. Понятно, что при таком способе поиска bb-т
|
|||
|
||||
### Заменить все
|
||||
|
||||
Для замены всех вхождений используется метод [:String#replace|].
|
||||
Для замены всех вхождений используется метод [String#replace](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/replace).
|
||||
Он интересен тем, что допускает первый аргумент - регэксп или строку.
|
||||
|
||||
Если первый аргумент - строка, то будет осуществлен поиск подстроки, без преобразования в регулярное выражение.
|
||||
|
|
@ -134,7 +134,7 @@ alert("2 ++ 1".replace("+", "*"))
|
|||
|
||||
Как видите, заменился только один плюс, а не оба.
|
||||
|
||||
**Чтобы заменить все вхождения, [:String#replace|] обязательно нужно использовать с регулярным выражением.**
|
||||
**Чтобы заменить все вхождения, [String#replace](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/replace) обязательно нужно использовать с регулярным выражением.**
|
||||
|
||||
В режиме регулярного выражения плюс придётся экранировать, но зато <code>replace</code> заменит все вхождения (при указании флага <code>g</code>):
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ alert("2 ++ 1".replace(/\+/g, "*"))
|
|||
Следующий пример произведет операции вычитания:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var str = "count 36 - 26, 18 - 9"
|
||||
str = str.replace(/(\d+) - (\d+)/g, function(a,b,c) { return b-c })
|
||||
alert(str)
|
||||
|
|
@ -161,7 +161,7 @@ alert(str)
|
|||
### Найти всё
|
||||
|
||||
В javascript нет одного универсального метода для поиска всех совпадений.
|
||||
Для поиска без запоминания скобочных групп - можно использовать [:String#match|]:
|
||||
Для поиска без запоминания скобочных групп - можно использовать [String#match](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/match):
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
|
@ -175,7 +175,7 @@ for(var i=0; i<result.length; i++) alert(result[i])
|
|||
|
||||
### Найти всё с учётом скобочных групп
|
||||
|
||||
В сколько-нибудь сложных задачах важны не только совпадения, но и скобочные группы. Чтобы их найти, предлагается использовать многократный вызов [:RegExp#exec|].
|
||||
В сколько-нибудь сложных задачах важны не только совпадения, но и скобочные группы. Чтобы их найти, предлагается использовать многократный вызов [RegExp#exec](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec).
|
||||
|
||||
Для этого регулярное выражение должно использовать флаг <code>'g'</code>. Тогда результат поиска, запомненный в свойстве <code>lastIndex</code> объекта <code>RegExp</code> используется как точка отсчета для следующего поиска:
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
Пример:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<div class="menu">
|
||||
<span class="title"><%-title%></span>
|
||||
<ul>
|
||||
|
|
@ -129,6 +130,7 @@ alert( compiled() ); // <div>Привет</div>
|
|||
Шаблон для меню в Handlerbars, к примеру, будет выглядеть так:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<div class="menu">
|
||||
<span class="title">{{title}}</span>
|
||||
<ul>
|
||||
|
|
@ -228,7 +230,7 @@ ko.applyBindings(user, document.body);
|
|||
Например:
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<!--+ run no-beautify -->
|
||||
<script src="http://knockoutjs.com/downloads/knockout-3.1.0.js"></script>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ CSS стоит изучать по одной из этих книг. Можно
|
|||
<i>Эрик Мейер</i></li>
|
||||
</ul>
|
||||
|
||||
Конечно, [стандарт CSS 2.1](http://specs.operafan.net/css2.1RU/CSS21/visuren.html) тоже будет вам в помощь. Подчас его скупая простота и точность гораздо понятнее, чем много страниц разъяснений.
|
||||
Конечно, [стандарты](http://www.w3.org/Style/CSS/) тоже будут полезны. Подчас их точность куда проще, чем много страниц разъяснений.
|
||||
|
||||
## JavaScript
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
Полифилл для `setImmediate` через `postMessage`:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
if (!window.setImmediate) window.setImmediate = (function() {
|
||||
var head = { }, tail = head; // очередь вызовов, 1-связный список
|
||||
|
||||
|
|
|
|||
|
|
@ -281,6 +281,7 @@ function ieTextRangeHighlight(text) {
|
|||
Эту задачу мы уже решали в самом начале статьи <a href="#demo-mix">в примере с миксом</a>. Теперь рассмотрим код:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function getSelectionText() {
|
||||
var txt = '';
|
||||
if (txt = window.getSelection) // Не IE, используем метод getSelection
|
||||
|
|
|
|||
|
|
@ -148,8 +148,7 @@ if( body.compareDocumentPosition(li) & 16 ) {
|
|||
(this != other && other.contains(this) && 8) +
|
||||
(this.sourceIndex >= 0 && other.sourceIndex >= 0 ?
|
||||
(this.sourceIndex < other.sourceIndex && 4) +
|
||||
(this.sourceIndex > other.sourceIndex && 2)
|
||||
: 1
|
||||
(this.sourceIndex > other.sourceIndex && 2) : 1
|
||||
) + 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
// вставить elem за последним элементом
|
||||
insertAfter(elem, body.lastChild); // <--- должно работать
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
```html
|
||||
<table id="table">
|
||||
<tr>
|
||||
<td>Это</td><td>Все</td><td>Элементы DOM</td>
|
||||
<td>Это</td>
|
||||
<td>Все</td>
|
||||
<td>Элементы DOM</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
|||
|
|
@ -78,12 +78,10 @@ div.innerHTML = "<strong>Ура!</strong> Вы прочитали это важ
|
|||
</ol>
|
||||
|
||||
<script>
|
||||
|
||||
var newLi = document.createElement('li');
|
||||
newLi.innerHTML = 'Привет, мир!';
|
||||
|
||||
list.appendChild(newLi);
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
@ -101,7 +99,6 @@ div.innerHTML = "<strong>Ура!</strong> Вы прочитали это важ
|
|||
<li>2</li>
|
||||
</ol>
|
||||
<script>
|
||||
|
||||
var newLi = document.createElement('li');
|
||||
newLi.innerHTML = 'Привет, мир!';
|
||||
|
||||
|
|
@ -147,6 +144,7 @@ parentElem.appendChild(elem)
|
|||
```html
|
||||
<!--+ height=150 run autorun -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.css">
|
||||
|
||||
<body>
|
||||
<h3>Моя страница</h3>
|
||||
</body>
|
||||
|
|
@ -167,6 +165,7 @@ parentElem.appendChild(elem)
|
|||
```html
|
||||
<!--+ height=150 run autorun -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.css">
|
||||
|
||||
<body>
|
||||
<h3>Моя страница</h3>
|
||||
</body>
|
||||
|
|
@ -197,6 +196,7 @@ parentElem.appendChild(elem)
|
|||
```html
|
||||
<!--+ height=200 run autorun -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.css">
|
||||
|
||||
<body>
|
||||
<h3>Моя страница</h3>
|
||||
</body>
|
||||
|
|
@ -216,7 +216,6 @@ parentElem.appendChild(elem)
|
|||
// вставим её после текущего сообщения
|
||||
div.parentNode.insertBefore(div2, div.nextSibling);
|
||||
*/!*
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
@ -284,6 +283,7 @@ div.parentNode.insertBefore( div2, div.nextSibling );
|
|||
```html
|
||||
<!--+ run -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.css">
|
||||
|
||||
<body>
|
||||
<h3>Сообщение пропадёт через секунду</h3>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ for(...) ul.appendChild(li); // потом узлы
|
|||
<li>Полностью создать список "вне DOM", а потом -- вставить в документ:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
var ul = document.createElement('ul');
|
||||
for(...) ul.appendChild(li); // сначала вставить узлы
|
||||
document.body.appendChild(ul); // затем в документ
|
||||
|
|
@ -122,7 +123,7 @@ li5.insertAdjacentHTML("beforeBegin", "<li>3</li><li>4</li>");
|
|||
</script>
|
||||
```
|
||||
|
||||
Единственный недостаток этого метода -- он не работает в Firefox до версии 8. Но его можно легко добавить, используя [полифилл insertAdjacentHTML для Firefox](insertAdjacentHTML.js).
|
||||
Единственный недостаток этого метода -- он не работает в Firefox до версии 8. Но его можно легко добавить, используя [полифилл insertAdjacentHTML для Firefox](insertAdjacentFF.js).
|
||||
|
||||
У этого метода есть "близнецы-братья", которые поддерживаются везде, кроме Firefox, но в него они добавляются тем же полифиллом:
|
||||
|
||||
|
|
@ -211,6 +212,7 @@ ul.appendChild(fragment); // вместо фрагмента вставятс
|
|||
```html
|
||||
<!--+ run autorun height=80 -->
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="https://cdn.polyfill.io/v1/polyfill.js?features=Element.prototype.mutation"></script>
|
||||
|
|
@ -233,6 +235,7 @@ ul.appendChild(fragment); // вместо фрагмента вставятс
|
|||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -34,9 +34,13 @@ HTML-документ ниже будет содержать `1 2 3`.
|
|||
</script>
|
||||
<table>
|
||||
<tr>
|
||||
<script> document.write('<td>') </script>
|
||||
<script>
|
||||
document.write('<td>')
|
||||
</script>
|
||||
Текст внутри TD.
|
||||
<script> document.write('</td>') </script>
|
||||
<script>
|
||||
document.write('</td>')
|
||||
</script>
|
||||
</tr>
|
||||
</table>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
**Для свойств, названия которых состоят из нескольких слов, используется вотТакаяЗапись:**
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
background-color => elem.style.backgroundColor
|
||||
z-index => elem.style.zIndex
|
||||
border-left-width => elem.style.borderLeftWidth
|
||||
|
|
@ -146,7 +147,7 @@ setTimeout(function() {
|
|||
Вот так `style` уже ничего не увидит:
|
||||
|
||||
```html
|
||||
<!--+ run height=100 -->
|
||||
<!--+ run height=100 no-beautify -->
|
||||
<head>
|
||||
<style> body { color: red; margin: 5px } </style>
|
||||
</head>
|
||||
|
|
@ -190,8 +191,11 @@ getComputedStyle(element[, pseudo])
|
|||
```html
|
||||
<!--+ run height=100 -->
|
||||
<style>
|
||||
body { margin: 10px }
|
||||
body {
|
||||
margin: 10px
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
|
||||
<script>
|
||||
|
|
@ -264,8 +268,11 @@ function getStyle(elem) {
|
|||
```html
|
||||
<!--+ run height=100 -->
|
||||
<style>
|
||||
body { margin: 10% }
|
||||
body {
|
||||
margin: 10%
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
var elem = document.body;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
Посмотрим следующий случай из жизни. Был текст, который, в частности, содержал `div` с зелеными границами:
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<!--+ run no-beautify -->
|
||||
<style>
|
||||
#moving-div {
|
||||
border: 5px groove green;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
Мы будем использовать для примера вот такой элемент, у которого есть рамка (border), поля (padding), и прокрутка:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<div id="example">
|
||||
...Текст...
|
||||
</div>
|
||||
|
|
@ -125,7 +126,7 @@
|
|||
**Это дает нам замечательный способ для проверки, виден ли элемент**:
|
||||
|
||||
```js
|
||||
function isHidden(elem)
|
||||
function isHidden(elem) {
|
||||
return !elem.offsetWidth && !elem.offsetHeight;
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -80,7 +80,10 @@ function getCoords(elem) {
|
|||
var top = box.top + scrollTop - clientTop;
|
||||
var left = box.left + scrollLeft - clientLeft;
|
||||
|
||||
return { top: top, left: left };
|
||||
return {
|
||||
top: top,
|
||||
left: left
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -104,7 +107,8 @@ function getCoords(elem) {
|
|||
```js
|
||||
//+ autorun
|
||||
function getOffsetSum(elem) {
|
||||
var top = 0, left = 0;
|
||||
var top = 0,
|
||||
left = 0;
|
||||
|
||||
while (elem) {
|
||||
top = top + parseInt(elem.offsetTop);
|
||||
|
|
@ -112,7 +116,10 @@ function getOffsetSum(elem) {
|
|||
elem = elem.offsetParent;
|
||||
}
|
||||
|
||||
return {top: top, left: left};
|
||||
return {
|
||||
top: top,
|
||||
left: left
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@
|
|||
```html
|
||||
<!--+ run -->
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<script>
|
||||
alert( document.body ); // null
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Привет, мир!
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
```html
|
||||
<html>
|
||||
|
||||
<head>
|
||||
*!*
|
||||
<script>
|
||||
|
|
@ -13,9 +14,11 @@
|
|||
</script>
|
||||
*/!*
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Привет, мир!
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ DOM -- это представление документа в виде дере
|
|||
Построим, для начала, дерево DOM для следующего документа.
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<!--+ run no-beautify -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
|
|
@ -60,6 +60,7 @@ drawHtmlTree(node, 'div.domtree', 690, 350);
|
|||
В остальных случаях всё честно -- если пробелы есть в документе, то они есть и в DOM, а если их убрать, то и в DOM их не будет, получится так:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<!DOCTYPE HTML>
|
||||
<html><head><title>О лосях</title></head><body>Правда о лосях</body></html>
|
||||
```
|
||||
|
|
@ -86,6 +87,7 @@ drawHtmlTree(node, 'div.domtree', 690, 300);
|
|||
Такой документ:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<p>Привет
|
||||
<li>Мама
|
||||
<li>и
|
||||
|
|
@ -98,7 +100,7 @@ drawHtmlTree(node, 'div.domtree', 690, 300);
|
|||
<script>
|
||||
var node = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1,"children":[]},{"name":"BODY","nodeType":1,"children":[{"name":"P","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"Привет\n"}]},{"name":"LI","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"Мама\n"}]},{"name":"LI","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"и\n"}]},{"name":"LI","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"Папа\n"}]}]}]}
|
||||
|
||||
drawHtmlTree(node, [].pop.call(document.querySelectorAll('div.domtree')), 690, 400);
|
||||
drawHtmlTree(node, 'div.domtree', 690, 400);
|
||||
</script>
|
||||
|
||||
[warn header="Таблицы всегда содержат `<tbody>`"]
|
||||
|
|
@ -107,6 +109,7 @@ drawHtmlTree(node, [].pop.call(document.querySelectorAll('div.domtree')), 690,
|
|||
Например, для такого HTML:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<table id="table">
|
||||
<tr><td>1</td></tr>
|
||||
</table>
|
||||
|
|
@ -123,6 +126,7 @@ drawHtmlTree(node, 'div.domtree', 600, 200);
|
|||
Вы видите? Появился `<tbody>`, как будто документ был таким:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<table>
|
||||
*!*
|
||||
<tbody>
|
||||
|
|
@ -145,6 +149,7 @@ drawHtmlTree(node, 'div.domtree', 600, 200);
|
|||
```html
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
Правда о лосях
|
||||
<ol>
|
||||
|
|
@ -155,6 +160,7 @@ drawHtmlTree(node, 'div.domtree', 600, 200);
|
|||
<li>...и коварное!</li>
|
||||
</ol>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
@ -216,6 +222,7 @@ IE8- не генерирует текстовые узлы, если они со
|
|||
То есть, такие два документа дадут идентичный DOM:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<!DOCTYPE HTML>
|
||||
<html><head><title>О лосях</title></head><body>Правда о лосях</body></html>
|
||||
```
|
||||
|
|
@ -225,12 +232,15 @@ IE8- не генерирует текстовые узлы, если они со
|
|||
```html
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>О лосях</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Правда о лосях
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@
|
|||
```html
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head><meta charset="utf-8"></head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>Пользователи:</div>
|
||||
<ul>
|
||||
|
|
@ -22,6 +26,7 @@
|
|||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
Вначале нерабочие способы, которые могут прийти на ум:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
if (!elem) { .. }
|
||||
```
|
||||
|
||||
Это не работает, так как `elem` всегда есть, и является объектом. Так что проверка `if (elem)` всегда верна, вне зависимости от того, есть ли у `elem` потомки.
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
if (!elem.childNodes) { ... }
|
||||
```
|
||||
|
||||
|
|
@ -15,6 +17,7 @@ if (!elem.childNodes) { ... }
|
|||
Несколько рабочих способов:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
if (!elem.childNodes.length) { ... }
|
||||
|
||||
if (!elem.firstChild) { ... }
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"Пустой" -- значит нет дочерних узлов, даже текстовых.
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
if (/*...ваш код проверки elem... */) { узел elem пуст }
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ DOM позволяет делать что угодно с HTML-элементо
|
|||
<!--+ run -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<script>
|
||||
*!*
|
||||
|
|
@ -43,6 +44,7 @@ DOM позволяет делать что угодно с HTML-элементо
|
|||
*/!*
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script>
|
||||
|
|
@ -50,6 +52,7 @@ DOM позволяет делать что угодно с HTML-элементо
|
|||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
[/warn]
|
||||
|
|
@ -76,6 +79,7 @@ DOM позволяет делать что угодно с HTML-элементо
|
|||
<!--+ run -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<div>Начало</div>
|
||||
|
||||
|
|
@ -94,6 +98,7 @@ DOM позволяет делать что угодно с HTML-элементо
|
|||
</script>
|
||||
...
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
@ -242,6 +247,7 @@ for(var key in elems) {
|
|||
<!--+ run -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<div>Начало</div>
|
||||
|
||||
|
|
@ -260,6 +266,7 @@ for(var key in elems) {
|
|||
</script>
|
||||
...
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ var elements = document.getElementsByTagName('div');
|
|||
</table>
|
||||
|
||||
<script>
|
||||
|
||||
*!*
|
||||
var tableElem = document.getElementById('age-table');
|
||||
var elements = tableElem.getElementsByTagName('input');
|
||||
|
|
@ -112,7 +111,6 @@ var elements = document.getElementsByTagName('div');
|
|||
var input = elements[i];
|
||||
alert( input.value + ': ' + input.checked );
|
||||
}
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
@ -306,8 +304,9 @@ alert( articles.length ); // 2, найдёт оба элемента
|
|||
Найдем заголовки с текстом `XPath` в текущем документе:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var result = document.evaluate("//h2[contains(., 'XPath')]", document.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
||||
//+ run no-beautify
|
||||
var result = document.evaluate("//h2[contains(., 'XPath')]", document.documentElement, null,
|
||||
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
||||
|
||||
for (var i = 0; i < result.snapshotLength; i++) {
|
||||
alert( result.snapshotItem(i).outerHTML );
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
<li>Магазин</li>
|
||||
</ul>
|
||||
<script>
|
||||
|
||||
var menu = document.getElementById('menu');
|
||||
var lis = menu.getElementsByTagName('li');
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
Для любого документа сделаем следующее:
|
||||
|
||||
```js
|
||||
var aList1 = document.getElementsByTagName('a'),
|
||||
var aList1 = document.getElementsByTagName('a');
|
||||
var aList2 = document.querySelectorAll('a');
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@
|
|||
<!--+ run height=60 -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
alert( document.body.lastChild.nodeType );
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@
|
|||
```html
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
alert( document.body.lastChild.nodeType );
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,8 @@ XML-режим включается, когда браузер получает
|
|||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<body><!-- комментарий -->
|
||||
<body>
|
||||
<!-- комментарий -->
|
||||
|
||||
<script>
|
||||
// для комментария
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@
|
|||
set: function(value) {
|
||||
this.innerText = value;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
|
||||
<div id="widget" data-widget-name="menu">Выберите жанр</div>
|
||||
|
||||
<script>/* ... */</script>
|
||||
<script>
|
||||
/* ... */
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
```html
|
||||
<!--+ run -->
|
||||
<style>
|
||||
.external { background-color: yellow }
|
||||
.external {
|
||||
background-color: yellow
|
||||
}
|
||||
</style>
|
||||
|
||||
<a name="list">список</a>
|
||||
|
|
|
|||
|
|
@ -331,9 +331,11 @@ document.body.sayHi(); // BODY, выполнилась с правильным t
|
|||
.order[order-state="new"] {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.order[order-state="pending"] {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.order[order-state="canceled"] {
|
||||
color: red;
|
||||
}
|
||||
|
|
@ -417,7 +419,7 @@ div.classList.add('order-state-canceled');
|
|||
Этот атрибут должен прятать элемент, действие весьма простое, для его поддержки в HTML достаточно такого CSS:
|
||||
|
||||
```html
|
||||
<!--+ run height="80" -->
|
||||
<!--+ run height="80" no-beautify -->
|
||||
<style>
|
||||
*!*
|
||||
[hidden] { display: none }
|
||||
|
|
@ -441,7 +443,7 @@ div.classList.add('order-state-canceled');
|
|||
|
||||
|
||||
```html
|
||||
<!--+ run height="80" -->
|
||||
<!--+ run height="80" no-beautify -->
|
||||
<style>
|
||||
*!*
|
||||
[hidden] { display: none }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
Что будет выведено при клике после выполнения кода?
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
button.addEventListener("click", function() { alert("1"); });
|
||||
|
||||
button.removeEventListener("click", function() { alert("1"); });
|
||||
|
|
|
|||
|
|
@ -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 остался минимум работы -- только добавить/удалить класс при клике.
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ p {
|
|||
position: absolute;
|
||||
font-size: 110%;
|
||||
top: 0;
|
||||
color: red;
|
||||
color: darkred;
|
||||
right: 10px;
|
||||
display: block;
|
||||
width: 24px;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ p {
|
|||
|
||||
.remove-button {
|
||||
font-size: 110%;
|
||||
color: red;
|
||||
color: darkred;
|
||||
right: 10px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
|
|
|||
|
|
@ -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); } // заменит предыдущий обработчик
|
||||
|
|
@ -294,6 +295,7 @@ element.removeEventListener( event, handler[, phase]);
|
|||
Вот так `removeEventListener` не сработает:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
elem.addEventListener( "click" , function() {alert('Спасибо!')});
|
||||
// ....
|
||||
elem.removeEventListener( "click", function() {alert('Спасибо!')});
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -374,7 +377,7 @@ input.removeEventListener( "click", handler);
|
|||
*!*
|
||||
elem.addEventListener("transitionend", function() {
|
||||
alert( "addEventListener" ); // сработает по окончании анимации
|
||||
}, false);
|
||||
});
|
||||
*/!*
|
||||
</script>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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 ';
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@
|
|||
```html
|
||||
<!--+ run autorun -->
|
||||
<style>
|
||||
body * { margin: 10px; border: 1px solid blue; }
|
||||
body * {
|
||||
margin: 10px;
|
||||
border: 1px solid blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<form onclick="alert('form')">FORM
|
||||
|
|
@ -218,6 +221,7 @@ elem.onclick = function(event) {
|
|||
<dd>Кросс-браузерно остановить всплытие можно так:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ p {
|
|||
position: absolute;
|
||||
font-size: 110%;
|
||||
top: 0;
|
||||
color: red;
|
||||
color: darkred;
|
||||
right: 10px;
|
||||
display: block;
|
||||
width: 24px;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ p {
|
|||
|
||||
.remove-button {
|
||||
font-size: 110%;
|
||||
color: red;
|
||||
color: darkred;
|
||||
right: 10px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
```html
|
||||
<!--+ autorun height=190 untrusted -->
|
||||
<style>
|
||||
li { border: 1px solid green; }
|
||||
li {
|
||||
border: 1px solid green;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ul onclick="alert(event.target)">
|
||||
|
|
@ -57,7 +59,9 @@ 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)">
|
||||
|
|
|
|||
|
|
@ -173,9 +173,15 @@ table.onclick = function(event) {
|
|||
|
||||
<script>
|
||||
function Menu(elem) {
|
||||
this.save = function() { alert('сохраняю'); };
|
||||
this.load = function() { alert('загружаю'); };
|
||||
this.search = function() { alert('ищу'); };
|
||||
this.save = function() {
|
||||
alert( 'сохраняю' );
|
||||
};
|
||||
this.load = function() {
|
||||
alert( 'загружаю' );
|
||||
};
|
||||
this.search = function() {
|
||||
alert( 'ищу' );
|
||||
};
|
||||
|
||||
var self = this;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -138,6 +138,7 @@ element.onclick = function(event) {
|
|||
Можно записать в одну строку:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
...
|
||||
event.preventDefault ? event.preventDefault() : (event.returnValue=false);
|
||||
...
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ var event = new Event(тип события[, флаги]);
|
|||
При просмотре примера ниже кнопка обработчик `onclick` на кнопке сработает сам по себе, событие генерируется скриптом:
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<!--+ run no-beautify -->
|
||||
<button id="elem" onclick="alert('Клик');">Автоклик</button>
|
||||
|
||||
<script>
|
||||
|
|
@ -74,7 +74,9 @@ 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( 'действие отменено' );
|
||||
} else {
|
||||
|
|
@ -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>
|
||||
|
|
@ -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");
|
||||
|
|
@ -304,7 +310,6 @@ event.initEvent("click", true, true);
|
|||
if (elem.dispatchEvent(event) === false) {
|
||||
alert( 'Событие было отменено preventDefault' );
|
||||
}
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@
|
|||
Это событие срабатывает при клике правой кнопкой мыши:
|
||||
|
||||
```html
|
||||
<!--+ autorun height=80 -->
|
||||
<!--+ autorun height=80 no-beautify -->
|
||||
<div>Правый клик на этой кнопке выведет "Клик".</div>
|
||||
<button oncontextmenu="alert('Клик!');">Правый клик сюда</button>
|
||||
```
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
В примере ниже встроенное меню показано не будет:
|
||||
|
||||
```html
|
||||
<!--+ autorun height=60 -->
|
||||
<!--+ autorun height=60 no-beautify -->
|
||||
<button oncontextmenu="alert('Клик!');return false">Правый клик сюда</button>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
Пример использования:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
addScripts(["a.js", "b.js", "c.js"], function() { a() });
|
||||
/* функция a() описана в a.js и использует b.js,c.js */
|
||||
```
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ script.onerror = function() {
|
|||
Например, рабочий скрипт:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var script = document.createElement('script');
|
||||
script.src = "https://code.jquery.com/jquery.js";
|
||||
document.documentElement.appendChild(script);
|
||||
|
|
@ -104,7 +104,7 @@ script.onreadystatechange = function() {
|
|||
Скрипт с ошибкой:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var script = document.createElement('script');
|
||||
script.src = "http://ajax.googleapis.com/404.js";
|
||||
document.documentElement.appendChild(script);
|
||||
|
|
@ -132,7 +132,7 @@ script.onreadystatechange = function() {
|
|||
Пример ниже вызывает `afterLoad` после загрузки скрипта и работает только в IE:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var script = document.createElement('script');
|
||||
script.src = "https://code.jquery.com/jquery.js";
|
||||
document.documentElement.appendChild(script);
|
||||
|
|
@ -189,7 +189,9 @@ script.onload = script.onerror = function() {
|
|||
script.onreadystatechange = function() {
|
||||
var self = this;
|
||||
if (this.readyState == "complete" || this.readyState == "loaded") {
|
||||
setTimeout(function() { self.onload() }, 0);// сохранить "this" для onload
|
||||
setTimeout(function() {
|
||||
self.onload()
|
||||
}, 0); // сохранить "this" для onload
|
||||
}
|
||||
};
|
||||
```
|
||||
|
|
@ -221,6 +223,7 @@ script.onreadystatechange = function() {
|
|||
<dd>Ставим обработчики на `onload` + `onerror`
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
var img = document.createElement('img');
|
||||
img.onload = function() { alert("Успех "+this.src };
|
||||
img.onerror = function() { alert("Ошибка "+this.src };
|
||||
|
|
|
|||
|
|
@ -99,8 +99,12 @@
|
|||
<!--+ autorun height=auto -->
|
||||
<style>
|
||||
b {
|
||||
-webkit-user-select: none; /* user-select -- это нестандартное свойство */
|
||||
-moz-user-select: none; /* поэтому нужны префиксы */
|
||||
-webkit-user-select: none;
|
||||
/* user-select -- это нестандартное свойство */
|
||||
|
||||
-moz-user-select: none;
|
||||
/* поэтому нужны префиксы */
|
||||
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -171,7 +175,7 @@ elem.onmousedown = elem.onselectstart = function() {
|
|||
Если уж хочется запретить копирование -- можно использовать событие `oncopy`:
|
||||
|
||||
```html
|
||||
<!--+ autorun height=80 -->
|
||||
<!--+ autorun height=80 no-beautify -->
|
||||
<div oncopy="alert('Копирование запрещено');return false">
|
||||
Уважаемый копирователь,
|
||||
почему-то автор хочет заставить вас покопаться в исходном коде этой страницы.
|
||||
|
|
|
|||
|
|
@ -356,6 +356,7 @@ function findDroppable(event) {
|
|||
Для его создания используем не обычный синтаксис `{...}`, а вызов `new function`. Это позволит прямо при создании объявить дополнительные переменные и функции в замыкании, которыми могут пользоваться методы объекта, а также назначить обработчики:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
var DragManager = new function() {
|
||||
|
||||
var dragObject = {};
|
||||
|
|
@ -400,6 +401,7 @@ var DragManager = new function() {
|
|||
С использованием `DragManager` пример, с которого начиналась эта глава -- перенос иконок браузеров в компьютер, реализуется совсем просто:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
DragManager.onDragEnd = function(dragObject, dropElem) {
|
||||
|
||||
// скрыть/удалить переносимый объект
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
Несмотря на то, что колёсико мыши обычно ассоциируется с прокруткой, это совсем разные вещи.
|
||||
|
||||
<ul>
|
||||
<li>При прокрутке срабатывает событие [onscroll](/event-onscroll) -- рассмотрим его в дальнейшем. Оно произойдёт *при любой прокрутке*, в том числе через клавиатурy, но *только на прокручиваемых элементах*. Например, элемент с `overflow:hidden` в принципе не может сгенерировать `onscroll`.</li>
|
||||
<li>При прокрутке срабатывает событие [onscroll](/onscroll) -- рассмотрим его в дальнейшем. Оно произойдёт *при любой прокрутке*, в том числе через клавиатурy, но *только на прокручиваемых элементах*. Например, элемент с `overflow:hidden` в принципе не может сгенерировать `onscroll`.</li>
|
||||
<li>А событие `wheel` является чисто "мышиным". Оно генерируется *над любым элементом* при передвижении колеса мыши. При этом не важно, прокручиваемый он или нет. В частности, `overflow:hidden` никак не препятствует обработке колеса мыши.</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
Например, код ниже выведет `alert` при одновременном нажатии клавиш `"Q"` и `"W"` (в любом регистре, в любой раскладке)
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
runOnKeys(
|
||||
function() { alert("Привет!") },
|
||||
"Q".charCodeAt(0),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
Например:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
document.forms.my -- форма с именем 'my'
|
||||
document.forms[0] -- первая форма в документе
|
||||
```
|
||||
|
|
@ -68,7 +69,8 @@ alert(elems[0].value); // 10, первый input
|
|||
<!--+ run height=80 -->
|
||||
<body>
|
||||
<form>
|
||||
<fieldset name="set"><legend>fieldset</legend>
|
||||
<fieldset name="set">
|
||||
<legend>fieldset</legend>
|
||||
<input name="text" type="text">
|
||||
</fieldset>
|
||||
</form>
|
||||
|
|
@ -84,7 +86,7 @@ alert( form.elements.set.elements.text ); // INPUT
|
|||
</body>
|
||||
```
|
||||
|
||||
Спецификация: [HTML5 Forms](http://www.w3.org/TR/html5/forms.html).
|
||||
Спецификация: [HTML5 Forms](https://html.spec.whatwg.org/multipage/forms.html).
|
||||
|
||||
[warn header="Доступ `form.name` тоже работает, но с особенностями"]
|
||||
Получить доступ к элементам формы можно не только через `form.elements[name/index]`, но и проще: `form[index/name]`.
|
||||
|
|
@ -95,7 +97,9 @@ alert( form.elements.set.elements.text ); // INPUT
|
|||
|
||||
```html
|
||||
<!--+ run height=40 -->
|
||||
<form name="myform"> <input name="text"> </form>
|
||||
<form name="myform">
|
||||
<input name="text">
|
||||
</form>
|
||||
|
||||
<script>
|
||||
var form = document.forms.myform;
|
||||
|
|
@ -138,7 +142,7 @@ alert(elem.form == form); // true
|
|||
</body>
|
||||
```
|
||||
|
||||
Познакомиться с другими свойствами элементов можно в спецификации [HTML5 Forms](http://www.w3.org/TR/html5/forms.html).
|
||||
Познакомиться с другими свойствами элементов можно в спецификации [HTML5 Forms](https://html.spec.whatwg.org/multipage/forms.html).
|
||||
|
||||
## Элемент label
|
||||
|
||||
|
|
@ -157,12 +161,20 @@ alert(elem.form == form); // true
|
|||
<!--+ autorun -->
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="agree">Согласен с правилами</label></td>
|
||||
<td><input id="agree" type="checkbox"></td>
|
||||
<td>
|
||||
<label for="agree">Согласен с правилами</label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="agree" type="checkbox">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="not-a-robot">Я не робот</label></td>
|
||||
<td><input id="not-a-robot" type="checkbox"></td>
|
||||
<td>
|
||||
<label for="not-a-robot">Я не робот</label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="not-a-robot" type="checkbox">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
```
|
||||
|
|
@ -171,7 +183,7 @@ alert(elem.form == form); // true
|
|||
<li>Завернуть элемент в `label`. В этом случае можно обойтись без дополнительных атрибутов:
|
||||
|
||||
```html
|
||||
<!--+ autorun -->
|
||||
<!--+ autorun no-beautify -->
|
||||
<label>Кликни меня <input type="checkbox"></label>
|
||||
```
|
||||
|
||||
|
|
@ -242,10 +254,10 @@ for (var i=0; i<select.options.length; i++) {
|
|||
</script>
|
||||
```
|
||||
|
||||
Спецификация: <a href="http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-94282980">HTMLSelectElement</a>.
|
||||
Спецификация: [the select element](https://html.spec.whatwg.org/multipage/forms.html#the-select-element).
|
||||
|
||||
[smart header="`new Option`"]
|
||||
В стандарте [the Option Element](http://dev.w3.org/html5/spec/the-option-element.html#the-option-element) есть любопытный короткий синтаксис для создания элемента с тегом `option`:
|
||||
В стандарте [the option element](https://html.spec.whatwg.org/multipage/forms.html#the-option-element) есть любопытный короткий синтаксис для создания элемента с тегом `option`:
|
||||
|
||||
```js
|
||||
option = new Option(text, value, defaultSelected, selected);
|
||||
|
|
@ -275,7 +287,7 @@ var option = new Option("Текст", "value", true, true);
|
|||
|
||||
[smart header="Дополнительные свойства `option`"]
|
||||
|
||||
У элементов `option` также есть особые свойства, которые могут оказаться полезными (см. [The Option Element](http://dev.w3.org/html5/spec/the-option-element.html#the-option-element)):
|
||||
У элементов `option` также есть особые свойства, которые могут оказаться полезными (см. [the option element](https://html.spec.whatwg.org/multipage/forms.html#the-option-element)):
|
||||
|
||||
<dl>
|
||||
<dt>`selected`</dt>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
Так как мы преобразуем `<div>` в `<textarea>` и обратно, нам нужно сделать их практически одинаковыми с виду:
|
||||
|
||||
```css
|
||||
#view, #area {
|
||||
#view,
|
||||
#area {
|
||||
height: 150px;
|
||||
width: 400px;
|
||||
font-family: arial;
|
||||
|
|
@ -20,6 +21,7 @@
|
|||
```css
|
||||
#view {
|
||||
/* padding + border = 3px */
|
||||
|
||||
padding: 2px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
|
@ -31,7 +33,6 @@ CSS для `#area` заменяет поля границами:
|
|||
#area {
|
||||
border: 3px groove blue;
|
||||
padding: 0px;
|
||||
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
|
@ -39,6 +40,7 @@ CSS для `#area` заменяет поля границами:
|
|||
По умолчанию, текстовое поле скрыто. Кстати, этот код убирает дополнительную рамку в ряде браузеров, которая появляется вокруг поля, когда на него попадает фокус:
|
||||
|
||||
```css
|
||||
/*+ no-beautify */
|
||||
#area:focus {
|
||||
outline: none; /* убирает рамку при фокусе */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,23 +57,32 @@
|
|||
|
||||
```html
|
||||
<!--+ run autorun height=80 -->
|
||||
<style> .error { background: red; } </style>
|
||||
<style>
|
||||
.error {
|
||||
background: red;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div>Возраст: <input type="text" id="age"></div>
|
||||
<div>Возраст:
|
||||
<input type="text" id="age">
|
||||
</div>
|
||||
|
||||
<div>Имя: <input type="text"></div>
|
||||
<div>Имя:
|
||||
<input type="text">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
age.onblur = function() {
|
||||
if (isNaN(this.value)) { // введено не число
|
||||
// показать ошибку
|
||||
this.classList.add("error");
|
||||
age.focus();*!*
|
||||
*!*
|
||||
age.focus();
|
||||
*/!*
|
||||
} else {
|
||||
this.classList.remove("error");
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
@ -175,7 +184,7 @@ age.onblur = function() {
|
|||
В примере ниже есть список элементов. Кликните на любой из них и нажмите "tab".
|
||||
|
||||
```html
|
||||
<!--+ autorun -->
|
||||
<!--+ autorun no-beautify -->
|
||||
Кликните на первый элемент списка и нажмите Tab. Внимание! Дальнейшие нажатия Tab могут вывести за границы iframe'а с примером.
|
||||
<ul>
|
||||
<li tabindex="1">Один</li>
|
||||
|
|
@ -225,7 +234,11 @@ age.onblur = function() {
|
|||
<input type="text" name="surname" value="Ваша фамилия">
|
||||
</form>
|
||||
|
||||
<style> .focused { outline: 1px solid red; } </style>
|
||||
<style>
|
||||
.focused {
|
||||
outline: 1px solid red;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
*!*
|
||||
|
|
@ -262,12 +275,19 @@ age.onblur = function() {
|
|||
<input type="text" name="surname" value="Ваша фамилия">
|
||||
</form>
|
||||
<style>
|
||||
.focused { outline: 1px solid red; }
|
||||
.focused {
|
||||
outline: 1px solid red;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function onFormFocus() { this.className = 'focused'; }
|
||||
function onFormBlur() { this.className = ''; }
|
||||
function onFormFocus() {
|
||||
this.className = 'focused';
|
||||
}
|
||||
|
||||
function onFormBlur() {
|
||||
this.className = '';
|
||||
}
|
||||
|
||||
var form = document.forms.form;
|
||||
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ if("onpropertychange" in checkbox) {
|
|||
<!--+ autorun run height=60 -->
|
||||
<input type="text" id="sms"> символов: <span id="result"></span>
|
||||
<script>
|
||||
|
||||
function showCount() {
|
||||
result.innerHTML = sms.value.length;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
Например, в таком HTML оба способа выведут `alert`, форма не будет отправлена:
|
||||
|
||||
```html
|
||||
<!--+ autorun height=80 -->
|
||||
<!--+ autorun height=80 no-beautify -->
|
||||
<form onsubmit="alert('submit!');return false">
|
||||
Первый: Enter в текстовом поле <input type="text" value="Текст"><br>
|
||||
Второй: Нажать на "Отправить": <input type="submit" value="Отправить">
|
||||
|
|
|
|||
|
|
@ -47,7 +47,9 @@
|
|||
function Menu(options) {
|
||||
var elem = options.elem;
|
||||
|
||||
elem.onmousedown = function() { return false; }
|
||||
elem.onmousedown = function() {
|
||||
return false;
|
||||
}
|
||||
|
||||
elem.onclick = function(event) {
|
||||
if (event.target.closest('.title')) {
|
||||
|
|
@ -127,7 +129,9 @@ if (event.target.closest('.title')) {
|
|||
function Menu(options) {
|
||||
var elem = options.elem;
|
||||
|
||||
elem.onmousedown = function() { return false; }
|
||||
elem.onmousedown = function() {
|
||||
return false;
|
||||
}
|
||||
|
||||
elem.onclick = function(event) {
|
||||
if (event.target.closest('.title')) {
|
||||
|
|
|
|||
|
|
@ -22,10 +22,8 @@
|
|||
float: left;
|
||||
padding: 6px;
|
||||
margin: 0 2px;
|
||||
|
||||
border: 1px solid gray;
|
||||
border-radius: 10px;
|
||||
|
||||
cursor: pointer;
|
||||
font-size: 90%;
|
||||
background: #FFF5EE;
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ HTML-разметка и названия CSS-классов должны отр
|
|||
Рассмотрим пример вёрстки "диалогового окна":
|
||||
|
||||
```html
|
||||
<!--+ autorun height=100 -->
|
||||
<!--+ autorun height=100 no-beautify -->
|
||||
<div class="dialog">
|
||||
<h2 class="title">Заголовок</h2>
|
||||
<div class="content">
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
Есть данные:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
var users = [
|
||||
{name: "Вася", age: 10},
|
||||
{name: "Петя", age: 15},
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
Ранее мы уже видели код `Menu`, который сам создаёт свой элемент:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function Menu(options) {
|
||||
// ... приведены только методы для генерации DOM ...
|
||||
|
||||
|
|
@ -66,6 +67,7 @@ function Menu(options) {
|
|||
Пример шаблона для меню:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<div class="menu">
|
||||
<span class="title"><%-title%></span>
|
||||
<ul>
|
||||
|
|
@ -180,7 +182,7 @@ alert( tmpl(data) ); // <span class="title">Заголовок</span>
|
|||
Например, вот шаблон для генерации списка от `1` до `count`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
// используется \, чтобы объявить многострочную переменную-текст шаблона
|
||||
var tmpl = '<ul>\
|
||||
<% for (var i=1; i<=count; i++) { %> \
|
||||
|
|
@ -263,6 +265,7 @@ alert( compiled );
|
|||
Функция `compiled`, которую вернул вызов `_template` из этого примера, выглядит примерно так:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function(obj) {
|
||||
obj || (obj = {});
|
||||
var __t, __p = '', __e = _.escape;
|
||||
|
|
@ -297,7 +300,7 @@ function(obj) {
|
|||
Например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
alert( _.template("<h1><%=menu.title%></h1>", {variable: "menu"}) );
|
||||
```
|
||||
|
||||
|
|
@ -331,6 +334,7 @@ function(*!*menu*/!*) {
|
|||
HTML (шаблоны):
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<script type="text/template" id="menu-template">
|
||||
<div class="menu">
|
||||
<span class="title"><%-title%></span>
|
||||
|
|
@ -380,7 +384,9 @@ function Menu(options) {
|
|||
}
|
||||
|
||||
function render() {
|
||||
var html = options.template({title: options.title});
|
||||
var html = options.template({
|
||||
title: options.title
|
||||
});
|
||||
|
||||
elem = document.createElement('div');
|
||||
elem.innerHTML = html;
|
||||
|
|
@ -400,7 +406,9 @@ function Menu(options) {
|
|||
function renderItems() {
|
||||
if (elem.querySelector('ul')) return;
|
||||
|
||||
var listHtml = options.listTemplate({items: options.items});
|
||||
var listHtml = options.listTemplate({
|
||||
items: options.items
|
||||
});
|
||||
elem.insertAdjacentHTML("beforeEnd", listHtml);
|
||||
}
|
||||
|
||||
|
|
@ -432,6 +440,7 @@ function Menu(options) {
|
|||
Здесь два шаблона. Первый мы уже разобрали, посмотрим теперь на список `ul/li`:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<ul>
|
||||
<% items.forEach(function(item) { %>
|
||||
<li><%-item%></li>
|
||||
|
|
@ -453,6 +462,7 @@ function Menu(options) {
|
|||
Вот функция, которую возвратит `_.template(tmpl)` для этого шаблона:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function(obj) {
|
||||
obj || (obj = {});
|
||||
var __t, __p = '', __e = _.escape;
|
||||
|
|
@ -485,7 +495,7 @@ function(obj) {
|
|||
Попробуйте сами запустить пример с открытыми инструментами разработчика и *включённой* опцией "остановка при ошибке":
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<!--+ run no-beautify -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||
|
||||
<script type="text/template" id="menu-template">
|
||||
|
|
@ -523,6 +533,7 @@ function(obj) {
|
|||
Это, конечно, лучше чем ничего, но, как правило, его имеет смысл заменить `sourceURL` на свой, указав при компиляции дополнительный параметр `sourceURL`:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
...
|
||||
var compiled = _.template(tmpl, {sourceURL: '/template/menu-template'});
|
||||
...
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
Например, мы можем добавить в `options` для `Menu` новый параметр -- функцию `onselect`, которая будет вызываться при выборе пункта меню:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
var menu = new Menu({
|
||||
title: "Сладости",
|
||||
template: _.template(document.getElementById('menu-template').innerHTML),
|
||||
|
|
@ -37,6 +38,7 @@ function showSelected(href) {
|
|||
В коде меню нужно будет вызывать её, например так:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
...
|
||||
function select(link) {
|
||||
options.onselect(link.getAttribute('href').slice(1));
|
||||
|
|
@ -58,6 +60,7 @@ function showSelected(href) {
|
|||
Для этого модифицируем функцию `select`:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function Menu(options) {
|
||||
...
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@
|
|||
В примере ниже регистрация элемента происходит через 2 секунды после его появления в разметке:
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<!--+ run no-beautify -->
|
||||
<style>
|
||||
*!*
|
||||
/* стиль для :unresolved элемента (до регистрации) */
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
В Shadow DOM выше можно увидеть полезный атрибут `pseudo`. Он нестандартный, существует по историческим причинам. С его помощью можно стилизовать подэлементы через CSS, например, сделаем поле редактирования даты красным:
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<!--+ run no-beautify -->
|
||||
<style>
|
||||
*!*
|
||||
input::-webkit-datetime-edit {
|
||||
|
|
@ -92,7 +92,7 @@ Shadow DOM примера выше в инструментах разработ
|
|||
Например:
|
||||
|
||||
```html
|
||||
<!--+ run autorun="no-epub" -->
|
||||
<!--+ run autorun="no-epub" no-beautify -->
|
||||
|
||||
<section id="elem">
|
||||
<h1>Новости</h1>
|
||||
|
|
|
|||
|
|
@ -19,13 +19,15 @@
|
|||
|
||||
```html
|
||||
<!--+ run autorun="no-epub" -->
|
||||
|
||||
<p id="elem">Доброе утро, страна!</p>
|
||||
<p id="elem">
|
||||
Доброе утро, страна!</p>
|
||||
|
||||
<template id="tmpl">
|
||||
<h3><content></content></h3>
|
||||
<p>Привет из подполья!</p>
|
||||
<script> document.write('...document.write:Новость!'); </script>
|
||||
<script>
|
||||
document.write('...document.write:Новость!');
|
||||
</script>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@
|
|||
|
||||
<template id="tmpl">
|
||||
*!*
|
||||
<style> p { color: red; } </style>
|
||||
<style>
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
*/!*
|
||||
<h3><content></content></h3>
|
||||
<p>Привет из подполья!</p>
|
||||
|
|
@ -54,11 +58,13 @@
|
|||
<style>
|
||||
#elem::shadow span {
|
||||
/* для span только внутри Shadow DOM #elem */
|
||||
|
||||
border-bottom: 1px dashed blue;
|
||||
}
|
||||
|
||||
#elem >>> * {
|
||||
/* для всех элементов внутри Shadow DOM #elem и далее внутри input[type=date] */
|
||||
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -132,7 +138,9 @@
|
|||
|
||||
```html
|
||||
<style>
|
||||
:host > p { color: green; }
|
||||
:host > p {
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
Этот селектор сработает для `<p>` первого уровня внутри Shadow DOM.
|
||||
|
|
@ -142,8 +150,13 @@
|
|||
Этот селектор используется для темизации хозяина "изнутри", в зависимости от его классов и атрибутов. Он отлично добавляет просто `:host`, например:
|
||||
|
||||
```css
|
||||
:host p { color: green; }
|
||||
:host(.important) p { color: red; }
|
||||
:host p {
|
||||
color: green;
|
||||
}
|
||||
|
||||
:host(.important) p {
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
Здесь параграфы будут иметь `color:green`, но если у хозяина класс `.important`, то `color:red`.
|
||||
|
|
@ -163,7 +176,7 @@
|
|||
Пример использования селектора `:host()` для разной расцветки Shadow DOM-сообщения, в зависимости от того, в каком оно `<p>`:
|
||||
|
||||
```html
|
||||
<!--+ run autorun="no-epub" -->
|
||||
<!--+ run autorun="no-epub" no-beautify -->
|
||||
*!*
|
||||
<p class="message info">Доброе утро, страна!</p>
|
||||
*/!*
|
||||
|
|
@ -215,7 +228,7 @@ elems[1].createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
|
|||
Например, здесь применится стиль для `<span>`:
|
||||
|
||||
```html
|
||||
<!--+ run autorun="no-epub" -->
|
||||
<!--+ run autorun="no-epub" no-beautify -->
|
||||
<style>
|
||||
*!*
|
||||
span { text-decoration: underline; }
|
||||
|
|
@ -247,7 +260,7 @@ elems[1].createShadowRoot().appendChild( tmpl.content.cloneNode(true) );
|
|||
В примере ниже селектор `::content span` стилизует все `<span>` внутри всех `<content>`:
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<!--+ run no-beautify -->
|
||||
<style>
|
||||
*!*
|
||||
span { text-decoration: underline; }
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@
|
|||
<li>Главный файл `index.html` подключает документы:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<link rel="import" href="ui-tabs.html">
|
||||
<link rel="import" href="ui-dialog.html">
|
||||
...
|
||||
|
|
@ -111,6 +112,7 @@
|
|||
<li>`ui-tabs.html` подключает `libs.html`:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<link rel="import" href="libs.html">
|
||||
...template и код для табов...
|
||||
```
|
||||
|
|
@ -120,6 +122,7 @@
|
|||
<li>`ui-dialog.html` также использует `libs.html`:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<link rel="import" href="libs.html">
|
||||
...template и код для диалогов...
|
||||
```
|
||||
|
|
|
|||
|
|
@ -60,7 +60,9 @@
|
|||
color: red;
|
||||
}
|
||||
</style>
|
||||
<div class="content"><content></content></div>
|
||||
<div class="content">
|
||||
<content></content>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
|
|
@ -171,7 +173,6 @@ document.registerElement('ui-message', {
|
|||
<template id="tmpl">
|
||||
<style>
|
||||
@import url(http://code.jquery.com/ui/1.11.3/themes/ui-lightness/jquery-ui.css);
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
|
@ -209,7 +210,9 @@ SliderProto.createdCallback = function() {
|
|||
slide: function() {
|
||||
// (3) пробросить событие
|
||||
var event = new CustomEvent("slide", {
|
||||
detail: { value: self.$slider.slider("option", "value") },
|
||||
detail: {
|
||||
value: self.$slider.slider("option", "value")
|
||||
},
|
||||
bubbles: true
|
||||
});
|
||||
self.dispatchEvent(event);
|
||||
|
|
@ -258,7 +261,10 @@ Object.defineProperty(SliderProto, 'value', {
|
|||
Он был в методе [offset](http://api.jquery.com/offset/), который предназначен для того, чтобы определять координаты элемента. Этот метод не срабатывал, поскольку в нём есть проверка, которая выглядит примерно так:
|
||||
|
||||
```js
|
||||
var box = { top: 0, left: 0 };
|
||||
var box = {
|
||||
top: 0,
|
||||
left: 0
|
||||
};
|
||||
...
|
||||
// Make sure it's not a disconnected DOM node
|
||||
if(!jQuery.contains(elem.ownerDocument, elem)) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# Веб-компоненты: взгляд в будущее
|
||||
|
||||
Веб-компоненты -- "платформа будущего": совокупность стандартов, которые позволяют описывать "свои теги" -- новые типы DOM-элементов, со своими свойствами и методами, инкапсулировать их DOM и стили.
|
||||
|
||||
Современные браузеры поддерживают их частично.
|
||||
Веб-компоненты -- "платформа будущего": совокупность стандартов, которые позволяют описывать новые типы DOM-элементов, со своими свойствами и методами, инкапсулировать их DOM и стили.
|
||||
|
|
@ -24,7 +24,7 @@ addScript('user?id=123');
|
|||
|
||||
Такой вызов добавит в `HEAD` документа тег:
|
||||
|
||||
```js
|
||||
```html
|
||||
<script src="/user?id=123"></script>
|
||||
```
|
||||
|
||||
|
|
@ -38,6 +38,7 @@ addScript('user?id=123');
|
|||
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
// ответ сервера
|
||||
var user = {name: "Вася", age: 25 };
|
||||
```
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ id: 3
|
|||
У объекта `EventSource` есть свойство `readyState`, которое содержит одно из значений (выдержка из стандарта):
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
const unsigned short CONNECTING = 0; // в процессе (пере-)соединения
|
||||
const unsigned short OPEN = 1; // соединение установлено
|
||||
const unsigned short CLOSED = 2; // соединение закрыто
|
||||
|
|
@ -203,7 +204,9 @@ eventSource.addEventListener('leave', function(e) {
|
|||
`EventSource` поддерживает кросс-доменные запросы, аналогично `XMLHttpRequest`. Для этого у конструктора есть второй аргумент -- объект, который нужно передать так:
|
||||
|
||||
```js
|
||||
var source = new EventSource("http://pupkin.ru/stream", { withCredentials: true });
|
||||
var source = new EventSource("http://pupkin.ru/stream", {
|
||||
withCredentials: true
|
||||
});
|
||||
```
|
||||
|
||||
Второй аргумент сделан объектом с расчётом на будущее. Пока что никаких других свойств там не поддерживается, только `withCredentials`.
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ var iframeDoc = iframe.contentWindow.document;
|
|||
<li>Когда ифрейм уже создан, то единственный способ поменять его `src` без попадания запроса в историю посещений:
|
||||
|
||||
```js
|
||||
|
||||
// newSrc - новый адрес
|
||||
iframeDoc.location.replace(newSrc);
|
||||
```
|
||||
|
|
@ -181,6 +180,7 @@ function postToIframe(url, data, target){
|
|||
<li>Сервер отвечает как-то так:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<script>
|
||||
parent.CallbackRegistry[window.name]({данные});
|
||||
</script>
|
||||
|
|
@ -257,6 +257,7 @@ function postToIframe(url, data, target){
|
|||
Поэтому в таком `IFRAME` первые несколько сообщений задержатся:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
|
|
@ -270,10 +271,15 @@ function postToIframe(url, data, target){
|
|||
```html
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
******* 1 килобайт пробелов, а потом уже сообщения ******
|
||||
<script>parent.onMessage("привет");</script>
|
||||
<script>parent.onMessage("от сервера");</script>
|
||||
<script>
|
||||
parent.onMessage("привет");
|
||||
</script>
|
||||
<script>
|
||||
parent.onMessage("от сервера");
|
||||
</script>
|
||||
...
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
<li>На злой странице находится форма такого вида:
|
||||
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<form action="http://mail.com/send" method="POST">
|
||||
<input type="hidden" name="message" value="Сообщение">
|
||||
...
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@ xhr.send(body);
|
|||
Для добавления файла нужно использовать тот же код, что выше, модифицировав заголовки перед полем, которое является файлом, так:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
Content-Disposition: form-data; name="myfile"; filename="pic.jpg"
|
||||
Content-Type: image/jpeg
|
||||
(пустая строка)
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ xhr.open('POST', 'http://anywhere.com/request', true)
|
|||
Пример заголовков:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type:text/html; charset=UTF-8
|
||||
*!*
|
||||
|
|
|
|||
|
|
@ -452,7 +452,9 @@ var WebSocketServer = new require('ws');
|
|||
var clients = {};
|
||||
|
||||
// WebSocket-сервер на порту 8081
|
||||
var webSocketServer = new WebSocketServer.Server({port: 8081});
|
||||
var webSocketServer = new WebSocketServer.Server({
|
||||
port: 8081
|
||||
});
|
||||
webSocketServer.on('connection', function(ws) {
|
||||
|
||||
var id = Math.random();
|
||||
|
|
@ -475,7 +477,7 @@ webSocketServer.on('connection', function(ws) {
|
|||
});
|
||||
```
|
||||
|
||||
Рабочий пример можно скачать: [websocket.zip](/zip/tutorial/ajax/websocket.zip). Понадобится поставить два модуля: `npm install node-static && npm install ws`.
|
||||
Рабочий пример можно скачать: [websocket.zip](websocket.zip). Понадобится поставить два модуля: `npm install node-static && npm install ws`.
|
||||
## Итого
|
||||
|
||||
WebSocket -- современное средство коммуникации. Кросс-доменное, универсальное, безопасное.
|
||||
|
|
@ -489,6 +491,3 @@ WebSocket -- современное средство коммуникации.
|
|||
Например, для Node.JS одной из самых известных библиотек является [Socket.IO](http://socket.io).
|
||||
|
||||
К недостаткам библиотек следует отнести то, что некоторые продвинутые возможности WebSocket, такие как двухсторонний обмен бинарными данными, в них недоступны. С другой -- в большинстве случаев стандартного текстового обмена вполне достаточно.
|
||||
[head]
|
||||
<script src="/files/tutorial/ajax/script/scriptRequest.js"></script>
|
||||
[/head]
|
||||
BIN
4-ajax/9-websockets/websocket.zip
Normal file
BIN
4-ajax/9-websockets/websocket.zip
Normal file
Binary file not shown.
|
|
@ -1,5 +1,3 @@
|
|||
# AJAX и COMET
|
||||
|
||||
Современный `XMLHttpRequest`, включая поддержку докачки, индикации прогресса, кросс-доменных запросов.
|
||||
|
||||
WebSocket. Альтернативные методы общения с сервером при помощи JSONP и IFRAME'ов.
|
||||
Современные средства для обмена данными с сервером и смежные аспекты.
|
||||
|
|
|
|||
|
|
@ -119,11 +119,15 @@
|
|||
<li>Эти точки соединяются. На рисунке ниже соединяющий их отрезок изображён <span style="color:blue">синим</span>.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr><td>При `t=0.25`</td><td>При `t=0.5`</td></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><img src="bezier3-draw1.svg"></td>
|
||||
<td><img src="bezier3-draw2.svg"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</li>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 7.5 KiB |
|
|
@ -2,10 +2,10 @@
|
|||
CSS-код для анимации одновременно `width` и `height`:
|
||||
```css
|
||||
/* исходный класс */
|
||||
|
||||
#flyjet {
|
||||
transition: all 3s;
|
||||
}
|
||||
|
||||
/* JS добавляет .growing *.
|
||||
#flyjet.growing {
|
||||
width: 400px;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ color.onclick = function() {
|
|||
Например, при клике на эту кнопку анимируются одновременно цвет и размер шрифта:
|
||||
|
||||
```html
|
||||
<!--+ run height=80 autorun -->
|
||||
<!--+ run height=80 autorun no-beautify -->
|
||||
<button id="growing">Кликни меня</button>
|
||||
|
||||
<style>
|
||||
|
|
@ -380,20 +380,29 @@ boat.onclick = function() {
|
|||
|
||||
```html
|
||||
<!--+ run height=60 -->
|
||||
|
||||
<div class="progress"></div>
|
||||
<div class="progress">
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Chrome, Opera, Safari */
|
||||
@-webkit-keyframes MY-ANIMATION-NAME {
|
||||
from { left:0px; }
|
||||
to { left:300px; }
|
||||
}
|
||||
|
||||
@-webkit-keyframes MY-ANIMATION-NAME {
|
||||
from {
|
||||
left: 0px;
|
||||
}
|
||||
to {
|
||||
left: 300px;
|
||||
}
|
||||
}
|
||||
/* Other browsers, except IE9- */
|
||||
|
||||
@keyframes MY-ANIMATION-NAME {
|
||||
from { left:0px; }
|
||||
to { left:300px; }
|
||||
from {
|
||||
left: 0px;
|
||||
}
|
||||
to {
|
||||
left: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.progress {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
Например:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
// присвоить
|
||||
$(document).data('prop', { anything: "любой объект" })
|
||||
|
||||
|
|
@ -34,6 +35,7 @@ elem[ jQuery.expando ] = id = ++jQuery.uuid; // средствами jQuery
|
|||
<li>...А сами данные сохраняются в специальном объекте `jQuery.cache`:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
jQuery.cache[id]['prop'] = { anything: "любой объект" };
|
||||
```
|
||||
|
||||
|
|
@ -55,20 +57,37 @@ jQuery.cache[id]['prop'] = { anything: "любой объект" };
|
|||
|
||||
## Примеры утечек в jQuery
|
||||
|
||||
Следующий код создает jQuery-утечку во всех браузерах:
|
||||
Следующая функция `leak` создает jQuery-утечку во всех браузерах:
|
||||
|
||||
```js
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<script src="http://code.jquery.com/jquery.min.js"></script>
|
||||
|
||||
<div id="data"></div>
|
||||
|
||||
<script>
|
||||
function leak() {
|
||||
|
||||
*!*
|
||||
$('<div/>')
|
||||
.html(new Array(1000).join('text')) // div с текстом, возможна AJAX-загрузка
|
||||
.html(new Array(1000).join('text'))
|
||||
.click(function() {})
|
||||
.appendTo('#data')
|
||||
.appendTo('#data');
|
||||
|
||||
document.getElementById('data').innerHTML = ''; // (*)
|
||||
document.getElementById('data').innerHTML = '';
|
||||
*/!*
|
||||
|
||||
}
|
||||
|
||||
var interval = setInterval(leak, 10)
|
||||
</script>
|
||||
|
||||
Утечка идёт...
|
||||
|
||||
<input type="button" onclick="clearInterval(interval)" value="stop" />
|
||||
```
|
||||
|
||||
Полный пример:
|
||||
|
||||
[codetabs src="jquery-leak"]
|
||||
|
||||
Утечка происходит потому, что обработчик события в jQuery хранится в данных элемента. В строке `(*)` элемент удален очисткой родительского `innerHTML`, но в `jQuery.cache` данные остались.
|
||||
|
||||
|
|
@ -79,7 +98,7 @@ document.getElementById('data').innerHTML = ''; // (*)
|
|||
Этот код также создает утечку:
|
||||
|
||||
```js
|
||||
function go() {
|
||||
function leak() {
|
||||
$('<div/>')
|
||||
.click(function() {})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="http://code.jquery.com/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="data"></div>
|
||||
|
||||
<script>
|
||||
function go() {
|
||||
|
||||
$('<div/>')
|
||||
.html(new Array(1000).join('text'))
|
||||
.click(function() {})
|
||||
.appendTo('#data');
|
||||
|
||||
document.getElementById('data').innerHTML = '';
|
||||
|
||||
}
|
||||
|
||||
var interval = setInterval(go, 10)
|
||||
</script>
|
||||
|
||||
Утечка идёт...
|
||||
|
||||
<input type="button" onclick="clearInterval(interval)" value="stop" />
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -146,6 +146,7 @@ function test(a, b) {
|
|||
После:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function test(a,b){run(a,"mystring",18E5,0,b&&0)};
|
||||
```
|
||||
|
||||
|
|
@ -169,6 +170,7 @@ function sayHi(*!*name*/!*, *!*message*/!*) {
|
|||
После оптимизации:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function sayHi(a,b){alert(a+" сказал: "+b)};
|
||||
```
|
||||
|
||||
|
|
@ -193,6 +195,7 @@ function test(nodeId) {
|
|||
После оптимизации GCC:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function test(a){a=document.getElementsById(a).parentNode;alert(a)};
|
||||
```
|
||||
|
||||
|
|
@ -226,6 +229,7 @@ function test(node) {
|
|||
После оптимизации:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function test(){alert("Останется только один")}
|
||||
```
|
||||
|
||||
|
|
@ -263,6 +267,7 @@ if (i=='1') {
|
|||
После оптимизации:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
for(var i=0;10>i++;)alert(i);i&&alert(i);"1"==i?alert(1):"2"==i?alert(2):alert(i);
|
||||
```
|
||||
|
||||
|
|
@ -359,7 +364,8 @@ function sayHi(b){
|
|||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
};
|
||||
}})();
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
<ul>
|
||||
|
|
@ -385,6 +391,7 @@ function sayHi(b){
|
|||
<li>Убираются лишние кавычки у ключей
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
{"prop" : "val" } => {prop:"val"}
|
||||
```
|
||||
|
||||
|
|
@ -392,6 +399,7 @@ function sayHi(b){
|
|||
<li>Упрощаются простые вызовы `Array/Object`
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
a = new Array() => a = []
|
||||
o = new Object() => o = {}
|
||||
```
|
||||
|
|
@ -414,6 +422,7 @@ o = new Object() => o = {}
|
|||
Рассмотрим код:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function changePosition(style) {
|
||||
var position, test;
|
||||
|
||||
|
|
@ -432,6 +441,7 @@ function changePosition(style) {
|
|||
Можно ли в такой ситуации заменить локальную переменную на более короткую? Очевидно, нет:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function changePosition(style) {
|
||||
var a, b;
|
||||
|
||||
|
|
@ -446,6 +456,7 @@ function changePosition(style) {
|
|||
Такая же опасность для сжатия кроется в использованном `eval`. Ведь `eval` может обращаться к локальным переменным:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function f(code) {
|
||||
var myVar;
|
||||
|
||||
|
|
@ -483,18 +494,10 @@ function f(code) {
|
|||
//+ run
|
||||
var isIE /*@cc_on =true@*/ ;
|
||||
|
||||
alert(isIE); // true в IE.
|
||||
alert( isIE ); // true в IE10-
|
||||
```
|
||||
|
||||
Там же доступны и дополнительные директивы: `@_jscript_version`, `@if` и т.п., но речь здесь не о том.
|
||||
|
||||
Для минификаторов этот "условный" комментарий -- всего лишь обычный комментарий. Они его удалят. Получится, что код не поймёт, где же IE.
|
||||
|
||||
Что делать?
|
||||
|
||||
<ol>
|
||||
<li>Первое и наиболее корректное решение -- не использовать условную компиляцию.</li>
|
||||
<li>Второе, если уж очень надо -- применить хак, завернуть его в `eval` или `new Function` (чтобы сжиматель не ругался):
|
||||
Можно хитро сделать, чтобы комментарий остался, например так:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
|
@ -503,10 +506,8 @@ var isIE = new Function('', '/*@cc_on return true@*/')();
|
|||
alert( isIE ); // true в IE.
|
||||
```
|
||||
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
Ещё раз заметим, что в современных IE11+ эта компиляция не работает в любом случае.
|
||||
...Однако, с учётом того, что в современных IE11+ эта компиляция не работает в любом случае, лучше избавиться от неё вообще.
|
||||
|
||||
В следующих главах мы посмотрим, какие продвинутые возможности есть в минификаторах, как сделать сжатие более эффективным.
|
||||
|
||||
|
|
|
|||
|
|
@ -121,13 +121,17 @@ first:2 --module second:1:first
|
|||
Например:
|
||||
|
||||
```js
|
||||
document.onkeyup = function(event) { alert(event.type) }
|
||||
document.onkeyup = function(event) {
|
||||
alert(event.type)
|
||||
}
|
||||
```
|
||||
|
||||
После продвинутого сжатия:
|
||||
|
||||
```js
|
||||
document.onkeyup = function(a) { alert(a.type) }
|
||||
document.onkeyup = function(a) {
|
||||
alert(a.type)
|
||||
}
|
||||
```
|
||||
|
||||
Как видите, переименованной оказалась только переменная `event`. Такое переименование заведомо безопасно, т.к. `event` -- локальная переменная.
|
||||
|
|
@ -135,13 +139,17 @@ document.onkeyup = function(a) { alert(a.type) }
|
|||
Почему компилятор не тронул остального? Попробуем другой вариант:
|
||||
|
||||
```js
|
||||
document.blabla = function(event) { alert(event.megaProperty) }
|
||||
document.blabla = function(event) {
|
||||
alert(event.megaProperty)
|
||||
}
|
||||
```
|
||||
|
||||
После компиляции:
|
||||
|
||||
```js
|
||||
document.a = function(a) { alert(a.b) }
|
||||
document.a = function(a) {
|
||||
alert(a.b)
|
||||
}
|
||||
```
|
||||
|
||||
Теперь компилятор переименовал и <code>blabla</code> и <code>megaProperty</code>.
|
||||
|
|
@ -268,6 +276,7 @@ SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler;
|
|||
После сжатия:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function a(b) {
|
||||
this.a = b;
|
||||
this.b()
|
||||
|
|
@ -428,6 +437,7 @@ MyFramework.publicOne();
|
|||
Результат компиляции в обычном режиме:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
// java -jar compiler.jar --js myframework.js --formatting PRETTY_PRINT
|
||||
(function(a) {
|
||||
a = a.MyFramework = {};
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ function removeNode(node) {
|
|||
|
||||
Восклицательный знак означает, что параметр обязатален.
|
||||
|
||||
Найти описания встроенных типов и объектов javascript вы можете в файле экстернов: <code>externs.zip</code> находится в корне архива <code>compiler.jar</code>, или в соответствующей директории SVN: <a href="http://closure-compiler.googlecode.com/svn/trunk/externs/">http://closure-compiler.googlecode.com/svn/trunk/externs/</a>.
|
||||
Найти описания встроенных типов и объектов javascript вы можете в файле экстернов: <code>externs.zip</code> находится в корне архива <code>compiler.jar</code>.
|
||||
|
||||
## Интеграция с проверками типов из Google Closure Library
|
||||
|
||||
|
|
@ -138,7 +138,9 @@ Google Closure Compiler знает о них и понимает, что вну
|
|||
|
||||
```js
|
||||
var goog = {
|
||||
isFunction: function(f) { return typeof f == 'function' }
|
||||
isFunction: function(f) {
|
||||
return typeof f == 'function'
|
||||
}
|
||||
}
|
||||
|
||||
if (goog.isFunction(func)) {
|
||||
|
|
@ -168,7 +170,7 @@ required: (Object|null|undefined)
|
|||
|
||||
Также можно указывать количество и тип параметров функции, ключевого слова <code>this</code>, объявлять классы, приватные методы и интерфейсы.
|
||||
|
||||
Проверка типов javascript, предоставляемая Google Closure Compiler - пожалуй, самая продвинутая из существующих на сегодняшний день.
|
||||
Проверка типов javascript, предоставляемая Google Closure Compiler -- пожалуй, самая продвинутая из существующих на сегодняшний день.
|
||||
|
||||
C ней аннотации, документирующие типы и параметры, становятся не просто украшением, а реальным средством проверки, уменьшающим количество ошибок на production.
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ Google Closure Library умеет преобразовывать классы CS
|
|||
Например, следующая функция задает такой список.
|
||||
|
||||
```js
|
||||
|
||||
goog.setCssNameMapping({
|
||||
"goog-menu": "a",
|
||||
"goog-menu-disabled": "a-b",
|
||||
|
|
@ -151,8 +150,7 @@ Google Closure Compiler производит соответствующие пр
|
|||
|
||||
```js
|
||||
/** @export */
|
||||
function Widget() {
|
||||
}
|
||||
function Widget() {}
|
||||
/** @export */
|
||||
Widget.prototype.hide = function() {
|
||||
this.elem.style.display = 'none'
|
||||
|
|
@ -162,8 +160,7 @@ Widget.prototype.hide = function() {
|
|||
После компиляции в продвинутом режиме:
|
||||
|
||||
```js
|
||||
function a() {
|
||||
}
|
||||
function a() {}
|
||||
goog.d("Widget", a);
|
||||
a.prototype.a = function() {
|
||||
this.b.style.display = "none"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
```html
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<ul>
|
||||
|
|
@ -17,6 +18,7 @@
|
|||
Сосед
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@
|
|||
alert( "Ошибка: " + e.message );
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
@ -82,7 +81,6 @@
|
|||
|
||||
iframe.onload = null;
|
||||
}
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
Например:
|
||||
```html
|
||||
<!--+ no-beautify -->
|
||||
<iframe src="http://target.com" name="target">
|
||||
|
||||
<script>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue