1150 JavaScript 20 Yrokov
1150 JavaScript 20 Yrokov
Владимир Дронов
ауа с г ір і
/Отакої}ЦаЯ НіїиЦінних
Санкт-Петербург
«БХВ-Петербург»
2021
УДК 004.438JavaScript
ББК 32.973.26-018.1
Д75
Дронов В. А.
Д75 JavaScript: 20 уроков для начинающих. — СПб.: БХВ-Петербург, 2021. —
352 с.: ил. — (Для начинающих)
ISBN 978-5-9775-6589-9
В книге 20 иллюстрированных уроков, 40 практических упражнений на тему
программирования веб-сценариев и более 70 заданий для самостоятельной работы.
Изложены основы JavaScript: данные и операторы, выражения и управляющие кон
струкции, функции, классы, объекты и массивы, средства отладки. Раскрыты меха
низмы управления веб-страницами: события и их обработка, управление элемента
ми, графика и мультимедиа, веб-формы и элементы управления, регулярные
выражения, навигация и управление окнами. Рассмотрена работа с HTML API и
компонентное программирование: асинхронное программирование, работа с внеш
ними данными, программная графика, объявление своих классов, создание компо
нентов. Освещены технологии взаимодействия с сервером: AJAX, PHP, разработка
фронтендов и бэкендов, серверные сообщения.
Электронный архив на сайте издательства содержит коды всех примеров и ре
зультаты выполнения упражнений.
Для начинающих веб-разработчиков
Введение.......................................................................................................................... 11
Почему JavaScript?..........................................................................................................................11
Что вы найдете в этой книге?........................................................................................................12
Что вам понадобится?....................................................................................................................12
Типографские соглашения.............................................................................................................13
Заключение................................................................................................................... 325
Приложение 1. Приоритет операторов.................................................................... 327
Приложение 2. Пакет хостинга ХАМРР................................................................. 329
П2.1. Установка пакета хостинга ХАМРР................................................................................. 329
П2.2. Панель управления ХАМРР. Запуск и остановка веб-сервера......................................334
П2.2.1. Указание языка при первом запуске.................................................................... 334
П2.2.2. Окно панели управления ХАМРР........................................................................ 334
П2.2.3. Запуск веб-сервера................................................................................................. 335
П2.2.4. Проверка работоспособности веб-сервера.......................................................... 335
П2.2.5. Остановка веб-сервера........................................................................................... 336
П2.3. Использование веб-сервера.............................................................................................. 336
П2.3.1. Тестирование веб-сайта с применением ХАМРР...............................................336
П2.3.2. Просмотр журналов работы веб-сервера и РНР..................................................336
П2.4. Решение проблем............................................................................................................... 337
П2.4.1. Увеличение максимального размера выгружаемых файлов..............................337
П2.4.2. Отключение кеширования файлов веб-обозревателем.......................................338
Почему JavaScript?
Прежде всего, он — один из трех «китов», на которых зиждется величественный
дворец веб-разработки. Первый «кит»— язык HTML— описывает саму веб
страницу, ее содержание, второй — CSS — ее оформление, a JavaScript — пове
дение.
JavaScript может «оживить» страницу, заставляя ее реагировать на действия поль
зователя. Он может превратить набор обычных картинок в красивую фотогалерею.
Он может загрузить с сервера какие-либо данные и вывести их прямо на странице
в виде абзаца, списка, таблицы или графика. Он даже может превратить страницу
в настоящую программу, обрабатывающую занесенные пользователем данные и
выводящую результаты их обработки.
JavaScript — единственный язык программирования, позволяющий «влезть» внутрь
веб-страницы, исправить или дополнить ее содержание. JavaScript— единствен
ный язык программирования, непосредственно поддерживаемый веб-обозревате
лями.
Ранее говорилось, что у этого языка в своей области нет конкурентов. И в ближай
шем будущем они не появятся.
12 Введение
Типографские соглашения
В книге будут часто приводиться различные языковые конструкции, применяемые
в JavaScript. Для наглядности при их написании использованы следующие типо
графские соглашения (в реальном коде они недействительны):
♦ HTML-, CSS-, JavaScript- и PHP-код набран моноширинным шрифтом:
<script type="text/javascript">
const ins = window.prompt(’Величина в дюймах', 0);
const cents = ins * 2.54;
</script>
Здесь вместо подстроки возвращ аемое зн ачен ие ДОЛЖНО быть ПОДСТаВЛеНО реаль
ное возвращаемое значение;
♦ в квадратные скобки [] заключаются необязательные фрагменты кода. Напри
мер:
toString([<основание>])
Приведенный код здесь разбит на две строки, но должен быть набран в одну.
Символ Ъ при этом нужно удалить;
♦ троеточием . . . помечены фрагменты кода, пропущенные ради сокращения
объема текста книги:
14 Введение
function circleLength(d) {
d = d N 2;
}
Здесь весь код между второй и последней строками пропущен.
Обычно такое можно встретить в исправленных впоследствии фрагментах
ко д а— приведены лишь собственно исправленные строки, а оставшиеся неиз
мененными пропущены. Также троеточие используется, чтобы показать, в какое
место должен быть вставлен вновь написанный код: в начало исходного фраг
мента, в его конец или в середину, между уже присутствующими в нем стро
ками.
В ним ание!
Все приведенные здесь типографские соглашения имеют смысл только в примерах
написания языковых конструкций JavaScript.
ЧАСТЬ I
Начала JavaScript
1.1. Упражнение.
Используем консоль веб-обозревателя
Изучение основ языка JavaScript удобно начать, набирая код в консоли.
Консоль — интерактивная исполняющая среда, встроенная в веб-обозре
ватель. В консоли можно набрать какое-либо выражение и сразу увидеть
результат его выполнения.
Вызовем консоль у установленного у нас веб-обозревдтеля и выполним в ней не
сколько выражений.
1. Запустим веб-обозреватель (автор книги использовал Google Chrome).
2. Нажмем клавишу <F12>, чтобы вызвать встроенные в веб-обозреватель отла
дочные инструменты, в число которых входит и консоль. По умолчанию панель
с отладочными инструментами появляется у нижней стороны окна веб-обо
зревателя (рис. 1.1).
3. В верхней части панели находятся корешки вкладок, на которых располагаются
различные отладочные инструменты. Переключимся на вкладку Console, щелк
нув на ней мышью (рис. 1.2).
На этой вкладке и находится консоль веб-обозревателя (рис. 1.3).
В белой области редактирования, занимающей большую часть вкладки, виден
мигающий текстовый курсор. Здесь вводятся выражения JavaScript, которые
нужно выполнить.
18 Часть I. Начала JavaScript
• Для начала сложим два числа, для чего наберем в области редактирования
следующий простой код:
27 + 14
Git fi] Elements Console Sources Network Performance Memory Application Security Audits : | X
► 1 message SU r e g is te r e d neartab?ie=UTF-8:8
>
► 0 1 user mess,,,
О No errors
Д No warnings
► 0 1 info
$ No verbose
SW r e g i s t e r e d
>27+14
41
>t
У отрицательных чисел в начале ставится знак «минус»: -. Для записи чисел в экс
поненциальной форме: <мантисса> х — применяется формат:
<мантисса>е<порядок>
,
Урок 1. Типы данных операторы и переменные ________________ 21
Примеры:
Отрицательные числа: Числа в экспоненциальной форме:
-10, -20, - 0 . 3 2 , - 0 . 0 5 3 1е6 (1000000), 1 . З е -5 (0,000013), -1 е З (-1000)
Помимо десятичных, можно записывать восьмеричные и шестнадцатеричные чис
ла, предварив их, соответственно, нулем или символами 0х.
Примеры:
Восьмеричные числа: Шестнадцатеричные числа:
010 (8), 0123 (83), -045 (-37) 0x10 (16), 0x53 (83), -0x321 (-801)
Для выполнения арифметических действий применяются арифметические опера-
торы.
Бинарные (принимающие два операнда) операторы записываются в формате:
<опвранд 1> <оператор> <операнд 2>
П ояснение
Операторы бывают унарные (принимающие один операнд), бинарные (принимающие
два операнда) и тернарны е (принимающие три операнда). Обо всех их подробно рас
сказывается по мере их упоминания.
<= Меньше или равно > 100 <= 1000 < true
! == Строго не равно
1 Два знака «равно». Один знак «равно» — это совсем другой оператор, который будет рассмотрен
позже.
24 Часть I. Начала JavaScript
Примеры:
> 10 <= 100 && 0 != 1 > 10 <= 100 11 0 != 1
< true < true
h-»
&&
II
о
1.7. Переменные
Переменная — ячейка памяти, предназначенная для временного хранения
какого-либо значения. Должна иметь уникальное имя, по которому выпол
няется обращение к этой переменной.
Примеры:
Правильные имена: Неправильные имена:
a, b, someValue, ^ p r i v a t e число, some value , 234value
Урок 1. Типы данных, операторы и переменные __________ 25
Прим ечание
В дальнейшем результат u n d efin ed , возвращаемый оператором l e t , ради компактно
сти указываться не будет.
1 Оператор присваивания обозначается одним знаком «равно» (=), а оператор сравнения «равно» —
двумя (==). Не путайте эти два оператора!
26 Часть I. Начала JavaScript
В ним ание!
При присваивании переменной нового значения старое значение теряется.
а += Ь а = а + Ь
а -= b а = а - b
а *= b а = а * b
а /= b а = а / Ь
а %= Ь а = а % b
Однако все же лучше объявлять переменные явно. Во-первых, это хороший стиль
программирования, а во-вторых, при работе в строгом режиме (о котором будет
рассказано в уроке 2) веб-обозреватель будет требовать явного объявления пере
менных.
28 Часть I. Начала JavaScript
В ним ание!
При обращении к необъявленной переменной в консоли возвращается значение
undefined. Но если это сделать в веб-сценарии (написанием которых мы займемся на
уроке 2), возникнет ошибка, и выполнение сценария будет прервано.
♦ ' function ' — функциональный тип (будет рассмотрен в уроке 3);
♦ ' ob ject ' — объектный тип (будет рассмотрен в уроке 4).
• о преобразуется в false;
• Infinity И -Infinity — В true;
• NaN — В false;
• undefined — В false.
Операторы сравнения (см .разд. 1.5) при сравнивании значений разных типов пред
варительно преобразуют их к одному типу:
> 2 == 2
< true
> 2 !== 2
< false
> +'123.456'
< 123.456
> parseFloat(1123.456')
< 123.456
> parseFloat('123.456abcdef')
< 123.456
2. Откроем копию файла 2.1.html в текстовом редакторе и вставим сразу после тега
<ы> пустой тег <script> (здесь и далее в тексте книги подобные вставки выде
ляются полужирным шрифтом), в который совсем скоро поместим код сце
нария:
<Ь1>Пересчет величин</Ь1>
<script type="text/javascript">
</script>
3. Сначала нам нужно вывести на экран стандартное диалоговое окно с полем вво
да, в которое пользователь будет заносить требуемую величину в дюймах.
Для этого вставим в тег <script> первое выражение сценария, которое выведет
на экран такое окно и присвоит введенную пользователем величину константе
ins:
<script type="text/javascript">
const ins = window.prompt('Величина в дюймах1, 0);
</script>
2.2. Упражнение.
Применяем условные выражения
У сценария, написанного в разд. 2.1, есть недостаток— если в диалоговом окне
ввода величины нажать кнопку Отмена, на страницу будет выведено число 0. Дело
в том, что по нажатию кнопки Отмена языковая конструкция window.prompt вернет
значение null. Следующее выражение нашего сценария умножит это значение
на 2,54, в результате чего и получится 0.
Давайте сделаем так, чтобы вместо нуля выводился осмысленный текст — напри
мер: «Величина не была введена».
Значит, в сценарии нам перед умножением на 2,54 следует проверить, вернула ли
конструкция window.prompt значение null, и, если это так, вывести текст сооб
щения. В противном случае мы, как и ранее, вычислим на основе введенного числа
«сантиметровую» величину. Выполнить такую проверку нам поможет условное
выражение.
Условное выражение включает в себя условие (аналогичное тому, что при
меняется в условном операторе из разд. 1.9) и два выражения. Если условие
истинно, выполняется первое выражение, если ложно — второе.
Условное выражение записывается в формате:
if (< усл ови е> )
<выражение tru e>
else
<выражение f a ls e >
Условное выражение (на рис. 2.3 оно выделено рамкой) проверяет, равно ли значе
ние константы ins (в которой сохраняется занесенная пользователем «дюймовая»
величина) значению null. Если это так, в переменную cents заносится текст сооб
щения, в противном случае — вычисленная величина в сантиметрах.
Поскольку переменной cents значение присваивается не в момент объявления, мы
объявили ее как обычную переменную — оператором let.
Урок 2. Выражения и управляющие конструкции 39
Здесь:
♦ установка — выражение, присваивающее счетчику начальное значение;
♦ у с л о в и е — пока возвращает в качестве результата true, цикл выполняется, но как
только вернет false, исполнение цикла завершается. Практически всегда усл о ви е
проверяет, не превышает ли текущее значение счетчика величину необходимого
количества проходов цикла;
♦ приращение — выражение, изменяющее значение счетчика;
♦ тело ц и к л а —
единичное выражение или блок, который и будет выполняться
заданное количество раз. Собственно, т ело — это код, для которого пишется
цикл.
* * *
1. В папке 2\!sources сопровождающего книгу электронного архива (ш.. приложе
ние 3) найдем файл 2.5.html и скопируем его в какую-либо папку на локальном
диске.
Этот файл хранит веб-страницу, содержащую заголовок первого уровня с тек
стом «Пересчет величин» и парный тег <tabie>, создающий «пустую» таблицу.
2. Откроем копию файла 2.5.html в текстовом редакторе и вставим между тегами
<tabie> и </tabie> код, объявляющий переменную-счетчик i и создающий сам
цикл со счетчиком:
<script type="text/javascript">
let i;
for (i = 1; i <= 10; ++i) {
}
</script>
В нашем цикле:
• установка (i = l) — присваивает счетчику значение l (первое число, квадрат
ный корень которого надо вычислить);
• ус л о в и е (i <= ю ) — проверяет, не превышает ли значение счетчика ю (коли
чество проходов цикла и одновременно последнее число, чей квадратный ко
рень нужно вычислить);
• приращение (++i) — инкрементирует (увеличивает на 1) значение счетчика.
3. Напишем тело цикла — выражения, вычисляющие квадратные корни (выделены
полужирным шрифтом):
for (i = 1; i <= 10; ++i) {
window.document.write ('< t r X t d > ', i, '</td>');
window.document.write('<td>' , Math.sqrt(i) , '</tdX/tr>') ;
}
На каждом проходе цикла мы создаем строку таблицы с двумя ячейками: в ле
вой выводится изначальное число, а в правой— квадратный корень из него.
Для вычисления квадратного корня от числа мы применили конструкцию
Math, sqrt (<число>) , упомянутую Вразд. 1.12.
Урок 2. Выражения и управляющие конструкции 45
}
Оно может увеличивать его на 2, что может понадобиться для вывода квадрат
ных корней от четных чисел:
for (і = 2; і <= 10; і += 2) { . . . }
♦ И установка , и условие , и приращение не являются обязательными для указания:
• можно опустить уст ановку — тогда начальное значение счетчику следует
присвоить перед исполнением цикла:
let і = 1;
for (; і <= 10; ++і) {
}
• можно опустить у с л о в и е — но тогда придется производить необходимую
проверку в начале тела цикла и прерывать выполнение цикла оператором
break, знакомым нам по разд. 2.4 :
for (i = 1; ; ++i) {
if (i > 10)
break;
}
46 Часть I. Начала JavaScript
i++;
}
В последних двух случаях цикл со счетчиком становится похожим на циклы двух
других разновидностей, которые мы скоро рассмотрим.
Пример:
let i = 1;
while (i <= 10) {
window.document.write('<tr><td>’, i, '</td>');
window.document.write(’<td>', Math, sqrt (i) , ’</tdx/tr> ’);
i++;
}
Урок 2. Выражения и управляющие конструкции 47
Пример:
let i = 1;
do {
window.document.write(1<tr><td>f, i, '</td>1);
window, document .write ('<td>', Math, sqrt (i), '</tdx/tr>') ;
i++;
} while (i <= 10)
2.8. Комментарии
Комментарий — фрагмент программного кода, не обрабатываемый веб
обозревателем. Служит для размещения в коде всевозможных заметок, по
яснений, напоминаний и др.
JavaScript поддерживает два вида комментариев:
♦ однострочный — начинается с последовательности символов / / (два слеша):
// Проверяем, хранит ли переменная sq целое число
if (sq == Math.floor(sq))
}
doSomething();
54 Часть I. Начала JavaScript
}
Если существуют и глобальная, и локальная переменные с одинаковыми
именами, попытка обратиться по этому имени в теле функции вызовет об
ращение к локальной переменной.
Так, если мы обратимся по имени somevar к переменной, объявленной в теле функ
ции someFunc, ТО ПОЛуЧИМ Значение ЛОКаЛЬНОЙ переменной someVar:
let someVar = 123;
function someFunc( . . . ) {
let someVar = 321;
}
Вложенная функция — функция, объявленная в теле другой функции. Дос
тупна только в теле функции, в которой объявлена. Имеет доступ к локаль
ным переменным, объявленным во «внешней» функции.
Урок 3. Функции и массивы ___________________________________________ 55
Пример:
// Объявление "внешней" функции
function outerFunc(a, b, с) {
let у = 0;
// Объявление вложенной функции
function innerFunc(d, е) {
}
56 Часть I. Начала JavaScript
3.4. Функции
с произвольным количеством параметров
JavaScript позволяет достаточно просто объявить функцию, принимающую произ
вольное количество параметров. Для этого нужно:
♦ объявить функцию, не принимающую параметров;
♦ в теле функции получить количество принятых параметров, обратившись к язы
ковой конструкции arguments.length;
♦ получить значения принятых параметров посредством языковой конструкции:
arguments [<порядковый номер параметра>].
Только нужно иметь в виду, что нумерация параметров начинается с о, а не с 1.
Урок 3. Функции и массивы 57
• HTML
• CSS
• JavaScript
Рис. 3.2. Маркированный список на основе вызова функции
с произвольным количеством параметров
let 1 = func(10);
}
и вызываем, передав ей функцию из переменной anonFunc в качестве параметра:
let resuit = computeSomeValue(anonFunc);
Пример:
const anonFunc2 = (d) => {
let 1;
1 = d * Math.PI;
return 1;
}
♦ сокращенном:
([< список параметров ч е р е з запятую> ]) => <единичное выражение>
3.8. Упражнение.
Создаем внешний веб-сценарий
В разд. 3.1 мы написали удачную функцию circleLength и теперь хотим использо
вать ее при разработке других сайтов, для чего вынесем объявление этой функции
во внешний веб-сценарий.
}
выделим его и вырежем в буфер обмена.
2. Создадим в текстовом редакторе новый файл и вставим в него фрагмент из бу
фера обмена.
3. Сохраним этот файл в той же папке, где находится файл страницы 3.1.html, на
значив ему имя 3.8.js и задав кодировку UTF-8.
Урок 3. Функции и массивы 61
♦ isNaN (<число>) — возвращает true, еСЛИ В качестве числа передано значение NaN,
и false в противном случае;
♦ eval {<строка с вьражением>) — ВЫЧИСЛЯет выражение, переданное В ВИДе строки,
и возвращает результат:
> eval('(10 +20) /2')
< 15
Создать массив можно, указав все входящие в него элементы через запятую и взяв
их в квадратные скобки. Созданный массив присваивается какой-либо переменной:
♦ создаем массив lengths и помещаем в него числа 2, 5, 10 и 20:
> let lengths
> lengths = [2, 5, 10, 20]
< (4) [2, 5, 10, 20]
Можно как получать текущее значение из элемента массива, так и заносить в него
новое значение:
♦ извлекаем второй (с индексом 1 — не забываем, что нумерация элементов начи
нается с о) элемент массива lengths:
> lengths[1]
<5
♦ меняем значение третьего (индекс 2) элемента того же массива на 15:
> lengths[2] = 15
> lengths
< (4) [2, 5, 15, 20]
Пользуясь им, мы можем как получать текущее значение свойства, так и присваи
вать ему новое значение.
Точка, разделяющая переменную с объектом и имя свойст ва , — это оператор
( доступа к элементу объекта.
Например, свойство length объекта строки хранит ее длину, выраженную в сим
волах:
66 Часть I. Начала JavaScript
> str.length
< 10
4.2. Классы
Класс — образец для создания объектов определенного вида. Он задает на
бор свойств и методов, которые будут поддерживаться всеми объектами,
относящимися к этому виду.
Класс должен иметь уникальное имя, которое обязано удовлетворять тем же требо
ваниям, что и имя переменной (см.разд. 1.7).
Список базовых классов, встроенных в JavaScript и реализующих значения различ
ных видов, приведен в табл. 4.1.
Урок 4. Классы и объекты 67
Примеры:
> Number.MIN_VALUE
< 5е-324
> Number.MAX_VALUE
< 1.7976931348623157e+308
Урок 4. Классы и объекты 69
♦ fromCharCode {<код 1>, <код 2> . . . <код п>) — статический, ВОЗВращаеТ Стро
ку, составленную из символов с заданными Unicode-кодами:
> String.fromCharCode(0x42f, 0x437, 0x44b, 0x43a, 0x20,
0x43, 0x53, 0x53)
< "Язык CSS"
♦ push (<значение 1>, <значение 2> . . . <значение ri>) — добавляет В конец мас
сива указанные значения и возвращает новый размер массива:
> let arr2 = [10, 11]
> arr2.push(12, 13)
< 4
> arr2
< (4) [10, 11, 12, 13]
♦ every {<функция проверки>[, <значение t h i s > ] ) — возвращает true, если все эле
менты текущего массива проходят проверку. Если хоть один элемент массива не
проходит проверку, возвращается false.
Проверку осуществляет указанная функция, принимающая три параметра: оче
редной элемент массива, индекс этого элемента и сам массив (два последних
параметра необязательны). Функция должна возвращать логическое значение:
true (если элемент прошел проверку) или false (в противном случае):
> // Проверяем, все ли элементы массива arrl больше О
> arrl.every((el, ind, ar) => el > 0)
< true
> // Проверяем, все ли элементы массива arrl больше 2
> arrl.every((el) => el > 2)
< false
♦ concat {<массив i> , <массив 2> . . . <массив n > ) — создает новый массив, со
держащий все элементы ИЗ текущего И всех переданных ему м ассивов , и возвра
щает его в качестве результата:
> arrl.concat([5, 6], [10, 11, 12])
< (9) [1, 2, 3, 4, 5, 6, 10, 11, 12]
Если нужно отсортировать массив в другом порядке, в вызове метода sort следует
задать функцию сравнения. Она должна принимать два параметра: два сравниваемых
элемента массива — и возвращать:
♦ любое отрицательное число — если первый элемент меньше второго;
♦ 0 — если элементы равны;
♦ любое положительное число — если первый элемент больше второго.
Вот пример сортировки массива с числами по убыванию:
> arr.sort((ell, е12) => е12 - ell)
< (7) [900, 90, 64, 32, 15, 7, -4]
Но В функции сравнения ДЛЯ ЭТОЙ Цели удобнее Применять МеТОД localeCompare КЛДС-
са string. Вот формат его вызова:
localeCompare(Сравниваемая строка>)
Метод возвращает:
♦ -1 — еСЛИ Текущая Строка «Меньше» сравниваемой;
♦ о — если обе строки равны;
♦ 1 — если текущая строка «больше» сравниваемой.
Вот пример сортировки массива со строками в порядке, обратном алфавитному:
> arr2.sort((ell, е12) => е12.localeCompare(ell))
< (6) ["Ruby", "Python", "PHP", "HTML", "CSS", "C++"]
Метод reverse класса Array меняет порядок следования элементов массива на про
тивоположный. Метод не принимает параметров и возвращает ссылку на текущий
массив:
78 Часть I. Начала JavaScript
> arr2.reverse()
< (6) г C++", "CSS", "HTML", "PHP", "Python", "Ruby"]
Параметры объекта, если они указаны, будут занесены в его свойства непосредст
венно при создании.
Выражение, создающее объект временной отметки, можно записать в трех фор
матах:
♦ new Date () — созданная временная отметка будет хранить текущие дату и время:
> let datel = new Date ();
♦ new Date {<год>, <номер месяца, начиная с 0>, <число>[, <часы>, <минуты>,
<секунды>[, <миллисекунды>] ] ) — временная отметка будет хранить указанные
дату и время:
> // 1 января 2019 года, 11:45:09.400
> let date2 = new Date(2019, 0, 1, 11, 45, 9, 400);
Если также не указать часы, минуты и секунды, временная отметка будет хранить
полночь указанной даты:
> //28 февраля 2019 года, полночь
> let date4 = new Date(2019, 1, 28);
Методы класса Date, предназначенные для получения или изменения одной из со
ставляющих временной отметки: года, месяца, часов и др. приведены в табл. 4.2.
Число g e t D a t e () s e t D a t e (<число>)
Часы g e tH o u r s () s e tH o u r s (<часы>)
Минуты g e tM in u te s () s e tM in u te s (<минуты>)
Секунды g e tS e c o n d s () s e t S e c o n d s (<секунды>)
Миллисекунды g e t M i ll i s e c o n d s () s e t M i l l i s e c o n d s (<мсек>)
Примеры:
> // Какой сейчас год?
> datel.getFullYear()
< 2019
> // А месяц?
> с!а1е1. getMonth ()
<2 // Третий по счету месяц — март
> // Меняем месяц на июль, а число — на 24-е
> date2.setMonth(6)
> clate2.setDate (24)
> datel.toLocaleTimeString()
< "11:14:45"
П ояснение
Пересчитать угол из градусов в радианы можно по формуле: аф * тт /1 8 0 .
Вот пример вычисления синуса угла 45°:
> l e t a n g le = 45 * M ath.PI / 180
> a n g le
< 0.7853981633974483
> M a th .s in (a n g le )
< 0.7071067811865475
П ояснение
Пересчитать угол из радианов в градусы можно по формуле: арад х 180 / тт.
Вот пример вычисления арктангенса от числа 1 и получения результата в градусах:
> l e t a t = M a th .a ta n (l)
> a t * 180 / M ath.PI
< 45
}
Как видим, объект этого класса чем-то похож на обычный массив.
Коллекция — объект, имеющий функциональность массива.
Все классы коллекций поддерживают оператор [ ] и свойство length.
{
<имя свойства 1> : <значение свойства 1>,
<имя свойства 2 > : <значение свойства 2>,
Пример:
♦ создаем служебный объект, хранящий сведения о каком-либо человеке:
let person = {
namel: 'Иван',
name2: 'Иванов
аде: 48
};
О ►UncaygHt R é fé ré псе E r r o r ; c i r c I e L e n g t i s n o t d e f i n e d
a t 3 . 1 . h t » I : 1 3 ______________________________________________________________
Более подробно класс window, его свойства и методы мы рассмотрим в уроке 11.
5.2. Упражнение.
Работаем с отладчиком веб-обозревателя
Возьмем страницу 3.1 .html, написанную в разд. 3.8, выполним код содержащегося
в ней сценария пошагово — выражение за выражением, и посмотрим, что при этом
происходит. Для этого нам понадобится отладчик веб-обозревателя.
Отладчик — позволяет приостанавливать исполнение сценария в указан
ных точках останова, трассировать его и просматривать значения, храня
щиеся в переменных.
Отладчик, как и знакомая нам консоль, входит в состав отладочных инструментов
веб-обозревателя.
Точка останова — выражение, на котором отладчику следует приостано
вить выполнение сценария и ждать указаний программиста (обычно на вы
полнение трассировки).
Трассировка — пошаговое, выражение за выражением, исполнение кода
сценария.
1. В папке 5\!sources сопровождающего книгу электронного архива (см. приложе
ние 3) найдем страницу 3.1.html и файл сценария 3.8.js, после чего откроем стра
ницу в веб-обозревателе.
2. Находясь в веб-обозревателе, нажмем клавишу <F12>, чтобы вывести панель
с отладочными инструментами.
3. Переключимся на вкладку Sources, где и располагается отладчик (рис. 5.2).
<script type="text/javascript">
^window, document,^write( 4tr><td>2</td>‘);
window,document-write("<td>*, circlelength(
Рис. 5.6. На первом выражении сценария поставлена точка останова
▼ Breakpoints
в 3.1.html: 12
window. doc ument. w rit«
и! <script type="text/javascriptа>______
Кнопка Кнопка
Resume script execution Step into next function call
Л if 1 rA
Кнопка \ Кнопка
Step over next function call Step out of current function
1 fu n c tio n c ir c le L e n g th ( d ) {
2 1 l e t 1; '___________ _
3 1 = d * M a th .P I;
4 re tu rn 1 ;
5
10. Выполним шаг с заходом еще два раза, чтобы выделение переместилось на по
следнее выражение тела функции: return 1;.
Веб-обозреватель покажет нам текущие значения параметра d и локальной
переменной, объявленной в этой функции. Так мы сразу поймем, правильно ли
выполняются вычисления (рис. 5.12).
94 Часть I. Начала JavaScript
1 fu n c tio n c ir c le L e n g th ( d ) { û - 2
2 le t 1; 1 = 6 .2 8 3 1 8 5 3 8 7 1 7 9 5 8 6
з] 1 = d * M a th .P I ; d =
4 re tu rn 1;
5 }
6
<idoctype ntml> ж
< h tm l>
► <head>~</head>
▼ < bo dy>
<Л1>Длина о к р у ж н о е т и < /h i >
▼ < ta b le > == $0
► <script type=,ftext/javascriptrt>_</script>
▼ < tb o d y >
▼ <tr>
<td>2</td>
< td > 6 .2 8 3 1 8 5 3 0 7 1 7 9 5 8 6 < /td >
</tr>
► <tr>«</tr>
► <tr>-</tr>
< /tb o d y >
< / t a b le > T
h tm l body ta b le s c rip t
Для создания объекта исключения следует использовать оператор new (см.разд. 4.6).
Объект создается на основе наиболее подходящего класса из упомянутых ранее.
Сгенерированное исключение может быть обработано посредством обычного обра
ботчика.
Вот вариант функции circieLength, проверяющей, является ли переданный ей
параметр числом, и, если это не так, генерирующей исключение класса TypeError:
function circieLength(d) {
let 1;
if (typeof d != 'number’) {
const ex = new TypeError();
ex.message = 'Допустимы только числа';
throw ex;
}
1 = d * Math.PI;
return 1;
}
Генерируемое этой функцией исключение мы можем обработать следующим обра
зом:
window.document.write('<tr><td>yte</td>');
window.document.write('<td>');
try {
// Пытаемся вызвать функцию circieLength, передав ей строку 'yte',
/ / и вывести возвращенный ей результат на экран
window.document.write(circieLength('yte'));
}
catch(ex) {
// Если функция сгенерировала исключение, выводим сообщение об ошибке
window.document.write(ex.message);
}
finally {
/ / В любом случае выводим закрывающие теги
window, document .write ('</tdx/tr>' );
}
Генерирование исключений часто применяется при проверке, правильные ли пара
метры были переданы функции, присутствует ли на странице нужный элемент
и т. п.
О События.
Э DOM и ВОМ.
3 Графика и мультимедиа.
О Веб-формы и элементы управления.
О Регулярные выражения.
Урок 6
События и их обработка
События. Обработчики событий
Понятие DOM
Получение сведений о событии
Фазы события
Обработчик по умолчанию и его отмена
</html>
Урок 6. События и их обработка 105
<script type="text/javascriptM>
</script>
Теперь нам нужно получить объекты DOM, представляющие тег <img>, в кото
ром будут выводиться изображения, и блоки-«кнопки». Поскольку у тега <img>
указан якорь output, мы можем найти соответствующий объект по этому якорю.
4. Вставим в тег <script> первое выражение сценария, которое присвоит константе
output объект, представляющий элемент output:
const output = window.document.getElementByld(foutput');
Прим ечание
Подробно объекты и классы DOM, их свойства и методы мы рассмотрим в уроке 7.
указывается
Имя события В виде строки, а обработчик — в виде ссылки на
нужную функцию.
});
el.addEventListener(1click', () => {
}) ;
♦ В функциях-стрелках переменная this, хранящая элемент, к которому привязан
обработчик, не создается, и обращение к ней вызовет ошибку:
el.addEventListener('click*, () => {
current = this; // Ошибка!
});
♦ К одному и тому же событию одного и того же элемента можно привязать
сколько угодно обработчиков. Они будут выполнены в том порядке, в котором
привязаны:
el.addEventListener('click’, listenerl);
el.addEventListener('click', listener2);
el.addEventListener('click *, listener3);
108 Часть II. Управление веб-страницей и веб-обозревателем
Пример:
el.removeEventListener(’click*, listener2);
<script type="text/javascript">
function showlmage() {
}
</script>
6.2. События,
поддерживаемые элементами страницы
Элементы страницы поддерживают весьма много событий. В табл. 6.1 приведены
только основные.
События мыши
c lic k Щелчок мышью
d b lc lic k Двойной щелчок мышью
contextm enu Щелчок правой кнопкой мыши перед выводом контекстного меню
mousedown Нажатие кнопки мыши
mouseup Отпускание кнопки мыши
m ouseenter
Наведение курсора мыши на элемент страницы*
mouseover
События клавиатуры
Возникают только в элементах, способных принимать клавиатурный ввод (в гиперссылках
и элементах управления), а также в секции тела страницы (теге < з ^ у > )
События CSS-анимации
t r a n s itio n e n d Конец воспроизведения анимации с двумя состояниями (создаваемой
атрибутами стиля семейства t r a n s i t i o n )
110 Часть II. Управление веб-страницей и веб-обозревателем
* Эти два события возникают при одинаковых условиях, но отличаются по количеству фаз их «прохож
дения» (подробно о фазах событий рассказано в разд. 6.4).
</body>
Урок 6. События и их обработка 111
6.3. Упражнение.
Получаем сведения о событии
Сделаем так, чтобы при наведении курсора мыши на одну из «кнопок» слайдера,
рассмотренного в разд. 6.1, на экране рядом с курсором появлялась миниатюра со
ответствующего изображения.
Реализовать ЭТО М О Ж Н О В обработчиках событий mouseover И mouseout: первый обра
ботчик выведет миниатюру на экран, второй скроет ее. А получить координаты
курсора мыши можно из объекта события, который передается любой функции-
обработчику с единственным параметром (об этом говорилось в разд. 6.1).
1. Итак, продолжим работу над текстом страницы 6.1 .html и добавим после панели
навигации (<nav>) HTML-код, создающий блок, в котором будет выводиться
миниатюра:
<nav>
</nav>
<div ic^"preview"X/div>
Чтобы позже получить объект, представляющий этот блок, пометим его якорем
preview.
2. Добавим во внутреннюю таблицу стилей слайдера стили, задающие оформление
для этого блока:
#preview {
position: absolute;
width: 120px;
height: 80px;
background: left/contain no-repeat;
display: none;
}
#preview.active {
display: block;
}
Миниатюру в этом блоке мы будем выводить в виде графического фона — так
проще.
3. В начало кода сценария добавим выражение, которое получит объект, представ
ляющий блок preview:
const preview = window.document.getElementByld('preview');
fun c t i o n s h o w i m a g e () {
cur r e n t = this;
output, src = getlmageURL (this .id) ;
}
6. Объявим функцию s h o w P r e v i e w — обработчик события m o u s e o v e r «кнопок», ко
торая выведет на экран блок p r e v i e w с миниатюрой графического изображения,
соответствующего «кнопке», на которую был наведен курсор мыши:
f u n c t i o n showPreview(evt) {
preview.style.left = evt.pageX + 'px';
preview.style.top = evt.pageY + 'px';
preview.style.backgroundlmage = 'url(' +
g e t l m a g e U RL(this.id) + ')';
preview.className = 'active*;
}
Параметр evt будет хранить объект класса MouseEvent, представляющий событие
(более обстоятельный разговор О нем пойдет чуть позже). Свойства р а деХ и
p a g e Y этого класса хранят горизонтальную и вертикальную координаты курсора
мыши относительно левого верхнего угла страницы в пикселах. Добавив к этим
величинам обозначение единицы измерения — рх (пикселы в языке CSS), — мы
получим готовые координаты блока preview. Далее мы выводим соответствую
щее «кнопке» изображение в качестве графического фона этого блока, после
чего привязываем к нему стилевой класс active, чтобы вывести его на экран.
7. Объявим функцию h i d e P r e v i e w ---обработчик события m o u s e o u t «КНОПОК», КОТО
рая скроет блок preview:
fu n c t i o n h i d e P r e v i e w () {
preview.className =
}
8. Наконец, дополним код, привязывающий обработчики к событиям, двумя выра
жениями, которые выполнят привязку написанных ранее обработчиков событий
m o u s e o v e r И mouseout:
b u t t o n s .f o r E a c h (
(el) => {
e l .a d d E v e n t L i s t e n e r ('c l i c k ', s h o w i m a g e );
el.addEventListener ('mouseover ', showPreview) ;
el .addEventLis tener ('mouseout ', hidePreview) ;
}
);
Откроем страницу 6.1.html в веб-обозревателе, наведем курсор мыши на кнопку 3
и полюбуемся миниатюрой, появившейся под курсором мыши (рис. 6.3).
Урок 6. События и их обработка 113
Рис. 6.3. При наведении курсора мыши на кнопку 3 появилась миниатюра рисунка
Класс Event
Представляет все события, кроме приведенных далее. Также является базовым
для всех остальных классов событий
Класс MouseEvent
Производный от класса Event. Представляет все события мыши, кроме w heel
Класс WheelEvent
Производный ОТ класса Event. Представляет событие wheel
Класс KeyboardEvent
Производный от класса Event. Представляет события клавиатуры
shiftKey true, если в текущий момент нажата клавиша <Shift>, и false в противном
случае
altKey true, если в текущий момент нажата клавиша <Alt>, и false в противном
случае
K/iaCC ClipboardEvent
Производный от класса Event. Представляет события буфера обмена
Класс TransitionEvent
Производный ОТ класса Event. Представляет событие transitionend
Класс AnimationEvent
Производный ОТ класса Event. Представляет события animationstart, animationiteration
И animationend
Класс PageTransitionEvent
Производный ОТ класса Event. Представляет события pageshow И pagehide
persisted true — если страница была сохранена в кэше, и false в противном случае
Класс HashChangaEvent
Производный ОТ класса Event. Представляет событие hashchange
* Свойства currentTarget и target хранят одинаковые значения только на фазе источника (подробно
о фазах событий рассказано в разд. 6.4).
** Таблицу Unicode-кодов символов можно найти на странице:
https://www.w3schools.com/charsets/ref_html_ytf8.asp.
*** Коды клавиш клавиатуры приведены на странице: http://umi-cms.spb.su/ref/javascript/251/.
116 Часть II. Управление веб-страницей и веб-обозревателем
2 <body> Погружения
3 <nav>
4 <div> Источника
5 <nav>
6 <body> Всплытия
7 <html>
Если третьим параметром передать значение false или вообще не указывать его,
обработка будет выполнена на фазе всплытия. Если же передать значение true,
обработчик сработает на фазе погружения.
Фазы погружения и источника проходят все события.
Фазу всплытия проходят лишь всплывающие события:
♦ за исключением mouseenter И mouseleave;
МЫШИ,
♦ клавиатуры;
Урок 6. События и их обработка 117
♦ буфера обмена;
♦ анимации.
Остальные события — невсплывающие — не проходят фазу всплытия.
Метод removeEventListener также поддерживает расширенный формат вызова —
с указанием фазы:
removeEventListener{<имя события>, <обработчик>^>
[, <фаза, на которой выполняется обработка>])
</nav>
});
)
}
Нам нужно выводить картинку только в том случае, когда пользователь щелкнул
на «кнопке». Проверить факт щелчка именно на «кнопке» просто: нужно лишь
сравнить значения свойства target объекта-события (оно, как мы помним, со
держит источник события) и переменной this (элемент, к которому привязан
обработчик) — это должны быть разные объекты (если же они равны, то пользо
ватель щелкнул на самой панели навигации, и мы ничего не делаем).
И не забываем, что раз обработчик привязан не к «кнопке», для получения дос
тупа к «кнопке» нужно использовать свойство target объекта-события, а не
переменную this.
4. Исправим КОД ф у н к ц и й showPreview И hidePreview:
function showPreview(evt) {
if (evt.target != this) {
preview.style.backgroundlmage = 'url(' +
getlmageURL(evt.target.id) + 1)';
118 Часть II. Управление веб-страницей и веб-обозревателем
preview.className = 'active*;
}
}
function hidePreview(evt) {
if (evt.target != this)
preview.className = '';
}
Проверим переделанную страницу в действии и убедимся, что все работает.
Обработка событий на фазе погружения применяется относительно редко.
Обычно в таких обработчиках реализуются всевозможные предварительные
проверки и, если таковые не выполняются, дальнейшее «прохождение»
события прерывается.
♦ bubbles — возвращает true, если событие всплывающее, и false — если оно не
всплывающее.
Не принимающий параметров метод stopPropagation прерывает дальнейшее «про
хождение» события:
function listener(evt) {
evt.stopPropagation();
}
6.5. Упражнение.
Отменяем обработку событий по умолчанию
Блок (тег <div>)— не лучший выбор для создания «кнопок» слайдера. Удобнее
делать их на основе гиперссылок: тег <а> поддерживает атрибут href, в котором
можно записать полную ссылку на нужный файл. Давайте заменим в нашем слай
дере блоки на гиперссылки.
1. Снова обратимся к коду страницы 6.1 .html и исправим теги <div> на <а>, а также
запишем ссылки на файлы в атрибутах href этих тегов:
<а href="images/1.jpg" class="active">l</a>
<a href="images/2.jpg">2</a>
<a href="images/3.jpg">3</a>
Урок 6. События и их обработка 119
display: block;
text-decoration: none;
}
nav a.active {
}
3. Внесем правки в код сценария:
function showlmage(evt) {
if (evt.target != this) {
output.src = evt.target.href;
}
}
function showPreview(evt) {
if (evt.target != this) {
preview.style.backgroundlmage = 'url(' +
evt. target, href + ')';
}
}
Свойство href соответствует одноименному атрибуту тега <а>.
4
Откроем исправленную страницу 6.1.Мт1 в веб-обозревателе и щелкнем на кноп
ке 3. Увы — изображение 3.jpg будет открыто, но не в панели слайдера, а непо
средственно в веб-обозревателе, заменив собой всю страницу (рис. 6.4).
Проблема в том, что при щелчке на гиперссылке выполнился обработчик по
умолчанию, исполнивший переход по этой гиперссылке.
Обработчик события по умолчанию — реализован в самом веб-обо
зревателе и срабатывает после всех обработчиков, написанных программи
стом.
120 Часть II. Управление веб-страницей и веб-обозревателем
evt.preventDefault();
}
}
Вот теперь наш слайдер будет работать, как положено.
Урок 6. События и их обработка 121
вой класс с указанным именем (ставится без начальной точки). Если таковых
элементов нет, возвращает пустую коллекцию:
<div class="button">l</div>
<div class="button">2</div>
<div class="button">3</div>
class с1аззЫаше
rowspan rowSpan
colspan со1Брап
7.3. Упражнение.
Делаем стильную полосу прокрутки
Элементы с прокруткой встречаются весьма часто. Чтобы оживить их, применяют
ся стильные полосы прокрутки, реализуемые программно. Давайте и мы сделаем
такой элемент и заодно закрепим на практике материал из разд. 7Л и 7.2.
1. В папке 7\!sources сопровождающего книгу электронного архива (см. приложе
ние 3) найдем страницу 7.1 .html и скопируем ее куда-либо на локальный диск.
Эта страница содержит элемент с прокруткой и расположенную правее заготов
ку для полосы прокрутки в виде вертикальной линии с овальным серым захва
том (рис. 7.2).
</div>
<div id="scrollbar">
<div></div>
</div>
132 Часть II. Управление веб-страницей и веб-обозревателем
lastPos = evt.clientY;
}
}
Здесь мы сначала вычисляем смещение курсора мыши (первое выражение тела)
и на его основе получаем величину смещения захвата (второе выражение).
Далее проверяем, не выходит ли полученное смещение захвата за пределы поло
сы прокрутки. Для этого достаточно выяснить, укладывается ли она в диапазон
0...262, где последнее число— это высота полосы прокрутки (300 пикселов) за
вычетом высоты захвата (38 пикселов, обе величины записаны в стилях).
Если смещение укладывается в указанный диапазон, создаем встроенный стиль,
указывающий вертикальную координату захвата, и присваиваем его свойству
style. Потом вычисляем величину, на которую нужно прокрутить содержимое
элемента container, и присваиваем ее свойству scroiiTop. Напоследок не забу
дем сохранить текущее положение мыши по вертикали.
7. Впишем под предыдущим выражением объявление обработчика события
mouseup, который прервет операцию перетаскивания:
function mUp(evt) {
this.removeEventListener('mousemove', mMove);
this.removeEventListener('mouseup', mUp);
}
Он просто убирает привязку обработчиков событий mousemove И mouseup.
Откроем страницу 7.1 .html в веб-обозревателе и протащим захват полосы прокрутки
вниз (рис. 7.3).
<h2 id=,,atom">Atom</h2>
Урок 7. У п р ав лени е э л е м е н т а м и в е б -ст р а н и ц 135
</section>
Если присвоить этим свойствам HTML-код, все содержащиеся в нем теги будут
выведены как есть:
par2.textcontent = 'Язык программирования <em>' + par2.innerText + '</еш>';
/*
Результат:
Язык программирования <em>JavaScript</em>
V
Класс h t m l e lement поддерживает два полезных метода:
♦ insertAdjacentHTML {<местоположение>, <НТМЬ-код>)— вставляет указанный HTML-код
ПОзаданному относительно текущего элемента местоположению. В качестве
местоположения указывается одна из строк:
const pl = document.getElementsByTagName('р')[0];
const sl = '<strong>JavaScript</strong> - ';
pl.insertAdj acentHTML('afterbegin', sl);
const s2 = '<р>Применяется в веб-разработке</р>';
pl.insertAdj acentHTML('afterend', s2);
Урок 7. Управление элементами веб-страниц 139
/*
Результат:
JavaScript - язык программирования
Применяется в веб-разработке
V
♦ insertAdjacentText {<мвстоположенив>, <текст>) — ТО же самое, ЧТО И
insertAdjacentHTML, ТОЛЬКО вставляет обы ЧН Ы Й текст.
----</tablo>
</body>
3. Добавим в конце HTML-кода тег < sc rip t> со сценарием, создающим массив
с диаметрами окружностей, у которых нужно вычислить длины, и переменную,
которую мы используем в качестве счетчика цикла:
<script type="text/javascript">
const ds = [2, 5, 10, 20];
let i;
</script>
Длина окружности
Д и ам етр Д ли на окруж ности
2 6.283185307179586
5 15.707963267948966
10 31.41592653589793
20 62.83185307179586
7.6.1. Методы,
конструирующие элементы веб-страниц
Для создания элементов страниц применяются два метода класса HTMLDocument,
представляющего саму страницу:
♦ createElement (<имя твга>) — создает объект, представляющий тег с указанным
именем, и возвращает его в качестве результата, имя тега записывается в виде
строки без символов < и >;
♦ createTextNode (<текст>) — СОЗДаеТ объект класса Text, ПреДСТаВЛЯЮЩИЙ ТеКСТО
вое содерж им ое элемента, на основе указанного текста и возвращает его в каче
стве результата.
142 Часть II. Управление веб-страницей и веб-обозревателем
const ps = document.getElementsByTagName('р');
const рагЗ = document.createElement(’p');
par3.textContent = 'Третий абзац';
document.body.insertBefore(рагЗ, ps[l]);
/*
Результат:
Первый абзац
Третий абзац
Второй абзац
*/
♦ insertAdjacentElement (<местоположение>, <вставляемый элемент>) — вставляет
указанный элемент ПО указанному относительно текущего элемента местоположе
нию. В качестве местоположения задается одна из строк:
const р2 = document.getElernentsByTagName('p')[0];
const strong = document.createElement('strong');
strong.textContent = 'JavaScript';
p2.insertAdjacentElement('afterbegin', strong);
Урок 7. Управление элементами веб-страниц 143
P ython
Язык программирования
*/
♦ remove Chi Id (<удаляемый элементу) — удаляет указанный э л е м е н т И ВОЗВращаеТ
его в качестве результата. Вызывается у родителя у д а л я е м о г о э л е м е н т а :
<ul>
<li>JavaScript</li>
<li>PHP</li>
' <li>Delphi</li>
</ul .
... A
const ul = document.getElementsByTagName(’ul’)[0];
document.body.removeChild(ul.lastElementChild);
/*
Результат:
JavaScript
PHP
V
144 Часть II. Управление веб-страницей и веб-обозревателем
],
Урок 7. Управление элементами веб-страниц 145
contras: [
*некоторые полезные инструменты . . .',
site: 'https://atom,io/*
};
Напишите страницу 7.8.3.html со сценарием, формирующим на основе этого объ
екта описание текстового редактора (рис. 7.7).
Подсказка: сконструируйте все необходимые элементы.
Рис. 7.6. Страница со свободно позиционируемым элементом, который можно перемещать мышью
Atom
Текстовый редактор для программистов.
Достоинства:
Недостатки:
О Ф н Ц И а л ^тть тч СДЙТ
8.2. Управление
мультимедийными элементами
Мы можем получать сведения об аудио- и видеороликах, выведенных в тегах
<audio> и <video>, — в частности, продолжительность и разрешение (у видеороли
ков). Мы также можем управлять их воспроизведением: запускать, приостанавли
вать, изменять текущую позицию, настраивать уровень громкости, приглушать
и вновь восстанавливать звук и др.
Для этого применяются специфические свойства, методы и события классов
HTMLAudioElernent И HTMLVideoElement, ПРОИЗВОДНЫХ ОТ класса HTMLElement И пред
ставляющих теги <audio> и <video>. Рассмотрим их подробно.
8.2.1. Свойства
Классы HTMLAudioElement И HTMLVideoElement ПОДДерживаЮТ Следующие СВОЙСТВа:
♦ currentTime — текущая позиция воспроизведения ролика в виде числа в се
кундах:
// Устанавливаем позицию воспроизведения видеоролика на 10 секунд
videol.currentTime = 10;
8.2.2. Методы
Классам HTMLAudioElement И HTMLVideoElement свойственны Следующие методы:
♦ load о — перезагружает текущий ролик. Обычно применяется, чтобы остано
вить ролик и перемотать его в начало;
150 Часть II. Управление веб-страницей и веб-обозревателем
8.2.3. События
Все события, поддерживаемые мультимедийными элементами, невсплывающие, не
имеют обработчика по умолчанию и представляются классом Event:
♦ loadstart — начата загрузка файла с роликом;
♦ durationchange — загружена часть метаданных, в которой записана продолжи
тельность ролика;
♦ loadedmetadata — загружена остальная часть метаданных, в которой записано,
в частности, разрешение ролика (если это видео);
♦ loadeddata — загружено достаточно данных, чтобы, по крайней мере, вывести
первый кадр ролика, однако его воспроизведение будет вестись с паузами на
подгрузку;
♦ progress — периодически возникает при загрузке файла;
♦ canpiay— загружено достаточно данных, чтобы, по крайней мере, начать вос
произведение ролика, однако в дальнейшем возможны паузы на подгрузку;
♦ canplaythrough — загружено достаточно данных, чтобы начать воспроизведение
ролика без пауз на подгрузку;
♦ play — воспроизведение ролика запущено или возобновлено нажатием кнопки
пуска или вызовом метода play;
♦ playing — после события play, когда ролик реально начинает воспроизводиться.
Между этими событиями возможна задержка, пока веб-обозреватель подгружает
данные из файла;
♦ timeupdate — позиция воспроизведения ролика изменилась;
♦ volumechange — Либо ИЗМеНИЛСЯ уровень ГрОМКОСТИ, Либо Звук был Приглушен,
либо, наоборот, восстановлен;
♦ waiting — в воспроизведении ролика возникла пауза, необходимая для подгрузки;
♦ pause — воспроизведение ролика приостановлено;
♦ seeking — пользователь начал перемещать регулятор позиции воспроизведения;
♦ seeked — пользователь закончил перемещать регулятор позиции воспроизведе
ния;
♦ ratechange — скорость воспроизведения ролика изменилась;
♦ ended — воспроизведение ролика закончено;
♦ suspend — загрузка мультимедийного файла либо полностью завершилась, либо
приостановлена по какой-то причине (например, сервер перегружен);
Урок 8. Графика и мультимедиа 151
8.3. Упражнение.
Реализуем свой видеопроигрыватель
Создадим средствами HTML, CSS и JavaScript стильный видеопроигрыватель,
в котором все элементы управления воспроизведением изначально скрыты (рис. 8.1, а)
и появляются поверх видео при наведении на него курсора мыши (рис. 8.1, б).12
video.addEventListener('playing', () => {
play.style.backgroundlmage = 'url(images/pause.png)';
player.classList.remove('active1);
});
video.addEventListener(’pause', () => {
play.style.backgroundlmage = 'url(images/play.png)';
player.classList.add('active');
});
6. В процессе воспроизведения ролика нужно обновлять текущую позицию в ре
гуляторе position.
Объявим обработчик события timeupdate Тега <video> — он и сделает все, что
нужно:
video.addEventListener('timeupdate', () => {
posH.style.width = video.currentTime / video.duration * 100 + '%';
}) ;
Вычислить ширину указателя (пустого блока, находящегося в блоке-регуля
торе) просто: мы делим текущую позицию воспроизведения на продолжитель
ность ролика, умножаем полученное частное на 100— и получаем ширину
в процентах.
7. По окончании ролика следует привести проигрыватель в исходное положение.
Проще всего сделать это, выполнив перезагрузку ролика — в обработчике со
бытия ended проигрывателя:
video.addEventListener('ended', () => {
video.load();
});
8. Напишем обработчик события click кнопки play, который запустит воспроиз
ведение ролика или, если он уже проигрывается, приостановит его:
play.addEventListener('click', () => {
if (video.paused) {
video.play();
} else {
video.pause();
9.1. Взаимодействие
с элементами управления
Мы можем программно получать значения, занесенные в элементы управления,
временно делать их недоступными, реагировать на изменение значения в поле вво
да, установку или сброс флажка и др. Все это выполняется посредством специфи
ческих свойств (табл. 9.1), методов (табл. 9.2) и событий (табл. 9.3), поддерживае
мых классами, представляющими элементы управления (помимо полученных
в «наследство» от суперкласса нтмьЕ1етеп1:). Классы событий и их свойства пред
ставлены в табл. 9.4.
/П оддерживаю щ ие его
Свойство Описание
элементы управления
Поддерживающие его
С войство Описание
элементы управления
Поддерживающие его
Метод Описание
элементы управления
Класс F o cu sE ve n t
Производный от класса Event. Представляет события фокуса ввода
♦ поля ввода даты — дата в свойстве value хранится в виде строки формата < год> -
<номер месяца>-<чмсло>\
cinput type="date" id="dat">
♦ поля ввода времени — время в свойстве value хранится в виде строки формата
<часы> : <минуты> :<секунды>\
♦ поля выбора цвета— цвет в свойстве value хранится в виде строки формата
#<r x g ><b >;
opt.textContent = languageTexts[i];
psel.add(opt);
}
9.2. Упражнение.
Пишем первое клиентское веб-приложение
Напишем клиентское веб-приложение, генерирующее CSS-код для создания у эле
мента страницы рамки на основе введенных пользователем данных.
Клиентское веб-приложение — программа, реализованная в виде веб-стра
ницы с веб-сценарием и не требующая для работы других программ
(в частности, серверных веб-приложений, работающих на стороне веб
сервера).
1. В папке 9\!sources сопровождающего книгу электронного архива (см. приложе
ние 3) найдем страницу 9.1.html, скопируем ее в какое-либо место на локальном
диске и откроем в текстовом редакторе.
Эта страница содержит набор элементов управления, в которых пользователь
будет заносить необходимые сведения (рис. 9.1).
3. Поле ввода Радиус скругления должно быть доступно для ввода только тогда,
когда установлен флажок Скругленные углы. Поэтому напишем обработчик
события change флажка Радиус скругления, который будет делать поле ввода
Скругленные углы доступным или недоступным, в зависимости от состояния
флажка:
rounded.addEventListener('change', () => {
radius.disabled = !rounded.checked;
});
4. Напишем код, который при нажатии кнопки Сгенерировать код сгенерирует
и выведет на экран CSS-код для задания рамки:
generate^addEventListener('click', () => {
let s = 'border: ' + width.value + ' ' +
style.options[style.selectedlndex].value + ' ' + color.value +
';\r\n';
if (rounded.checked)
s += 'border-radius: ' + radius.value +
output.textContent = s;
});
В случае задания скругленных углов сгенерированный CSS-код будет состоять
из двух атрибутов стиля: border и border-radius, — выведенных в две строки.
Мы добились этого, поместив после символа ; первой строки последователь
162 Часть II. Управление веб-страницей и веб-обозревателем
<^аЬ1е>
</:£огт>
Свойство Описание
elements Коллекция всех элементов управления, имеющихся в форме
length Количество элементов управления в форме
autocomplete Если • on ' — у всех полей ввода в форме выводится список ранее вве
денных значений для быстрого выбора (поведение по умолчанию). Если
'of f ' — такой список не выводится
Метод Описание
submit() Выполняет отправку данных, как если была нажата кнопка отправки
данных
reset () (Выполняет сброс формы, как если бы была нажата кнопка сброса
Всплывающие
9.4. Упражнение.
Реализуем валидацию данных в веб-форме
В приложении из разд. 9.3 не помешает обезопаситься на тот случай, если пользо
ватель забудет ввести толщину рамки, радиус скруглення или же не укажет в них
единицу измерения. Давайте сделаем это и пока ради простоты будем принимать
лишь величины, заданные в пикселах.
1. В теги <input> страницы 9.2.html, создающие поля ввода Толщина и Радиус
скруглення, добавим атрибут без значения required, чтобы сделать эти поля
Урок 9. Веб-формы и элементы управления 165
Если методу при вызове передать непустую строку, элемент управления счи
тается содержащим некорректное значение. Чтобы пометить элемент управ
ления как содержащий корректное значение, следует передать методу
setCustomValidity Пустую Строку.
Итак, напишем функцию checkvaiue, которая выполнит необходимую проверку,
и привяжем ее к полям ввода Толщина и Радиус скругления в качестве обра
ботчика события change:
function checkValueO {
if (this.value)
166 Ч аст ь II. У пр ав л е ни е в е б -с т р а н и ц е й и в еб -о б о зр е в а т ел ем
if ( t h i s . v a l u e . e n d s W i t h (’p x ' ))
t h i s .s e t C u s t o m V a l i d i t y ('');
else
t h i s .s e t C u s t o m V a l i d i t y ^
(’У к а ж и т е еди н и ц у и з м е р е н и я px ( п икселы)’);
}
f o r m . e l e m e n t s [0].a d d E v e n t L i s t e n e r (’c h a n g e ’, c h e c k V a l u e );
f o r m . e l e m e n t s [4].a d d E v e n t L i s t e n e r ('c h a n g e ’, c h e c k V a l u e );
const w i d t h = d o c u m e n t . g e t E l e m e n t B y I d ( ’w i d t h ’);
const w i d t h E r r o r = d o c u m e n t . g e t E l e m e n t B y l d (’w i d t h E r r o r ’);
Урок 9. В е б -ф о р м ы и э л ем е н т ы уп р а в л е н и я 167
♦ rangeOverflow— true, если число, занесенное в поле ввода числа, больше ука
занного в атрибуте тега max, false в противном случае;
♦ stepMismatch— true, если число, занесенное в поле ввода числа, не попадает
в интервал между значениями, заданный атрибутом тега step, false в противном
случае;
♦ patternMismatch — true, если введенное значение не совпадает с шаблоном, за
данным в атрибуте тега p a t t e r n (о нем разговор пойдет на уроке 10), false в про
тивном случае;
♦ c u s t o m E r r o r -- true, еСЛИ меТОД s e t C u s t o m V a l i d i t y б ы л ВЫЗВан С н е п у с т о й СТрО
к о й , false в противном случае.
Р и с . 9.5. В е б -п р и л о ж е н и е , ге н е р и р у ю щ е е C S S -код д л я ф о р м и р о в а н и я п р о св е то в
Р и с . 9.6. П р и л о ж е н и е -э к з а м е н а то р
Урок 10
Регулярные выражения
Регулярные выражения JavaScript
Литералы и модификаторы регулярных выражений
Поиск и обработка текста посредством регулярных выражений
Программная валидация с помощью регулярных выражений
HTML-валидация
Этот способ имеет СМЫСЛ применять Л И Ш Ь тогда, когда шаблон И (или) модифика
торы создаются программно.
Для тестирования шаблонов регулярных выражений можно использовать интернет
службу «Regular expression» (рис. 10.1), доступную по адресу https://regexl01.com/.
Примеры:
// Ищем отдельное слово вида ’CSS<LfH<£p<3>'
гех = /\bCSS\d\b/;
result = rex.test('Язык CSS3'); // true
result = rex.test(’Язык CSS’); // false
result = 'Пакет SCSS’.search(rex); // -1
// Ищем обозначение цвета в формате RGB без учета регистра символов
rex = /#\w\w\w\w\w\w/i;
result = rex.test('color: #cb458a;'); // true
10.2.2. Поднаборы
| Поднабор — литерал, обозначающий любой символ из заданного набора.
В табл. 10.2 приведен список поддерживаемых поднаборов.
Примеры:
rex = /[RST] [i-m] [Aa-w]/;
result = rex.test(’Sky'); // true
result = rex.test('Tin'); // false
Урок 10. Регулярные выражения______________________________________________________ 1 7 5
10.2.3. Вариант
Вариант — литерал, обозначающий любой фрагмент из перечисленных.
Он записывается в формате:
<фрагмент 1>\<фрагмент 2> | . . . \<фрагмент п-1>\<фрагмент л>.
10.2.4. Квантификаторы
IКвантификатор — литерал, указывающий количество повторений или
Иместоположение символа.
Вот все поддерживаемые квантификаторы:
♦ <сим волу * — символ может присутствовать в произвольном количестве экземп
ляров:
rex = /\bCS+S\b/i; // Результат: CS |сЦ [CSSS| |CSSSSSSSS|
♦ < символ > і — символ может присутствовать в одном экземпляре или отсутство
вать: і
нящая имя тега из первой группы. Чтобы поместить в регулярное выражение сим
вол прямого слеша, мы предварили его обратным слешем:
rex = /<(\w+)>(.*?)<\/\l>/; // Результат: |</strong>|
Пример:
гех = /А [0-9] + ../; // Результат: [20pt| 30px\r\n200mm 5cm
гех = /А [0-9]+../т; // Результат: |20pt| 30px\r\n|200mm| 5cm
гех = /[0-9]+..$/; // Результат: 20pt 30px\r\n200mm |5cm|
гех = /[0-9]+..$/т; // Результат: 20pt [30px|\r\n2Q0mm |5crn|
Пример:
rex = /CSS\d/;
result = 'HTML CSS5 JavaScript'.replace(rex, 'CSS');
// 'HTML CSS JavaScript'
Пример:
resuit = ’HTML, CSS; JavaScript ’.spiit (/, |;/) ;
// [’HTML’, ’CSS’, ’JavaScript’]
10.4. Упражнение.
Выполняем программную валидацию
с помощью регулярного выражения
Веб-приложение, написанное в разд. 9.4, позволяет задать в качестве единицы из
мерения только пикселы. Доработаем его, чтобы можно было указывать также
пункты и проценты. И используем для этого регулярное выражение.
1. Найдем в папке 10\!sources сопровождающего книгу электронного архива
(см. приложение 3) страницу 9.2.html, скопируем ее куда-либо на локальный диск
и откроем копию в текстовом редакторе.
182 Часть II. Управление веб-страницей и веб-обозревателем
10.5. HTML-валидация
с применением регулярных выражений
Чтобы выполнить валидацию введенного в поле значения на совпадение с регуляр
ным выражением, необязательно писать веб-сценарий. Достаточно указать нужное
регулярное выражение в атрибуте pattern тега <input>. Регулярное выражение
должно быть записано без символов слеша и без модификаторов. Пример:
<input type="text" id=nwidth" pattern="[0-9]+(px|pt|%)">
Атрибут тега pattern поддерживается в обычном поле ввода, полях ввода пароля,
интернет-адреса и адреса электронной почты.
Недостатки этого способа валидации: необходимость записи регулярного выраже
ния в каждое поле ввода, в котором нужно выполнить проверку значения, и невоз
можность указания модификаторов (вследствие чего, например, нельзя выполнить
сравнение без учета регистра символов).
С войство Описание
С войство Описание
Метод Описание
</html>
<script type=”text/javascript">
// Здесь помещается код сценария
</script>
Однако подобный сценарий можно оформить и как обработчик события load окна.
Это событие возникает, как только страница загружена и обработана, следователь
но, его обработчик исполняется, когда в памяти уже сформированы все объекты,
представляющие элементы страницы. Такой сценарий можно поместить куда угод
но — например, в секцию заголовка страницы:
<html>
<head>
188 Часть II. Управление веб-страницей и веб-обозревателем
<script type="text/javascript">
window.addEventListener('load', () => {
// Здесь помещается код сценария
}) ;
</script>
</head>
<body>
</body>
</html>
});
</script>
</head>
<script type="text/javascript">
function highlightActiveLink(hash) {
active = document.querySelector('nav a.active');
if (active)
active.classList.remove('active');
active = document.querySelector('nav a[href$=' + hash + ']');
active.classList.add('active');
}
</script>
Сначала ищем активную в текущий момент гиперссылку и, если она есть, уби
раем у нее стилевой класс active, чтобы снять подсветку. Потом ищем гипер
ссылку с полученным в параметре якорем и привязываем к ней стилевой класс
active, тем самым подсвечивая.
else
hash = 'vsc';
highlightActiveLink(hash);
}) ;
В полученном из свойства newURL объекта события интернет-адресе ищем сим
вол решетки (#), с которого начинается якорь. Если таковой есть, вырезаем из
интернет-адреса имя якоря без символа решетки. Если же решетки в интернет
адресе нет, берем в качестве якоря активной гиперссылки vsc — это якорь самой
первой гиперссылки в панели навигации. После чего вызываем функцию
hightlightActiveLink, передав ей полученный ЯКОрь.
♦ hash — имя якоря с начальным символом решетки. Если якоря нет, хранит пус
тую строку:
let hash = location.hash; // '#anch'
С войство Описание
a v a ilW id th Ширина свободной области экрана (без учета панели задач) в пикселах
a v a ilH e ig h t Высота свободной области экрана (без учета панели задач) в пикселах
Пример:
<img id="logo">
Подтвердите действие
Введите неотрицательное число
ОК
Подтвердите действие
Выполнить операцию?
Рис. 11.4. Окно с запросом на ввод значения, содержащее текст, поле ввода и кнопки ОК и Отмена
12.1. Упражнение.
Используем периодические таймеры
Напишем клиентское веб-приложение, вычисляющее простые числа в указанном
пользователем диапазоне.
1. В папке 12\!sources сопровождающего книгу электронного архива (см. приложе
ние 3) найдем страницу 12.1.1.html и скопируем ее куда-либо на локальный диск.
Эта страница содержит заготовку для создания приложения (рис. 12.1).
В поля ввода чисел От: и до: заносятся начальное и конечное числа диапазона,
в котором нужно найти простые числа, кнопка отправки данных Вычислить за
пускает вычисления, а нижний список, изначально пустой, служит для вывода
найденных простых чисел.
3. В конце HTML-кода добавим тег <script> с первыми выражениями сценария:
<script type="text/javascript">
const form = document.forms [0 ];
form.addEventListener(Submit’, (evt) => {
const min = parselnt(form.elements[0].value);
const max = parselnt(form.elements[1].value);
let flag, sqr, el;
form.elements[3].innerHTML = f';
form.elements[2].disabled = true;
}) ;
</script>
form.elements[2].disabled = true;
for (let i = min; i <= max; ++i) {
if (i % 2 != 0) {
flag = true;
sqr = Math.floor (Math, sqrt(i) ) ;
for (let j = 3; j <= sqr; j += 2)
if (i % j = 0) {
flag = false;
break;
}
if (flag) {
el = document.createElement ('option ') ;
el.textContent = in
form .elements[3].add(el);
}
)
)
}) ;
Принцип несложен: простым считается число, не делящееся нацело на 2 и все
числа от трех до значения квадратного корня из этого числа, округленного до
ближайшего меньшего целого. Такое число добавляется в нижний список.
Урок 12. Таймеры и фоновые потоки 199
Рис. 12.2. В нижнем списке появились все простые числа, найденные в заданном диапазоне
Проблема здесь в том, что пока идут вычисления, приложение перестает отвечать
на действия пользователя (как бы «подвисает»)— поскольку веб-обозреватель,
полностью занятый выполнением кода, не успевает отреагировать на действия
пользователя вовремя. Невозможно даже прокрутить список, чтобы увидеть най
денные простые числа.
Можно разбить процесс вычислений на отдельные короткие этапы, выполняемые
через одинаковые промежутки времени. Тогда веб-обозреватель сможет отреагиро
вать на действия пользователя в промежутке между выполнением отдельных эта
пов. Реализовать такой подход проще всего посредством периодических таймеров.
Периодический таймер — программный механизм HTML API, многократно
срабатывающий по истечении указанного промежутка времени и выпол
няющий при срабатывании заданную функцию.
200 Часть III. HTML API и компонентное программирование
break;
}
if (flag) {
el = document.createElement('option1);
el.textContent = i;
form.elements[3].add(el);
}
}
}
if (i >= max) {
window.clearlnterval(int);
form.elements[2].disabled = false;
}
}
Код этой функции похож на код обработчика события submit из предыдущего
варианта сценария, но с двумя различиями. Во-первых, цикл, в котором произ
водится поиск простых чисел, будет выполняться, пока текущее число из пере
менной i не выходит за верхнюю границу (max), и количество обработанных чи
сел не превышает 1000. Во-вторых, по окончании обработки всех чисел из диа
пазона (если значение переменной i, которая в тот момент будет хранить
последнее из обработанных чисел, выходит за верхнюю границу диапазона max)
мы удаляем таймер вызовом метода clearlnterval и делаем доступной кнопку
Вычислить, тем самым приведя приложение в изначальное состояние.
4. Наконец, напишем обработчик события submit, запускающий процесс вычис
ления:
form. addEventListener(*submit', (evt) => {
min = parseint(form.elements[0].value);
max = parselnt(form.elements[1].value);
i = min;
form.elements[3].innerHTML = 1';
form.elements[2].disabled = true;
int = window.setlnterval(computeSimpleValues, 100);
evt.preventDefault() ;
}) ;
form.elements[2].disabled = true;
worker = new Worker('12.3.js');
});
5. Поскольку все потоки независимы друг от друга, сценарий из фонового потока
не сможет получить доступ к списку, чтобы добавить в него найденное простое
число. Для пересылки чисел из фонового потока в основной мы применим меж
поточные сообщения.
Межпоточное сообщение — сигнал, пересылаемый из одного потока дру
гому и содержащий в себе одно произвольное значение. Применяется для
обмена данными между потоками и пересылки управляющих команд.
Чтобы получить в основном потоке сообщение, отправленное фоновым пото
ком, достаточно обработать событие message, возникающее в объекте фонового
потока.
Для ЭТОГО добавим выражение, привязывающее К событию message потока worker
функцию-обработчик processResuit (будет написана позже):
form.addEventListener(1submit1, (evt) => {
worker.addEventListener('message*, processResult);
const data = {};
data.min = parselnt(form.elements[0] .value) ;
data.max = parselnt(form.elements[1] .value) ;
worker.postMessage (data) ;
evt.proventDefault();
}) ;
7. Нам также нужно реагировать на сообщения от фонового потока и на хранящие
ся в них значения. Условимся, что строка 'stop1 станет командой на завершение
фонового потока, а любое другое значение будет выведено в списке найденных
простых чисел.
Для завершения фонового потока у его объекта следует вызвать не прини
| мающий параметров метод terminate.
Перед обработчиком события submit запишем код объявления функции
processResult, которая выполнит все это:
function processResult(evt) {
if (evt.data == 'stop') {
form.elements[2].disabled = false;
worker.terminate();
} else {
const el = document.createElement('option');
el.textContent = evt.data;
form.elements[3].add(el);
}
}
8. Для получения сообщений от основного потока в фоновом потоке обработчик
события message следует привязать к объекту фонового потока, а для отправки
сообщения ИЗ фонового потока основному — вызвать метод postMessage также
у объекта фонового потока. Упомянутый ранее объект можно получить из пере
менной this, автоматически создаваемой в фоновом потоке.
Создадим в той же папке файл 12.3.js, в котором сохраним код фонового потока:
this.addEventListener('message', (evt) => {
let flag, sqr;
for (let i = evt.data.min; i <= evt.data.max; ++i)
{
if (i % 2 != 0) {
flag = true;
sqr = Math.floor(Math.sqrt(i));
for (let j = 3 ; j <= sqr; j += 2)
if (i % j == 0) {
flag = false;
break;
}
Урок 12. Таймеры и фоновые потоки 205
if (flag)
this.postMessage(i);
}
}
this.postMessage('stop');
}) ;
Как только очередное простое число найдено, отправляем его в сообщении
основному потоку для вывода в списке. По завершении вычислений не забываем
отправить сообщение со строкой 'stop* — командой на завершение фонового
потока.
В ним ание!
В веб-обозревателе Google Chrome фоновые потоки могут запускаться лишь на стра
ницах, загруженных с веб-сервера. Попытка запустить фоновый поток на странице, за
груженной с локального диска, вызовет ошибку.
Класс такого поля поддерживает свойство files. Оно хранит объект класса
FiieList, который является коллекцией выбранных в поле файлов (если в теге
<input> отсутствует атрибут без значения multiple, коллекция будет содержать
лишь один файл). Каждый из элементов коллекции — это объект класса File, пред
ставляющий отдельный выбранный файл.
Свойство Описание
Класс P ro g re s s E v e n t
Представляет событие progress
13.2. Упражнение.
Реализуем предварительный просмотр
выбранного графического файла
Часто в веб-формах для выгрузки графического файла на сервер делают панель
предварительного просмотра. Давайте и мы сделаем нечто подобное.
1. В папке 15\!sources сопровождающего книгу электронного архива (см. приложе
ние 3) найдем страницу 13.2.html и скопируем ее куда-либо на локальный диск.
Эта страница содержит поле выбора файла file, расположенный под ней блок
preview, в котором будет выводиться выбранное изображение, и оформляющую
все это внутреннюю таблицу стилей.
Урок 13. Работа с файлами, хранение данных и перетаскивание 211
3. Добавим обработчик события load только что созданного объекта, который вы
ведет загруженный файл в блоке preview:
fr.addEventListener(’load', (evt) => {
preview.style.backgroundlmage = 'url(f + evt.target.result + *) f;
}) ;
Мы выведем загруженное изображение в виде графического фона, поскольку
такой фон проще разместить по центру блока.
4. Добавим обработчик события change поля выбора файла file, который запустит
загрузку выбранного файла:
file.addEventListener('change1, () => {
fr.readAsDataURL(file.files [0] );
}) ;
Откроем страницу 13.2.html в веб-обозревателе, выберем в поле какой-либо графи
ческий файл и посмотрим на его содержимое, выведенное в блоке (рис. 13.1).
13.4. Перетаскивание
Перетаскивание (иначе drag’n'drop) — технология, позволяющая перено
сить данные из одного элемента страницы {источника) в другой {приемник)
простым перетаскиванием мышью.
Реализация перетаскивания на странице включает несколько этапов, которые мы
рассмотрим в порядке их выполнения.
Оба параметра указываются в виде строк, тип значения можно задать произволь
ный, но обычно используют MIME-тип.
214 Часть III. HTML API и компонентное программирование
В ним ание!
Практически всегда обработчик события drop по умолчанию принимает переносимые
данные за интернет-адрес и пытается выполнить переход по нему. Поэтому обработку
события drop по умолчанию следует отменять.
Пример:
dragdest.addEventListener('drop', (evt) => {
let s = evt.dataTransfer.getData('text/plain');
if (evt.dataTransfer.dropEffeet == 'move')
// Выполняем перенос данных
else
// Копируем данные
evt.preventDefault();
}) ;
По завершении перетаскивания в элементе-источнике возникает событие dragend.
Оно всплывающее, не имеет обработчика по умолчанию и может применяться для
выдачи каком-либо оповещений о завершении переноса данных.
13.5. Упражнение.
Практикуемся в реализации перетаскивания
Напишем веб-приложение «Экзаменатор», предлагающее перенести из левого пе
речня в правый все языки для разработки веб-страниц (но не серверных веб
приложений!). Для этого мы применим знания, полученные в разд. 13.4.
1. В папке 13\!sources сопровождающего книгу электронного архива (см. приложе
ние 3) найдем файл 13.5.html и скопируем его куда-либо на локальный диск. Этот
файл хранит страницу с заготовкой для написания веб-приложения (рис. 13.2).
Урок 13. Работа с файлами , хранение данных и перетаскивание 217
Экзаменатор
Перенесите и з левого списка в правый все языки, применяемые для
разработки веб-страниц.
Python
Assembler
HTML
XAML
TypeScript
CSS
Java
C++
JavaScript
| Готово!
Экзаменатор
П еренесите нз левого списка в правый все языки, применяемые для
разработки веб-страниц.
Python HTML
Assembler JavaScript
XAML CSS
Java Typescript
C++
і Готово! I
Рис. 13.3. Несколько позиций перетащены из левого перечня в правый
Урок 13. Работа с файлами, хранение данных и перетаскивание 219
14.3. Указание
основных параметров графики
Основные параметры графики, включающие цвета линий, заливок и настройки
тени, действуют на любую графику, рисуемую на холсте.
Урок 14. Программная графика 223
5. После HTML-кода поместим тег < sc rip t> с выражениями, получающими доступ
к холсту и к его графическому контексту:
<script type="text/javascript">
const draw = document.getElementByld('draw1);
const ctx = draw.getContext(12d');
</script>
226 Часть III. HTML API и компонентное программирование
Она равна высоте холста за вычетом 25 пикселов — под вывод названия языка.
10. И напишем код, выводящий диаграмму:
let xi, yi;
for (let i = 0; i < languages.length; ++i) {
a = iheight * languages[i][1] / 100;
xi = i * (iwidth + 5) ;
yi = draw.height - a;
ctx.fillRect(xi, yi, iwidth, a);
ctx.fillText(languages[i][0], xi + iwidth / 2, yi, iwidth);
}
Урок 14. Программная графика 227
Рис. 14.6. Рисование прямых линий: а — с выводом только контура нарисованной фигуры;
6 — с выводом только заливки нарисованной фигуры
Замыкание контура
Чтобы замкнуть рисуемый контур, проведя прямую линию от текущего местопо
ложения пера до точки, в которой началось рисование, следует вызвать не прини
мающий параметров метод ciosePath.
Пример (см. рис. 14.6, а):
ctx3.beginPath();
ctx3.strokeStyle = 'blue';
ctx3.moveTo(50, 0);
ctx3.lineTo(100, 100);
ctx3.lineTo(0, 100);
ctx3.ciosePath();
ctx3.stroke() ;
При рисовании фигур из заливок методом fill контур будет замкнут автоматиче
ски (см. рис. 14.6, б).
Урок 14. Программная графика 229
• round — скругленная;
• bevel — срезанная.
Помимо этого, можно указать стиль линий — будут ли они штриховыми или пунк
тирными. Для этого применяется метод setLineDash графического контекста:
setLineDash {<массив с параметрами стиля линий>)
Примеры:
ctx3.beginPath();
ctx3.setLineDash([б, 3]);
ctx3.moveTo(О, 50); ■■■■■■■■■■■
ctx3.lineTo(100, 50);
ctx3.stroke(); __________
ctx4.beginPath();
ctx4.setLineDash([10, 3, 5, 3]);
ctx4 .moveTo (0, 50); ■ ■■■■■■■■■
ctx4.lineTo(100, 50);
ctx4.stroke(); __________
Чтобы ВНОВЬ Проводить сплошные ЛИНИИ, следует вызвать метод setLineDash, пере
дав ему пустой массив.
Не принимающий параметров метод getLineDash возвращает заданный ранее мас
сив с параметрами стиля линий.
Рисование дуг
Для рисования дуг (частей окружностей) используются два метода:
♦ arc-- р и с у е т д у г у С ЦвНТрОМ В ТОЧКв С КООрДИНатаМИ [х, у], у к а з а н н ы м и р а д и у
сом,
,начальным И конечным углам и:
агс(<х>, <у>, <радиус>, <начальный у го л > , <конечный у г о л > [,
<против часовой ст релки?>])
♦ arcTo — рисует дугу с указанным ради усом между двумя касательными. Первая
касательная проводится между точкой, в которой находится перо, и точкой с ко
ординатами [xi, yi], вторая — между точками с координатами [xi, y i ] и [х2, у2]
(рис. 14.7).
Урок 14. Программная графика 231
Формат:
arcTo(<xl>, <у1>, <х2>, <у2>, < ради ус> )
Пример:
ctx4.beginPath();
ctx4.moveTo(5, 95);
ctx4.lineTo(5, 50);
ctx4.arcTo(5, 5, 50, 5, 45);
ctx4.arcTo(95, 5, 95, 50, 45);
ctx4.lineTo(95, 95);
ctx4.stroke() ;
Формат:
quadraticCurveTo{<сх>, <су>, <х>, <у>)
Пример:
ctxl.beginPath();
ctxl.moveTo(50, 5)
ctxl.quadraticCurveTo(5, 5, 50, 95);
ctxl.quadraticCurveTo(95, 95, 50, 5);
ctxl.fill ();
Точка
Формат:
bezierCurveTo(<cxl>, <cyl>, <cx2>, < cy2 >, <x>, <y>)
Пример:
ctx2.beginPath();
ctx2.moveTo(50, 30)
ctx2.bezierCurveTo(5, 5, 5, 80, 50, 80);
ctx2.moveTo(50, 30)
ctx2.bezierCurveTo(95, 5, 95, 80, 50, 80);
ctx2.fill();
Рисование прямоугольников
Чтобы нарисовать в составе сложной фигуры прямоугольник, нужно вызвать метод
rect:
rect(<x>, <у>, <ширина>, <высота>)
Левый верхний угол прямоугольника будет находиться в точке [х, у]. По окончании
рисования перо останется в той же точке.
Урок 14. Программная графика 233
Пример:
ctxl.beginPath();
ctxl.rect(30, 40, 60, 40);
ctxl.lineTo(30, 5);
ctxl.stroke();
Начало градиента будет находиться в точке [х1, у1], конец— в точке [х2, у2]. Эти
координаты указываются относительно холста.
Метод возвращает объект класса сапчаэОгасИепь, представляющий созданный гра
диент.
Для добавления к градиенту ключевой точки у полученного объекта градиента
нужно вызвать метод addColorStop:
addCo1огБtо р (<относительное расст ояние>, <цвет>) *
234 Часть III. HTML API и компонентное программирование
Начальная
окружность
Конечная^
окружность
Прим ечание
Веб-обозреватель Mozilla Firefox при указании как значения repeat-x, так и значения
repeat-y повторяет графическую заливку и по горизонтали, и по вертикали (как если
бы было указано значение repeat).
Примеры:
<img src="img.png" id="img">
С о зд а в а т ь г р а ф и ч е с к у ю за к р а с к у м о ж н о л и ш ь п о с л е т о г о , как за к о н ч и т с я з а г р у зк а
ф а й л а с и з о б р а ж е н и е м , и с п о л ь з у е м ы м в к а ч е с т в е за к р а с к и . Д о б и т ь с я э т о г о м о ж н о ,
п о м е с т и в с о з д а ю щ и й за к р а с к у к о д в о б р а б о т ч и к с о б ы т и я load о к н а (и л и т е г а <img>
с н у ж н ы м и з о б р а ж е н и е м ):
14.8. Преобразования
П р е о б р а зо в а н и е — м а н и п у л я ц и я н а д с и с т е м о й к о о р д и н а т х о л с т а : с м е щ е н и е
ее начала, и зм ен ен и е м асш таба или п ов о р от.
♦ t r a n s l a t e (<dx>, <dy>) — с м е щ а е т н а ч а л о с и с т е м ы к о о р д и н а т н а в е л и ч и н у dx п о
г о р и зо н т а л и и н а в е л и ч и н у d y п о в е р т и к а л и . П о л о ж и т е л ь н ы е в е л и ч и н ы в ы зы в а
ю т с м е щ е н и е в п р а в о и в н и з, о т р и ц а т е л ь н ы е — в л е в о и в в е р х .
П р и м ер :
c t x l . s t r o k e R e c t (0 , 0, 40, 40);
c t x l . t r a n s l a t e (50, 30)
c t x l . f i l l R e c t (0, 0, 40, 40);
П р и м ер :
Пример:
ctx3.strokeRect(20, 0, 80, 20);
ctx3.rotate(Math.PI / 4)
ctx3.fillRect(20, 0, 80, 20);
♦ drawlmage {<изображение>, <fx>, <fy>, <fw>, <fh>, <x>, <y>, <w>, <h>) — вы
резает из изображения фрагмент с левым верхним углом в точке с координатами
[fx, fy], шириной fw и высотой fh , после чего выводит его в точке [х, у] холста,
задав ему ширину w и высоту h.
Пример:
нии
• lighter— ТО же, ЧТО И source-over, ТОЛЬКО ЧаСТЬ НОВОЙ фигуры,
накладывающейся на старую, закрашивается цветом, полученным
в результате сложения цветов обеих фигур;
Пример:
ctxl2.fillStyle = ’black’;
ctxl2.fillRect(0, 0, 70, 70);
ctxl2.fillStyle = ’lightgrey’;
ctxl2.globalCompositeOperation = 'xor*;
ctxl2.fillRect(30, 30, 70, 70);
15.1.1. Конструктор.
Объявление свойств и методов в конструкторе
Для объявления нового класса достаточно написать для него функцию-кон
структор.I
I Конструктор — функция, которая будет выполняться при создании каждо-
|| го нового объекта представляемого ей класса.
Конструктор может принимать произвольное количество параметров, но не должен
возвращать результат. Имя конструктора, представляющего вновь объявленный
класс, станет именем этого класса.
Конструктор объявляет у создаваемого объекта необходимые свойства и присваи
вает им изначальные значения: фиксированные, рассчитанные в результате вычис
лений или полученные с параметрами. Ссылка на создаваемый объект хранится
в переменной this, доступной в теле конструктора.
В качестве конструктора может быть задействована только именованная
или анонимная функция. Функцию-стрелку использовать нельзя, т. к. в ее
теле переменная this ссылается не на текущий объект, а на объект текущего
окна.
Свойства у создаваемого объекта объявляются простым присваиванием им значе
ний (как и добавленные свойства, описанные в разд. 4.12).
246 Часть III. HTML API и компонентное программирование
Чтобы объявить метод, следует создать у объекта свойство и присвоить ему функ
цию — именованную или анонимную (но, опять же, не функцию-стрелку!), которая
и реализует этот метод. В этой функции также будет доступна переменная this,
хранящая ссылку на текущий объект.
В качестве примера объявим класс user со свойствами паше (имя пользователя),
password (пароль), аде (возраст), sendNotification (если true, пользователь хочет
получать оповещения об обновлениях на сайте, если false — не хочет) и методом
isMature, возвращающим true, если возраст пользователя не меньше 18 лет.
// Функция User__isMature(), реализующая метод isMature класса User
function User__isMature() {
return this.age >= 18;
}
// Функция-конструктор класса User
/ / В качестве параметров принимает имя, пароль и возраст пользователя,
// заносит их в свойства создаваемого объекта и объявляет метод
function User(name, password, age) {
this.паше = name;
this.password = password;
this.age = age;
this.sendNotification = true;
this.isMature = User__isMature;
}
Объект объявленного таким образом класса может быть создан с применением опе
ратора new:
new <имя класса> ([<параметры конструктора ч е р е з запятую>])
15.1.2. Прототип.
Объявление свойств и методов в прототипе
Свойства и методы, которые следует объявить в классе, также можно занести в его
прототип.
Прототип — служебный объект класса object, чьи свойства и методы на
следуются объектом класса, которому принадлежит этот прототип. Насле
дование свойств и методов из прототипа выполняется еще до исполнения
конструктора.
Урок 15. Объявление своих классов 247
Каждый из классов, как встроенных в JavaScript, DOM, BOM или HTML API, так и
объявленных программистом, содержит свой прототип. Прототип любого объяв
ленного программистом класса изначально пуст. Ссылка на прототип хранится
в статическом свойстве prototype владеющего им класса.
В прототипе имеет смысл объявлять свойства, чьи значения не будут изменяться
в конструкторе (в противном случае проще объявить их непосредственно в конст
рукторе).
Вот Пример объявления ТОГО же класса User, В котором СВОЙСТВО sendNotifications
и метод isMature объявлены в прототипе:
function User2(паше, password, age) {
this.name = name;
this.password = password;
this.age = age;
}
// Объявляем в прототипе свойство sendNotifications и метод isMature
User2.prototype.sendNotifications = true;
User2.prototype.isMature = function() {
return this.age >= 18;
};
Где объявлять свойства и методы класса: в конструкторе или прототипе— дело
вкуса. Первый способ несколько нагляднее (поскольку все объявления собраны
в одном месте), но второй дает некоторую прибавку в производительности (т. к.
свойства и методы объявляются в прототипе лишь единожды и потом просто копи
руются в создаваемые объекты).
Условимся о следующем:
• набор «кнопок» слайдера будем идентифицировать по указанному у него
якорю (вспомним, что название «кнопки» у слайдера взято в кавычки, по
скольку это не настоящие кнопки, создаваемые тегом <input>). Как можно
видеть, у нашего набора «кнопок» — тега <nav> — задан якорь slideri;
• в наборе «кнопок» должны присутствовать только гиперссылки, создающие
«кнопки»;
• перед набором «кнопок» должен присутствовать элемент, содержащий в ка
честве первого потомка тег <img> (в нем будет выводиться очередное изобра
жение).
Следование этим соглашением позволит нам заметно упростить код слайдера.
3. Допишем в конце HTML-кода тег <script>, в который поместим объявление
конструктора класса slider:
<script type="text/javascript">
function Slider(buttonset) {
this.buttonset = buttonset;
this.buttonset.addEventListener('click', Slider__showlmage);
}
</script>
10. Для пробы добавим выражение, которое сразу после открытия страницы выве
дет в слайдере второе по счету изображение, вызвав у объекта слайдера метод
setCurrentIndex!
sliderl.setCurrentlndex(1);
15.3. Упражнение.
Создаем динамическое свойство
В классе slider, написанном в разд. 15.2, мы объявили два метода: g e tcur rent index,
возвращающий номер активной «кнопки», и setcurrentindex, активизирующий
«кнопку» с указанным номером. Перепишем этот класс, заменив эти методы дина
мическим свойством currentindex. Это упростит использование класса.
В качестве объекта следует указать прототип нужного класса, имя свойства задается
в виде строки, объект конфигурации , относящийся к классу object, должен иметь
свойства get и set, задающие, соответственно, геттер и сеттер.
В нашем коде уже есть готовые геттер И сеттер--- методы getc u r rent Index И
setcurrentindex. Нам остается превратить их в обычные функции и указать в вызо
ве метода defineProperty.
1. В коде сценария страницы 15.2.html найдем объявления методов g e t c u r r e n t i n d e x
И s et c u r r e n t i n d e x И переделаем И Х В объявления функций Slid e r __
g e t C u r r e n t l n d e x И Slider__ s e t c u r r e n t i n d e x (исправленный К О Д выделен ПОЛу
жирным шрифтом):
function Slider getCurrentlndex() {
}
function Slider__setcurrentindex(ind) {
>
2. Запишем под объявлениями этих функций код, объявляющий динамическое
С В О Й С Т В О currentindex:
252 Часть III. HTML API и компонентное программирование
Object.defineProperty(Slider.prototype, 'currentlndex1, {
get: Slider__getCurrentIndex,
set: Slider__setCurrentIndex
}>;
3. Исправим выражение, выводящее в первом слайдере второе по счету изображе
ние:
sliderl.currentlndex = 1;
♦ если указать только сеттер — свойство станет доступным только для записи:
Object.defineProperty(SomeClass.prototype, 'writeOnlyProperty',
{set : SomeClass__setWOP});
someClassObject.writeOnlyProperty = 5;
let val = someClassObject.writeOnlyProperty; // Ошибка!
15.4. Упражнение.
Реализуем наследование классов
Напишем класс siider2 — более развитую разновидность слайдера. Его конструк
тор сможет принимать в качестве параметра, помимо объекта набора «кнопок», еще
И якорь. А сам класс получит поддержку методов goNext И goPrevious, выводящих
в слайдере, соответственно, следующее и предыдущее изображения. Чтобы не
писать заново весь код, унаследуем класс siider2 от класса slider.
Наследование — создание одного класса на основе другого. Унаследован
ный класс (производный, или подкласс), помимо собственных свойств и ме
тодов, получает все свойства и методы класса, от которого он наследован
(базового, или суперкласса).12
1. В папке 15\!sources сопровождающего книгу электронного архива (см. приложе
ние 3) найдем файл 15-4.html и папку images и скопируем их куда-либо на локаль
ный диск. Страница 15-4.html содержит код класса slider и заготовку для созда
ния слайдера.
2. Откроем страницу 15.4.html в текстовом редакторе и добавим к коду сценария
объявление функции-конструктора класса siider2:
function Slider2(buttonset) {
if (typeof buttonset == 'string')
buttonset = document.getElementByld(buttonset);
}
Если в качестве параметра получена строка, подразумевается, что был передан
якорь набора «кнопок», по которому следует найти сам набор.
254 Часть III. HTML API и компонентное программирование
Slider.appiy(this, arguments);
} '
6. Добавим объявления методов goNext и goPrevious нового класса:
Slider2.prototype.goNext = function () {
this.currentlndex = this.currentlndex + 1;
Урок 15. Объявление своих классов 255
Slider2.prototype.goPrevious = function () {
this.currentIndex = this.currentlndex - 1;
};
7. Напишем выражение, создающее объект слайдера:
const sliderl = new Slider2('sliderl');
// Объявление метода
BaseClass.prototype.someMethod = function (argl, arg2) {
};
BaseClass.prototype.someMethod.apply(this, arguments);
};
I функции-конструктора.
Урок 15. Объявление своих классов_____________________________________ 257
}
Slider.selector = '.slider';
}
Объявленные таким образом статические свойства и методы не наследуются под
классами, поскольку не являются частью прототипа суперкласса.
function Slider_showlmage(evt) {
if (evt.target != this) {
this.previousElementSibling.firstElementChild.src =
evt.target.href;
this.children.forEach((el) => (
el .classNaxne = (el = evt.target) ? 'active' : '';
>);
evt.preventDefault();
}
}
Как видим, благодаря применению метода forEach для перебора коллекции, код
несколько сократился.
Откроем страницу 15.4.html в веб-обозревателе и проверим работу слайдера.
Фотогалерее ..
0'/Ра*^Док>м^ты/Работа/Книг14/1а;
а б
Рис. 15.2. а — лайтбокс скрыт; б — лайтбокс открыт
Урок 16
Компоненты
Компоненты и их написание
Замыкания
Изоляция компонентов
ческие файлы) и initial (номер изначально активной «кнопки». Если это свой
ство не указано, будет активна первая «кнопка»);
♦ привяжет к базовому элементу стилевой класс slider, после чего к нему будут
применены оформляющие CSS-стили;
♦ создаст в базовом элементе «кнопки», а над ними — панель для вывода изобра
жений.
♦ * *
1. Найдем в папке 16\!sources сопровождающего книгу электронного архива
(см. приложение 3) файл 16.2.html и папку images и скопируем их в какую-либо
папку локального диска. Страница 16.2.html содержит полностью работающий
слайдер, основанный на коде из разд. 15.3. В папке images находятся графи
ческие файлы.
2. Откроем копию страницы 16.2.html в текстовом редакторе и исправим селекторы
стилей, оформляющие слайдер (здесь и далее добавленный и исправленный код
выделен полужирным шрифтом, а удаленный — зачеркиванием):
section; nav.slider, section.slider-panel {
}
section.slider-panel {
}
section.slider-panel img {
}
.slider {
}
nav.slider a {
}
.slider a .active {
}
Сам набор «кнопок» у нас будет помечаться стилевым классом slider. Панель
для вывода изображений мы сделаем из тега <section> со стилевым классом
slider-panel.
У нас должен остаться лишь пустой тег <nav>, который станет базовым элемен
том для слайдера.
Теперь займемся контроллером класса slider. Переделки там будут значитель
ными, и мы рассмотрим их по частям.
4. Добавим в список параметров конструктора параметр config, которому будет
присвоен объект с исходными данными:
function Slider(buttonset, config) {
}
5. Добавим в конец кода конструктора выражение, задающее номер активной
«кнопки» по умолчанию (о, т. е. первая «кнопка»), если он явно не указан
в свойстве initial объекта с исходными данными:
function Slider(buttonset, config) {
if (!config.initial)
config.initial = 0;
}
6. Добавим выражение, привязывающее к базовому элементу стилевой класс
slider:
function Slider(buttonset, config) {
if (!config.initial)
config.initial = 0;
this.buttonset.classList.add(1slider1);
}
7. Добавим код, который создаст «кнопки» слайдера:
function Slider(buttonset, config) {
let button;
config.images.forEach((el, i) => {
button = document.createElement('a ');
button.href = el;
button.textContent = i + 1;
if (i = config.initial)
button.classList.add('active');
this.buttonset.appendChild (button) ;
>) ;
264 Часть III. HTML API и компонентное программирование
Р и с . 16.1. С л а й д е р , п р е о б р а з о в а н н ы й в ком п о н е н т
16.3. Замыкания
В составе кода нашего компонента-слайдера есть обычные функции: slider__
showlmage, Slider__getCurrentlndex И Slider__setCurrentlndex. СторОННИЙ разра
ботчик, применяющий библиотеку с нашим классом, по незнанию может вызвать
одну из них, что приведет к программной ошибке и даже нарушит работу слайдера.
Разработчик может задействовать и другую библиотеку, в которой также объявлены
функции: Slider__showlmage, Slider__getCurrentlndex И Slider__setCurrentlndex.
266 Часть III. HTML API и компонентное программирование
16.4. Упражнение.
Изолируем компонент в замыкании
Сделаем компонент слайдера slider, написанный в разд. 16.2, полностью изолиро
ванным от остального кода.
1. Откроем страницу 16.2.html и заключим код компонента slider (объявления кон
структора Slider, функций Slider__showlmage, Slider__getCurrentlndex, Slider__
setcurrentindex и вызов метода defineProperty) в замыкание (добавленный и
исправленный код здесь и далее выделен полужирным шрифтом):
(function О {
function Slider__showlmage(evt) {
}
function Slider(buttonset, config) {
}
function Slider__getCurrentlndex() {
}
function Slider__setcurrentindex(ind) {
}
Object.defineProperty( . . . );
>) 0 ;
2. Добавим в тело замыкания выражение, возвращающее в качестве результата
функцию-конструктор:
(function () {
Object.defineProperty( . . . );
return Slider;
}) () ;
3. Допишем перед замыканием фрагмент, который присвоит возвращенный конст
руктор глобальной константе slider:
const Slider = (function () {
}) О;
268 Часть III. HTML API и компонентное программирование
О Технология AJAX.
Э Серверные веб-приложения.
о Платформа РНР.
О Фронтенды и бэкенды.
Э Веб-службы.
О Серверные сообщения.
Урок 17
Технология AJAX
Реализация AJAX
Формат JSON
П ояснение
XML (extensible Markup Language, расширяемый язык разметки) — язык для кодиро
вания произвольных данных. Похож на HTML — XML-данные представляются в виде
набора вложенных друг в друга парных тегов и их атрибутов.
Ранее активно применялся для кодирования пересылаемых по Сети данных, но в се
редине 2000-х годов был вытеснен более компактным и простым в обработке форма
том JSON. В этой книге XML не рассматривается.
Наименование метода пересы лки данных указывается в виде строки ' GET1 ИЛИ ' POST'.
Для простой загрузки файла следует указать метод GET.
загружаемого файла также задается в виде строки. Третьим пара
интернет -адрес
метром передается логическая величина:
♦ false— будет выполнена синхронная загрузка, при которой исполнение кода
приостановится, пока запрошенный файл не будет загружен;
♦ true — будет выполнена асинхронная загрузка, при которой сразу после отправ
ки веб-серверу запроса на загрузку исполнение кода продолжится.
Применение синхронной загрузки упрощает программирование, однако страница
на момент выполнения загрузки перестает реагировать на действия пользователя.
При использовании асинхронной загрузки страница не «подвисает», но программи
рование несколько усложняется.
Тем не менее, в последнее время чаще всего применяется асинхронная загрузка. Ее
будем использовать и мы:
ajax.open('GET', */fragments/fr3.htmlf, true);
Примечание
Полный список всех возможных кодов статуса можно найти на странице
http://www.re8tapitutorial.ru/httpstatuscodes.html.
17.2. Упражнение.
Пишем сверхдинамический веб-сайт
Напишем сверхдинамический сайт, представляющий сведения о трех текстовых
редакторах, применяемых программистами.
Сверхдинамический веб-сайт — состоит из одной страницы, на которой вы
водятся различные фрагменты содержания, хранящиеся в отдельных
HTML-файлах. Загрузка и вывод файлов с фрагментами выполняется про
граммно при щелчках на гиперссылках.
Сверхдинамические сайты работают быстрее обычных, т. к. относительно неболь
шие файлы с HTML-фрагментами загружаются быстрее громоздких файлов с пол
ноценными веб-страницами.
Примечание
Для тестирования этого сайта понадобится установленный и работающий пакет хос
тинга ХАМРР. Процесс его установки описан в приложении 2.
17.5. Упражнение.
Загрузка и вывод и80Ы-данных
Напишем страницу, которая будет загружать ^(Ж -ф айл с данными о распростра
ненности различных языков программирования и выводить их в табличном виде.
1. В папке ЧТМвоигсев сопровождающего книгу электронного архива (см. приложе
ние 3) найдем файлы 17 5.html и 17.5)зоп и скопируем их в корневую папку
веб-сервера из пакета ХАМРР. Файл 17.5.html хранит страницу с необходимым
начальным кодом, а файл 17.5)зоп — непосредственно ЗвОМ-данные.
278 Часть IV. Взаимодействие с сервером
Во встроенном контейнере (теге <span>) с якорем year будет выведен ГОД, К KO-
торому относятся данные. В секции основного содержания таблицы (теге
<tbody>) с якорем output станут выводиться строки со сведениями о языках про
граммирования. Каждая строка включит три ячейки:
• название языка;
• уровень его популярности, выраженный числом;
• встроенный контейнер (<span>), создающий столбец импровизированной диа
граммы, ширина которого показывает уровень популярности языка.
4. Добавим в конце HTML-кода тег <script> с выражениями, получающими доступ
к элементам year, output и создающими объект AJAX:
<script type="text/javascript">
const year = document.getElementByld('year');
const output = document.getElementById('output');
const ajax = new XMLHttpRequest();
</script>
Урок 17. Технология AJAX 279
}
В свойстве level каждого языка хранится уровень его популярности в процен
тах. Эту величину мы можем использовать для указания ширины столбца диа
граммы.
6. Добавим код, который после загрузки файла 17.5.json вызовет функцию showData:
ajax.addEventListener('readystatechange', function () {
if (this.readyState == 4 && this.status == 200)
showData();
}) ;
7. И напишем код, загружающий этот файл:
ajах.open('GET', '17.5.json’, true);
ajax.send();
17.6. Упражнение.
Пишем компонент A JA X Lo ader
Чтобы упростить дальнейшую работу, реализуем код, выполняющий загрузку дан
ных по AJAX, в виде невидимого компонента AJAXLoader (написание компонентов
рассматривалось в уроке 16).
I Невидимый компонент — компонент, не выводящийся на экран.
Компонент AJAXLoader будет поддерживать следующие свойства и методы:
♦ g e t — статическое свойство, доступное только для чтения, хранит обозначение
метода GET;
♦ pos t — статическое свойство, доступное только для чтения, хранит обозначение
метода POST;
♦ load {<инт ернет -адрес>, <функция>) — метод, запускающий загрузку файла
С указанного интернет-адреса И вызывающий заданную функцию после его ус
пешной загрузки. Функция в качестве единственного параметра получит содер
жимое загруженного файла.
* * *
1. Создадим в корневой папке веб-сервера из пакета ХАМРР файл ajaxloader.js и за
пишем в него код, объявляющий замыкание:
const AJAXLoader = (function () {
ПО;
2. Вставим в замыкание объявление функции-конструктора (добавленный код
здесь и далее выделен полужирным шрифтом):
const AJAXLoader = (function () {
function AJAXLoader() {
this.ajax = new XMLHttpRequest() ;
this.ajax.addEventListener('readystatechange', dataLoaded);
>
}) ();
Урок 17. Технология AJAX 281
return AJAXLoader;
}) () ;
282 Часть IV. Взаимодействие с сервером
}
9. Исправим объявление функции showData следующим образом:
function showData(response) {
let tr, td, span;
let languages = JSON.parse(response);
}
10. Добавим в конец сценария код, создающий объект компонента AJAXLoader и за
пускающий загрузку файла:
const ajax = new AJAXLoader();
ajax.load(f17.5.json', showData);
Сделайте так, чтобы элемент можно было указывать либо в виде ссылки на него,
либо в виде якоря.
♦ Переделайте страницу 17.2.Мт1 так, чтобы находящийся в ее составе сценарий
использовал метод 1оас1НТМЬ компонента АаАХЬоас1ег.
♦ Переделайте написанную в уроке 14 страницу 14.5.Ь!т1 таким образом, чтобы
данные для вывода диаграммы загружались из файла 17.5.]8оп.
Урок 18
Серверные веб-приложения.
__________ Платформа РНР
Серверные веб-приложения
Введение в РНР
Серверные веб-страницы
Разработка РНР-приложений
Отправка данных РНР-приложениям
Рис. 18.2. Обновленная веб-страница, показывающая вместе с текущей датой еще и время года
18.3. Упражнение.
Пишем простейшую фотогалерею на РНР
Напишем на РНР простейшую фотогалерею, выводящую набор всех изображений,
хранящихся в папке. Для простоты сделаем так, чтобы фотогалерея обрабатывала
только файлы с расширением jpg.
290 Ч аст ь IV. В за и м о д е й с т в и е с сервером
if ($dh = opendir($path)) {
while (($file = readdir ($dh) ) ! = false) {
if ($file != && $file != {
echo '<a href=,M,>' ;
echo '<img src="' . $image s_folder . $file . ,n>';
echo '</a>';
)
)
}
?>
if ($dh = opendir($path)) {
while (($file = readdir($dh)) !== false){
}
292 Ч аст ь IV. В заи м о д е й с т в и е с сервером
с1озвс11г ($сЗЬ) ;
}
?>
Функция сЗ-оэесИг закрывает папку с указанным в параметре идентификатором.
6. Запустим встроенный в ХАМРР веб-сервер и перейдем в веб-обозревателе по
интернет-адресу ЬНр://1оса11ю$Ш8.3.р11р. Мы увидим страницу с фотогалереей
(рис. 18.3).
18.4. Упражнение.
Передаем данные методом GET
Если щелкнуть на любой картинке из нашей фотогалереи, ничего не произойдет.
Реализуем по щелчку просмотр полных редакций изображений на отдельных стра
ницах с выводом текстовых описаний (если они есть).
Для вывода страниц с изображениями напишем серверную страницу get.php. Имя
файла с выводимым изображением будет передаваться ей страницей index.php мето
дом G E T под именем image. Описания будут храниться в папке descriptions в тексто
вых файлах с теми же именами, что и у файлов с изображениями.
Для передачи методом GET отдельные величины:
♦ кодируются — в частности, пробелы преобразуются в символы + (плюс), а бук
вы кириллицы и знаки препинания — в их числовые коды;
♦ сводятся в пары вида:
<имя передаваемом велмчмны>=<ее значенме>\
♦ пары объединяются в одну строку и отделяются друг от друга амперсандами (&);
♦ строка добавляется в конец интернет-адреса целевой страницы и отделяется от
него вопросительным знаком (?).
Отдельные величины, передаваемые методом GET, называются GET-napa-
( метрами .
Вот пример передачи странице get.php методом GET параметра image со значением
*20190402114802 1 И параметра mode СОЗначением 'show*:
/get.php?image=20190402114802&mode=show
В РНР-коде все полученные GET-параметры хранятся в ассоциативном
массиве $_g e t , создаваемом самой платформой. Ключи элементов этого
массива совпадают с именами GET-параметров.
Вот пример извлечения значения GET-параметра image:
$fn = $_GET['image1];
}
294 Ч аст ь IV . В за и м о д е й с т в и е с сервером
if (filejaxists ($path)) {
$s = file_get_contents($path);
echo '<hl>' . $s . '</hl>*;
У рок 18. С е р в ер н ы е веб -пр и ло ж ени я. П л а т ф о р м а Р Н Р 295
} else
echo '<Ь1>Изображение</Ы>';
?>
Функция file exists возвращает true, если файл с указанным в параметре пу
тем существует. Функция file get contents считывает содержимое файла и воз
вращает его в виде строки.
Если текстовый файл с описанием отсутствует, на странице вводится заголовок
«Изображение».
6. Вставим в тег <section> с якорем photo РНР-код, выводящий само изображение:
<section id="photo">
<?php
$path = $images_folder . $fn . '.jpg';
echo '<img src="' . $path .
?>
</section>
7. Вставим в тег гиперссылки Назад РНР-код, задающий целевой интернет-адрес:
<р><а href="/#<?php echo $fn ?>">Назад</а></р>
Это интернет-адрес страницы с фотогалереей, к которому в качестве якоря
добавлено имя просматриваемого изображения. В результате при возврате на
страницу фотогалереи ее содержимое будет прокручено до элемента с указан
ным в адресе якорем — до гиперссылки с миниатюрой просматриваемого изо
бражения. Так мы реализуем корректный возврат на то же место страницы, с ко
торого ушли.
Запустим веб-сервер, откроем страницу фотогалереи, пощелкаем на разных миниа
тюрах и проверим, выводятся ли изображения и описания к ним (рис. 18.4).
Рис. 18.4. Щелчки на миниатюрах фотогалереи выводят полноразмерные изображения и описания к ним
296 Ч аст ь IV. В з аи м о д е й с т в и е с сервером
18.5. Упражнение.
Передаем данные методом POST
Постоянно любоваться на одни и те же картинки скоро надоест. Поэтому добавим
средства для загрузки в нашу фотогалерею новых изображений.
Этим займется серверная страница app.php, где мы создадим веб-форму с полем вы
бора графического файла и областью редактирования, куда будет заноситься опи
сание. РНР-код, сохраняющий выгруженный файл и описание к нему, мы для удоб
ства поместим в ту же страницу app.php. А пересылать данные из веб-формы станем
методом POST.
Веб-форма пересылает введенные в нее данные самостоятельно — для этого необ
ходимо лишь нажать кнопку отправки данных. Данные могут быть отправлены как
методом POST, так и методом GET.
B РНР-коде данные, переданные методом POST (POST-параметры), хра
I нятся в автоматически создаваемом ассоциативном массиве $ p o s t .
Выгруженные файлы в РНР хранятся в ассоциативном массиве $ files .
Каждый его элемент также представляет собой ассоциативный массив, хра
нящий различные сведения о полученном файле (в частности, «временное»
имя, размер и тип).
1. Создадим в корневой папке веб-сервера файл add.php с таким начальным HTML-
кодом:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<ti11е>Добавление изображения</1itle>
<link href="18.3.css" rel="stylesheet" type="text/css">
</head>
<body>
<Ь1>Добавление изображения</Ы>
<form action="/add.php" method="post"
enctype="multipart/form-data">
<р>Изображение:<br><input type="file"
name="file" accept=" .jpg" requiredx/p>
<р>Описание:<br><textarea
name="description"x/textareax/p>
<pxinput type="submit" name="submit"
уа1ие="Добавить "x/p>
</form>
<p><a href="/">Ha3afl</a></p>
</body>
</html>
Урок 18. С ер в ер н ы е в еб -пр и ло ж ени я. П л а т ф о р м а Р Н Р 297
В форме мы создали:
• поле выбора файла file, принимающее только файлы с расширением jpg и
обязательное к заполнению, — для указания файла с добавляемым изображе
нием;
• область редактирования description — для занесения описания;
• КНОПКУ ОТПраВКИ ДаН Н Ы Х submit.
В ним ание!
Сохранять выгруженный файл в PHP под его изначальным именем не рекоменду
ется — если в имени присутствуют символы кириллицы, они будут преобразованы
в нечитаемые последовательности символов. Это происходит из-за ошибки в про
граммном ядре платформы, не исправленной до сих пор.
$d = getdate(time());
$file_base_name = $d['year'] . $d['mon'] . $d['mday'] .
$d['hours'] . $d['minutes'] . $d['seconds'];
}
?>
Вызовом функции time мы получаем текущую временную отметку в стиле
UNIX, а «пропустив» ее через функцию getdate, вызванную без второго пара
метра, — ассоциативный массив с различными частями даты и времени. Далее
мы извлекаем элементы этого массива и составляем из них имя файла.
РНР временно сохраняет все выгруженные файлы в особой папке под «времен
ными» именами. «Временное» имя каждого файла хранится в элементе с клю
чом tmp name ассоциативного массива, содержащего сведения о файле. Все эти
файлы должны быть перемещены на место постоянного хранения.
5. Добавим код, формирующий имя для выгруженного файла с изображением и
сохраняющий его в папке images:
<?php
if (isset ($_POST ['submit']) ) {
header('Location: / ') ;
}
?>
Функция header вставляет в отправляемый клиенту ответ заданный заголовок.
Заголовок — находится в начале серверного ответа (или клиентского запро
са), содержит сведения о передаваемых данных или какое-либо указание
веб-обозревателю (веб-серверу).
Указание выполнить перенаправление по заданному интернет-адресу,, отправ
ляемое веб-обозревателю, записывается заголовком следующего формата:
Location: <целевой интернет-адрес>
После перенаправления выполнять остальной код серверной страницы ни к чему.
9. Добавим выражение, завершающее работу серверного приложения вызовом
функции exit:
<?php
if (isset($_POST[fsubmit1])) {
exit() ;
}
?>
300 Ч аст ь IV. В за и м о д е й с т в и е с сервером
</section>
{"data":
[{"path":"VimagesV201904Q2114732jpg","id":"20i90402114732"},
{"path":"VimagesV20190402114802jpg”."id":"20190402114802м},
{"path":"VimagesWO190402141454jpgVid" ;*20190402141454"},
{'"path":"Vmiag«V20i90510170602jpgVuJV'SO190510170602"},
{"pa&":'VimagesV20190510170618.jpgV'id":"20190510170618"},
{'path”:HVnnagesV20190510170647jpgM/,idu:,,20190510170647"},
{"path":"VimagesV20190510170709 jpg","id":"20190510170709"}]}
data.forEach((el) => {
а = document.createElement('a ');
img = document.createElement(1img');
img.src = el.path;
a .appendChild(img );
section.appendChild(a);
});
document.body.appendChild(section);
document.title = fФотогалерея';
window.scrollTo(0, 0);
}
function PGList() {
this.ajax = new AJAXLoader();
this.ajax.load(*get.php', show);
}
return PGList;
}) () ;
Обычно конструктор компонента принимает в качестве первого параметра базо
вый элемент. Но в нашем случае это не нужно, поскольку базовым элементом
всегда будет выступать секция тела страницы.
Конструктор сразу же создаст объект компонента AJAXLoader и запустит загрузку
данных, формируемых веб-службой get.php.
Функция show выполнится после получения данных, создаст заголовок страни
цы, список миниатюр, задаст для страницы название Фотогалерея и прокрутит
ее содержимое в самый верх.
5. Закончив компонент, приступим к работе над одной-единственной страницей
нашего сверхдинамического сайта — index.html — и создадим в корневой папке
файл index.html с таким кодом:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<link href="styles.css" rel="stylesheetM type=,,text/css">
<script src="ajaxloader.js" type="text/javascript"x/script>
<script src="pglist.js" type="text/javascript"x/script>
</head>
<body>
</body>
</html>
<script type="text/javascript">
let component = new PGList();
</script>
У ро к 19. Р а з р а б о т к а ф р о н т ен д ов и б экендов 305
Р и с . 19.2. С в е р х д и н а м и ч е с к а я ф о т о га л е р е я , о с н о в а н н а я на но вом п о д хо д е
и с о с т о я щ а я из ф р о н т е н д а и б экенд а
}
>
?>
2. На этом доработки бэкенда закончены. Приступим к написанию фронтенда
и, в частности, компонента, выводящего изображения.
Вывод изображения будет выполняться по щелчку на гиперссылке в списке
миниатюр (он В Ы В О Д И Т С Я компонентом PGList). Компоненту, который выведет
изображение, нужно передать его идентификатор. Будем передавать его через
интернет-адрес гиперссылки, записав в виде якоря такого формата:
get=<идентификатор изображения>
data.forEach((el) => {
a = document.createElement('a ');
a. href = '#get= ' + el. id;
img = document.createElement ('img ');
}) ;
}) 0 ;
У р о к 19. Р а з р а б о т к а ф р о н т ен д ов и бэкендов 307
Декоративная мельница, г.
Волжский.
Назад
При этом в предшествующем вызове метода open в первом параметре следует ука
зать строку 1POST*.
Отправить данные методом POST можно тремя способами.
</form>
Имя POSТ-параметра указывается В ВИДе СТрОКИ, зн ачен ие, еСЛИ Не ЯВЛЯеТСЯ СТрО
кой, будет преобразовано в строку;
♦ если нужно добавить файлы, применив другой формат вызова метода append:
append (<имя РОБТ-параметра>, <файл>[, <имя файла>])
Файл указывается в виде объекта класса File (см.разд. 13.1), имя файла задается
в виде строки. Если же оно не указано, отправляемый файл получит имя 'ЫоЬ';
♦ передать методу send объекта AJAX объект класса FomData с добавленными
в него данными.
Пример:
const description = document.getElementByld(description1);
const image = document.getElementByld(fimage1);
const fd = new FomData ();
fd.append('description', description.value);
fd.append(fimage1, image.files[0], image.files[0].name);
fd.append('operation', faddimage1);
const ajax = new XMLHttpRequest();
ajax.open(1POSTf, 'add.php', true);
ajax.send(fd);
$current_dir = dirname($_SERVER['SCRIPT_FILENAME']);
$images_path = $current_dir . $images_folder;
$descriptions_path = $current_dir . $descriptions_folder;
$d = getdate(time ());
$file_base_name = $d[fyear'] . $d['mon'] . $d['mday'] . $d[fhours’] .
$d[’minutes'] . $d['seconds'];
$image_file_name = $images_path . $file_base_name . '.jpg’;
move_uploaded_file ($_FILES ['file '] ['tmp_name ’], $image_file_name) ;
if (isset ($_POST [’description']) && !empty ($_POST ['description']) ) {
$description_file_name = $descriptions_path . $file_base_name .
'.txt';
$file = fopen($description_file_name, 'w');
fwrite($file, $_POST['description']);
fclose($file);
}
$output['data']['status'] = 1;
$json = json_encode($output);
echo $json;
?>
В самом конце мы отсылаем клиенту ответ — JSON-нотацию объекта со свойст
вом data, которое хранит объект со свойством status, содержащим число 1. Так
мы уведомим клиента, что операция была успешно выполнена.
2. Теперь— фронтенд. Условимся, что компонент, реализующий форму для за
грузки изображения (мы напишем его совсем скоро), будет выводиться на экран
при переходе ПО якорю add. И Сразу же добавим В КОД компонента PGList, выво
дящего список миниатюр, фрагмент, который создаст гиперссылку Добавить
изображение.
Откроем файл pglist.js и внесем в него следующие правки:
const PGList = (function () {
function show(response) {
document.body.appendChild(hi);
let p = document.createE lament ('p ') ;
let a = document.créateElement('a ');
a .href = '#add';
a .textContent = 'Добавить изображение';
p.appendChild(a);
document.body.appendChild(p);
let section = document.createElement('section');
section.id = 'photogallery';
let ат— img;
data.forEach((el) => {
У рок 19. Р а з р а б о т к а ф ро н т ен д о в и бэкендов 313
}) () ;
3. Теперь добавим в компонент AJAXLoader метод loadPOST, который отправит
методом POST данные веб-службе и загрузит результат ее работы. Первым
параметром он получит интернет-адрес веб-службы, вторым— отправляемые
данные, третьим — функцию, вызываемую после успешной загрузки, необяза
тельным четвертым — функцию, вызываемую в случае неудачи.
Итак, откроем файл ajaxloader.js и добавим в него объявление метода loadPOST:
const AJAXLoader = (function () {
};
return AJAXLoader;
}) () ;
4. Напишем компонент PGAdd, который выведет форму для выбора изображения,
загрузит изображение на сервер и в случае успеха выполнит перенаправление на
список миниатюр.
Создадим в корневой папке файл pgadd.js с кодом этого компонента:
const PGAdd = (function () {
let __ajax, __file, __description;
function redirect() {
location.hash =
}
function sendData(evt) {
const fd = new FormData();
fd.append('file’, __file.files[0], __file.files[0].name);
if (__description.value)
fd.append('description', description.value);
__ajax = new AJAXLoader();
__ajax.loadPOST('add.php', fd, redirect);
evt.preventDefault();
}
314 Ч аст ь IV. В з аи м о д е й с т в и е с сервером
function PGAdd() {
document.body.innérHTML = '';
let hi = document.createElement('hi');
hi.textContent = 'Добавление изображения';
document.body.appendChiId(hi);
let form = document.createElement('form');
let p = document.createElement('p');
let txt = document.createTextNode('Изображение');
p .appendChiId(txt);
let br = document.createElement('br*);
p.appendChiId(br);
__file = document.createElement('input');
__file.type = 'file';
__file.id = 'file';
__file.accept = '.jpg';
__file.required = true;
p.appendChiId( file);
form.appendChild(p);
p = document.createElement('p ');
txt = document.createTextNode('Описание');
p .appendChiId(txt);
br = document.createElement('br');
p.appendChiId(br);
__description = document.createElement('textarea');
__description.id = 'description';
p.appendChiId(__description);
form.appendChiId(p);
p = document.createElement('p');
let input = document.createElement('input');
input.type = 'submit';
input.value = 'Добавить';
p .appendChiId(input);
form.appendChiId(p);
document.body.appendChiId(form);
form.addEventListener('submit', sendData);
p = document.createElement('p');
let a = document.createElement('a');
a .href = '';
a .textContent = 'Назад';
p.appendChiId(a);
document.body.appendChiId(p);
document.title = 'Добавление изображения';
window.scrollTo(0, 0);
}
return PGAdd;
}) () ;
Урок 19. Р а з р а б о т к а ф р о н т ен д ов и бэкендов 315
function route() {
if (result = getRE.exec(hash))
component = new PGItem(result[1]);
else if (hash = '#add')
component = new PGAddO ;
else if (!hash)
component = new PGList();
}
</script>
Пример:
data: Это серверное сообщение. Всем привет!
Пример:
retry: 60000
data: Нам, веб-службам, торопиться некуда...
Пример:
data: Это ваша веб-служба,
id: 1
data: Здравствуйте!
id: 2
data: Не соскучились ?
id: 3
t h i s .e s .a d d E v e n t L i s t e n e r ('end', e n d ) ;
}
return PGList2;
} ) () ;
</head>
</html>
<script t y p e = " t e x t / j a v a s c r i p t ”>
function r o u t e () {
else if (lhash)
c o m ponent = n e w PGL±st2();
}
< /script>
★ Умножение 4*3
8 / Деление 10/3
% Остаток от деления 10 % 3
+ Сложение 1 + 2
7
- Вычитание 2-1
in
Проверка существования 'prop ' in obj
свойства
instanceof Принадлежность классу d instanceof Date
328 Прилож ение 1
(окончание)
== Равно X == у
2 9 • Условный (£ 1 а д ) ? х : у
Apache f riends
Щелкните /
на этой гиперссылке
Apache,
MySQL
FiieZilla FTP Server
Mercury Mail Server
Tomcat
Установите эти
9 0 Program languages флажки
□ Pert
S 0 Program languages
□ p h p M y A d m in
Webalner
Fake S endm aii
ХАМРР Instater
Next>
6. Сбросим в следующем диалоговом окне Bitnami for ХАМРР (рис. П2.5) флажок
Learn more about Bitnami for ХАМРР, чтобы установщик не вывел веб
страницу с дополнительными сведениями (сейчас они нам не нужны), и нажмем
кнопку Next.
332 Прилож ение 2
7. В следующем диалоговом окне Ready to Install (рис. П2.6) нажмем кнопку Next,
чтобы непосредственно начать установку пакета.
8. Подождем, пока установка завершится (рис. П2.7).
Рис. П2.11. Кнопка Start в строке Apache перечня компонентов в панели управления ХАМРР
Modules
S ervice M odule и о д Portes) A ctions
3560
Apache 80, 443 1 Stop 1 Admin Con fig Logs
100
Рис. П2.13. Кнопка Stop в строке Apache перечня компонентов в панели управления ХАМРР
Прим ечание
В меню также присутствует пункт PHP (php_error_log), но при его выборе выводится
сообщение о том, что файл с таким журналом отсутствует. Судя по всему, это про
граммная ошибка в пакете ХАМРР.
Start АФш [с »
Apache (httpdconf)
stm So Apache (httpd-ssUonf)
. ; <8rowse> {Apache}
<РЮ: 14560) <Browse> [PHP]
(PID- 2580)
<Brow*e> [phpMyAdmin]
opped
Рис. П2.15. Меню кнопки Config веб-сервера Apache — выбираем пункт РНР (php.ini)
338 Прилож ение 2
• <разм ер в мегабайтах>М
View. SS % . E3 Group by frame j □ Preserve log f£] Disable cache □ Offline No throttling
Рис. П2.18. Панель инструментов вкладки Network — устанавливаем флажок Disable cache
В ним ание!
Кеширование будет отключено, пока панель с инструментами разработчика присутст
вует на экране. Если закрыть ее, кеширование вновь активизируется, независимо от
состояния флажка Disable cache.
$ B
$_FILES 296 beforeprint 110, 187
$_GET 293 beforeunload 110, 187
$_POST 296 beginPath 227
$_SERVER 290 bezierCurveTo 232
blur 156, 157, 186, 187
body 123
BOM 185
A Boolean 67
abort 151, 209 bottom 130
abs 80 break 42, 47
acos 81 bubbles 118
acosh 81 button 114
activeElement 124
add 136,156
addColorStop 233
c
addEventListener 106, 116 call 256
afterprint 110, 187 cancellable 121
AJAX 271 canplay 150
alert 192 canplaythrough 150
altKey 114, 115 CanvasGradient 233
animationend 110, 115 CanvasPattem 236
AnimationEvent 115 CanvasRenderingContext2D 221
animationiteration 110,115 cbrt 80
animationName 115 ceil 80
animationstart 110, 115 change 157
append 310 characterSet 144
appendChild 142 charAt 70
apply 254 charCode 114
arc 230 charCodeAt 71
arcTo 230 checked 156
Arguments 82 checkValidity 166
Array 71 childElementCount 126
asin 81 children 126
asinh 81 classList 136
assign 191 className 136
atan 81 clear 212
atan2 81 clearData 214
atanh 81 clearlnterval 200
autocomplete 155, 164 clearRect 222
availHeight 192 clearTimeout 202
avail Width 192 click 109
344 П р е д м е т н ы й ука за т е л ь
FileList 207 H
FileReader 208, 210
files 156, 207,219 hash 191
fill 76, 227, 228 hashchange 110, 115, 187
fillRect 222 HashChangeEvent 115
fillStyle 223, 234 head 123
fillText 224 header 299
filter 74 height 130, 192, 221
find 74 host 190
findlndex 74 hostname 191
firstElementChild 126 href 190
floor 80 HTML API 199, 200
flush 318 HTMLAudioElement 148
focus 156, 157, 186, 187 HTMLBodyElement 123
FocusEvent 157 HTMLCanvasElement 221
focusin 157 HTMLCollection 124
focusout 157 HTMLDocument 123
font 224 HTMLElement 125
fopen 299 HTMLFormElement 164
forEach 74 HTMLHeadElement 123
form 155 HTMLImageElement 147
FormData 309 HTMLInputElement 166, 167
forms 124 HTMLVideoElement 148
fromCharCode 71
Function 67
l
fwrite 299
ignoreCase 181
G images 123
in 86
getBoundingClientRect 130 includes 69, 73
getContext 221 index 156
getData216 indexOf 70, 73
getdate 288 Infinity 22
getDate 79 innerHeight 185
getDay 79 innerHTML 137
getElementByld 124 innerText 129, 138
getElementsByClassName 124 innerWidth 185
getElementsByName 124 input 157
getElementsByTagName 124 insertAdjacentElement 142
getFullYear 79 insertAdjacentHTML 138
getHours 79 insertAdjacentText 139
getltem 212 insertBefore 142
getLineDash 230 instanceof 86
getMilliseconds 79 invalid 157 '
getMinutes 79 isArray 72
getMonth 79 isEqualNode 130
getSeconds 79 isFinite 61
GET-napaMeTp 293 islnteger 67
global 181 isNaN 61
globalAlpha 239 isSameNode 130
globalCompositeOperation 239 isset 297
346 П р е д м е т н ы й у ка за т е л ь
lastElementChild 126
lastEventld 320
N
lastlndex 179 name 97, 207
lastlndexOf 70, 73 NaN 22
lastModified 144 naturalHeight 147
lastModifiedDate 207 natural Width 147
left 130 networkState 149
length 69,71,82, 156, 164 new 78
lengthComputable 209 newURL 115
let 25,27,41 nextElementSibling 126
lineCap 229 NodeList 124
lineJoin 229 null 83
lineTo 228 Number 67
lineWidth 229
links 124
LN10 80 o
LN2 80
load 110, 147, 149, 186, 208, 209 Object 82
loaded 209 offsetHeight 129
loadeddata 150 ofFsetLeft 128
loadedmetadata 150 offsetParent 128
loadend 209 ofFsetTop 128
loadstart 150, 209 ofFsetWidth 128
localeCompare 77 ofFsetX 114
localStorage 212 ofFsetY 114
Location 190 oldURL 115
log 81, 89 open 272, 319
LOG2E 80 opendir 291
options 156
origin 190
M outerHeight 185
map 75 outerWidth 185
match 179,180
Math 80
max 80
p
MAX VALUE 68 pagehide 110,115, 187
measureText 224 pageshow 110, 115, 186
П р ед м ет н ы й у к а за т е л ь 347
и w
undefined 29 waiting 150
unlink 300 wheel 109, 114
unshift 72 WheelEvent 114
URIError 98 which 114, 115
URL 144 width 130, 192, 221,224
willValidate 167
v Window 123, 185
Worker 202
valid 167 write 139
validationMessage 166 writeln 139
validity 167
ValidityState 167
value 155
X
valueMissing 167 X130
var 27, 41 XAMPP 329
videoHeight 148 0 панель управления 334
videoWidth 148 XML 271
volume 148 XMLHttpRequest 272
volumechange 150
Y
у 130
A Веб-приложение
О клиентское 160
Атрибут тега О серверное 160, 285
0 draggable 213 Веб-сайт: сверхдинамический 274
0 height 221 Веб-служба 302
0 id 104 Веб-страница
0 pattern 182 О по умолчанию 292
0 script 35 О серверная 289
Веб-сценарий 35
0 src 60
О внешний 60
0 width 221
О внутренний 35
Возврат результата 20
Б Возобновление 95
Временная отметка 78
Библиотека 60 О в стиле ЦМХ 287
Блок 40 Выражение 35
Бэкенд 302 О блочное 40
О выбора 41
в О условное 38
О условное в сокращенной форме 39
Валидация 165 0 условное множественное 39
Вариант 175 Выход из функции 94
350 П р е д м е т н ы й у ка за т е л ь
г Конкатенация 23
Консоль 17, 89
Геттер 251 Константа 27
Градиент 233 Конструктор 245
О линейный 233 Контекст исполнения 127
О радиальный 235 Кривая Безье 231
Графическая закраска 236 О квадратическая 231
Графический контекст 221 О кубическая 231
Группа 177
л
Д Лайтбокс 258
Декремент 28 Литерал
О регулярного выражения 171
ж О строковый 22, 287
Лог 336
Журнал 336 Логическое
0 И 24
0 ИЛИ 24, 56
3 0 НЕ 24
Заголовок 299 0 отрицание 24
Замыкание 266 0 сложение 24, 56
Застревание в кеше 338 0 умножение 24
и м
Имя Маршрутизация 309
О класса 66 Маска 240
О переменной 24, 287 Массив 61
О события 105 0 ассоциативный 288
0 функции 51 0 вложенный 63
Индекс 61 0 внешний 63
Инициализация 261 0 размер 61
Инкремент 28 0 элемент 61
Инспектор ООМ 95 Межпоточное сообщение 203
Исключение 96 Метасимвол 173
0 обработка 97 Метод 66
0 обработчик 97 0 переопределение 255
0 статический 67, 257
к Модификатор 171
Квантификатор 175
Кеш 338
Н
Класс 66 Наследование 83, 253
0 базовый 83 Нулевая ссылка 83
0 производный 83
Ключ 288 о
Ключевая точка 233
Коллекция 82 Обработчик события 105, 107, 139
Комментарий 48 0 по умолчанию 119
Компонент 261 0 привязка 106, 108
0 невидимый 280 0 удаление 108
П р ед м ет н ы й у к а за т е л ь 351
х
Хеш 288
Холст 221
J a v a S c rip t
/ûjfokoirjjAfl ЦаЩйн^МК
Дронов Владимир Александрович, профессиональный про
граммист, писатель и журналист, работает с компьютерами
с 1987 года. Автор более 30 популярных компьютерных книг, в том
числе «HTML и CSS: 25 уроков для начинающих», «Django 2.1.
Практика создания веб-сайтов на Python», «HTML, JavaScript,
PHP и MySQL. Джентльменский набор Web-мастера», «Python 3.
Самое необходимое», «Python 3 и PyQt 5. Разработка прило
жений», «Laravel. Быстрая разработка современных динамиче
ских Web-сайтов на РНР, MySQL, HTML и CSS», книг по продуктам Adobe Flash
и Adobe Dreamweaver различных версий. Его статьи публикуются в журналах
«Мир ПК» и «Интерфейс» (Израиль) и интернет-порталах «IZ City» и «TheVista.ru».
Простым языком, кратко, наглядно, в картинках рассказано о программировании
веб-сценариев на языке JavaScript. В книге 20 иллюстрированных уроков,
40 практических упражнений и более 70 заданий для самостоятельной работы.
Вы узнаете, как
JavaScript
в картинках и упражнениях
• обрабатывать события;
• добавлять элементы на веб-страницу;
• создать свой видеопроигрыватель;
• проверить правильность введения данных
в веб-форму;
• выполнять длительные вычисления в фоновом çbhv®
потоке;
• нарисовать график на веб-странице;
191036, Санкт-Петербург,
• объявить свой класс; Гончарная ул„ 20
• написать компонент; Тел.: (812) 717-10-50,
339-54-17, 339-54-28
• загрузить данные с сервера;
E-mail: [email protected]
• программировать фронтенды и бэкенды; Internet: www.bhv.ru
• отлаживать веб-сценарии. ISBN 978-5-9775-6589-9