Вы находитесь на странице: 1из 586

Эрик

n
Фримен
*
Элизабет
о *
Робсон
„ * V v 4\
--------------------------------------------------------------------------------------------------

Изучаем гт
программирование на

HTMlS Учебное руководство


по созданию веб-приложений
с использованием JavaScript

Раскройте
секреты гуру HTML5

«Загрузите* HTML5
Узнайте, почему все, и JavaScript
что вашим друзьям прямо в свой мозг
известно о видео,
может оказаться
ошибочным

Научитесь
избегать
досадных Изучите
проблем подводные камни,
с браузерной связанные
поддержкой I * с браузерами

О REILLY
Отзывы о книге

«HTML5 является самой актуальной технологией создания веб-сайтов. М ногие разработчики го­
р ят ж еланием воспользоваться ею для создания гибких, насы щ енны х медиа-сайтов, с которы м и
также будет удобно работать на нланш етны х комнью терах и смартфонах. К нига „Изучаем програм­
мирование на H T M L 5“ — наилучший и самый увлекательны й снособ освоить эту восхитительную
технологию . О чень рекомендую».
— М эр иэи и М арк, старш ий ви ц е-и р ези деи т ио техн ол оги я м в B lu e N ile Inc.

«Являясь н ростой, инф орм ати вн ой и увлекательной, книга „Изучаем программирование на H T M L 5 “


нредставляет собой настольное руководство для всех, кто ж елает изучить HTM L5 или нросто р е­
шил освеж ить свои знания но данной теме. С ерия „Head First“помотает мне ноддерж ивать знания
на актуальном технологическом уровне, нозволяя более эф ф екти вн о унравлять нроектам и и ока­
зы вать содействие моим разработчикам».
— Тодд Гуилл, м ен ед ж ер п р оек тов, A llR ecip es.co m

«Это вам не устареваю щ ий DHTML! „Изучаем программирование на H TM L5 “ рисует многообещ а­


ющую и онтимистичную картину будущего В сем ирной наутины через нризму HTML5, давая вам
шанс но лучить туда билет. Если вы ищ ете нодробное, нанисанное достунным язы ком и н орой до­
вольно забавное руководство но HTM L5, данная книга то, что вам нужно».
— М эиии О тто, веб-разр аботч ик и креативщ ик

«Авторы данной книги нонали в точку — навыки работы с JavaScript являю тся ключом к HTML5.
Даже если вам никогда не доводилось нисать JavaScript-HporpaMMbi, эта книга номож ет быстро
во всем разобраться благодаря наличию увлекательных и нрактичны х нримеров».
— Д эв и д П ауэрс, автор кииги «РНР. С оздан и е ди н ам и ч еск и х страниц» (РН Р Solutions:
D ynam ic Web D esig n M ade Easy)
О других книгах серии Head First

«Будьте осторож ны . Если кто-то из вас лю бит читать неред сном, то лучше отлож ите чтение книги
„Изучаем HTM L, XH TM L и CSS“ (H ead First HTM L with CSS & XHTM L) на дневное время. Эта книга
будоражит мозг».
— П оулии М акнамара, Ц ен т р н ов ы х техн ол оги й и обр азов ан и я,
Ф рибур ск и й ун и в ерси тет, Ш в ей ц ар и я

«Книга „Изучаем HTML, XH TM L и CSS“ нредставляет собой тщ ательно п роработанное соврем ен­
ное руководство но дальновидным нрактикам в области разм етки и представления веб-страниц.
А вторы нредвидят, какие моменты могут вызвать у читателя замеш ательство, и своеврем енно
разъясняю т их. И снользованны й нодход, в основе которого леж ат обилие наглядных нрим еров
и последовательность излож ения, является онтимальны м для читателя: он будет вносить неболь­
шие изм енения и наблюдать итоговы й эф ф ект в браузере, что нозволит разобраться в назначении
каждого нового элемента».
— Д эи и и Гудмеи, автор книги «Д инам ический HTML: п о д р о б н о е руководство»
(D ynam ic HTML: T h e D efin itive G uide)

«Книга „Изучаем HTM L, XH TM L и CSS“с самого начала создает у читателя ощущение, что весь нро-
цесс обучения окаж ется нросты м и увлекательным. О своение HTM L нри нравильном объяснении
не сложнее изучения основ родного язы ка, н ри этом авторы нроделали отличную работу и нриво-
дят наглядные нрим еры но каждой конценции».
— М айк Д эв и д со н , п р ези д ен т и и сп ол н и тел ьн ы й ди р ек т ор N ew svin e, Inc

«Вместо излож ения материала в стиле традиционны х учебников „Программируем для iPhone и iPad“
нредлагает читателю живую, увлекательную и даже нриятную методику обучения програм м ирова­
нию для iOS. М атериал но добран умело и качественно: в книге рассматриваю тся многие клю чевые
технологии, вклю чая Core Data, и даже такие важные аснекты , как проекти рован ие интерф ейса.
И где еще можно нрочитать, как UlWebView и UITextField беседуют у камина?»
— Ш о п М ер ф и , п р оек ти р овщ и к и р азр аботч и к п р и л ож ен и й дл я iO S

«Книга „Программируем для iPhone и iPad“ объясняет н ринцины разработки н рилож ений iOS с са­
мого начала. О сновны е и зм енения но сравнению с нервы м изданием относятся к iOS 4, Xcode 4
и нанисанием н рилож ений для iPad. Благодаря нош аговым онисаниям с визуальным стилем из­
лож ения м атериала эта книга становится отличны м средством изучения нрограм м ирования для
iP hone и iPad во всех аснектах, от нростейш их до нетривиальных».
— Ри ч Р о зе и , програм м ист и соавтор кииги Mac OS X for U n ix G eeks

«В отличие от многих невразумительных книг но программированию , насы щ енны х техническим


ж аргоном, руководства серии Head First jQuery номогаю т новичкам создавать их н ервы е страницы
jQ u ery на нростом и достунном уровне».
— Л и и дси Скурас, ю р и ст и ирограммист-самоучка
HTML5
Programming
W ouldnt it be dreamy if th ere
was an HTM L5 book th a t didn't
assume you knew what the DOM,
events, and APIs were, all by page
three? It's probably ju st a fantasy

Ryan Benedetti
Ronan Cranley

O ’REILLY
Beijing • Cambridge • Koln • Sebastopol • Tokyo
Изучаем программирование на
Создание

HTML5 Как было бы здорово, если бы


существовала книга о HTML5,
веб-приложений
с использованием
JavaScript

в которой не предполагается заранее,


что читателю знакомы такие понятия,
как объектная модель документа (DOM),
события и API-интерфейсы.
Об этом можно лишь мечтать...

Эрик Фримен
Элизабет Робсон

Москва ■Санкт-Петербург ■Нижний Новгород ■Воронеж


Ростов-на-Дону - Екатеринбург - Самара - Новосибирск
Киев ■Харьков ■Минск
2013
ББК 32.988-02-018.1
УДК 004.43
Ф88

Фримен Э., Робсон Э.


Ф88 Изучаем программирование на HTML5. — СПб.: Питер, 2013. — 640 с.: ил.
ISBN 978-5-459-00952-1
Хотите создавать динамичные, интерактивные, насыщенные данными веб-страницы? Почему бы не использовать ПТМЬ5 для
создания полнофункциональных веб-приложений? И почему бы не делать это с помощью современных методик, которые так же
легко применимы к вашему настольному браузеру, как и к мобильным устройствам? Вам, конечно же, захочется использовать такие
новейшие ПТМЬ5-технологии, как API-интерфейс Geolocation, элемент video, 2В-рисование, API-интерфейсы Web Storage и Web
Workers и т. д. Пе так ли?
С помощью данной книги вы научитесь создавать веб-нриложения с использованием современных стандартов и нередовых методик
завтрашнего дня. Вы изучите основы новых API-интерфейсов ПТМЬ5 и узнаете, как они взаимодействуют со страницами и приво­
дятся в движение JavaScript-кодом, а также как использовать их для создания веб-приложений, которые впечатлят ваше начальство
и изумят друзей.

ББК 32.988-02-018.1
УДК 004.43

Права на издание получены по соглашению с O ’Reilly. Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой
бы то ни было форме без письменного разрешения владельцев авторских прав.

Информация, содержащаяся в данной книге, получена из источников, рассматриваемых издательством как надежные. Тем не менее, имея в виду
возможные человеческие или технические ошибки, издательство не может гарантировать абсолютную точность и полноту приводимых сведений
и не несет ответственности за возможные ошибки, связанные с использованием книги.

© Authorized Russian translation of the English edition of Head First HTM L5 Programming,
ISBN 9781449390549 © 2011 Eric Freeman and Elisabeth Robson. This translation is published
and sold by permission of O'Reilly Media, Inc., the owner of all rights to publish and sell the same.
ISBN 978-1449390549 (англ.) © 2011 Eric Freeman and Elisabeth Robson. This translation is published and sold by permission
of O'Reilly Media, Inc., the owner of all rights to publish and sell the same.
ISBN 978-5-459-00952-1 © Перевод на русский язык О О О Издательство «Питер», 2013
© Издание на русском языке, оформление О О О Издательство «Питер», 2013
П о с в я щ а е т с я С т и в у Д ж о б с у , б л а го д а р я к о т о р о м у п о ­
п у л я р н о с т ь H T M L 5 д о с т и гл а т а к и х в ы со т, ч т о д а н н а я
к н и г а д о л ж н а р а з о й т и с ь о г р о м н ы м т и р а ж о м .. .

И ещ е раз п о св я щ а е тся С ти в у Д ж о б су, п о то м у ч т о о н


на ш ге р о й .
об авторах
Р о 5 со н

Эри к Ф р и м е н

Эрик — один из основонолож ников серии «Head Э лизабет совмещ ает деятельность п роекти ров­
First». К эти С иерра так характеризует Эрика: щ ика программного обеспечения, нисателя и
«Один из редких людей, которы е одинаково хоро­ инструктора. О на увлеклась технологиям и еще
шо владею т язы ком, практическим и навыками и во врем я учебы в Йельском университете, где
знаниям и культуры в разны х областях, будь то сфе­ нолучила стенень магистра ком пью терны х наук
ра, в которой орудует хакер-хинстер, работает кор­ и занималась разработкой язы ка нараллельного
п орати вн ы й вице-нрезидент, нроектировщ ик или визуального програм м ирования и нрограм м ной
экснерт-аналитик». архитектуры.
В п роф ессиональном нлане Эрик недавно нодош ел Элизабет увлеклась созданием веб-нрилож ений
к ночти десятилетней отметке в качестве долж­ на самом раннем этане разви тия И нтернета.
ностного лица в медиа-комнании: он занимает ноет О на участвовала в создании заслужившего нри-
главного технического д иректора Disney O nline
знание веб-сайта T he Ada Project, которы й стал
& Disney.com в Walt Disney Company. В настоящ ее
одним из нервы х ресурсов, нризванны х номочь
врем я Эрик занят W ickedlySmart — стартаном, ко­
женщ инам, заняты м в сф ере инф орм атики. О на
то р ы й он организовал совместно с Элизабет.
является одним из основателей W ickedlySmart —
По образованию Эрик —учены й в области компью­ образовательного онлайн-ресурса, носвящ енно-
терны х наук, и ему довелось заниматься научными го веб-технологиям, на котором нредставлены
исследованиями с таким светилом, как Дэвид Ге- ее книги, статьи, видео и нрочее. Ранее, когда
лерн тер, во врем я его работы в качестве доктора Элизабет была руководителем снециальны х
ф и лософ и и в Йельском университете. нроектов в O ’Reilly M edia, она лично нроводила
В свободное врем я Эрик серьезно увлекается музы­ семинары и онлайн-лекции на разны е техн и че­
кой; результат носледнего нроекта, над которы м ские темы, создавала образовательны е ресурсы.
он работал совместно с н ионером музыкального До сотрудничества с O ’Reilly M edia Элизабет
стиля «эмбиент» Стивом Роачем, им еется в элек­ довелось ноработать в Walt Disney Company, где
тронном магазине нрилож ени й для iP hone и назы ­ она отвечала за руководство исследованиями
вается Im m ersion Station. и разработкам и в сф ере ц иф рового медиа.
П иш ите Эрику но адресу eric@ w ickedlysm art.com , П иш ите Элизабет на beth@ w ickedlysm art.com ,
а также носетите его сайт h t t p : / / ericfreem an.com н осетите ее блог h t t p : / / elisabethrobson.com

8
содержание

(У д е р ж а н и е (с в о д к а )

В ведение 21
1 Знакомство с HTM L5. Добро пожаловать в Вебвилль 35
2 Знакомство с JavaScript и объектной моделью
документа (D O M ). Немного кода 69
3 События, обработчики и весь этот джаз.
Немного взаимодействия 119
4 Функции и объекты JavaScript. СерьезныйJavaScript 147
5 С оздание HTM L-страниц с поддерж кой оп р едел ения
м естополож ения. API-интерфейс Geolocation 199
6 О бщ ение с веб-службами. Приложения-экстраверты 247
7 Раскрываем в себ е художника. Элемент canvas 315
8 Т елевидение для нового поколения. Элемент video...
и наш особый гость - элемент canvas 383
9 Сохраняем данны е локально. API-интерфейс Web Storage 447
10 П рим еняем JavaScript на деле: API-интерфейс Web Workers 507
П ри лож ен ие. Десять важных тем (которые мы не рассмотрели) 565

(^ « д ер ж ан и е (н а с т о я щ е е )

Введение
Ваш мозг думает о программировании на HTML5. Вы сидите за
книгой и пытаетесь что-нибудь выучить, но ваш мозг считает, что вся
эта писанина не нужна. Ваш мозг говорит: «Выгляни в окно! На свете
есть более важные вещи, например сноуборд». Так как убедить свой
мозг в том, что знание HTML5 и JavaScript не менее важно для вас?

Для кого написана эта книга? 22


Мы знаем, о чем вы думаете 23
И мы знаем, о чем думает ваш мозг 23
М етапознание: учимся учиться 25
Технические р ецензенты 30
Б лагодарности 31
От издательства 33

9
зн аком ство с U IM L 5

Добро пожаловать в Вебвилль


HTML стремительно развивается. Да, изначально HTML представлял
собой простой язык разметки, однако с выходом новых версий он посте­
пенно наращивал мускулы. В настоящее время мы располагаем версией
HTML, заточенной под создание полноценных веб-приложений с поддерж­
кой localStorage, 20-рисования, автономного режима работы, сокетов, по­
токов и т. д. История развития HTML не всегда была радужной: она полна
драматизма (об этом мы поговорим позже), а в этой главе мы для начала
совершим увеселительный тур по Вебвиллю, чтобы вы могли разобраться
во всем, что вкладывается в понятие «HTML5». Поэтому запрыгивайте к
нам — мы отправляемся в Вебвилль, где за 3,8 страницы (ровно) пройдем
путь от исходной точки до HTML5.

П ер ехо д и те на HTML5 СЕГОДНЯ! Зачем ждать? 36


П редставляем вам наш новый Н Т М Ь б-м одернизатор.
О бновите свой HTM L прямо сейчас 38
Вы ближ е к НТМ Ьб-разметке, чем думаете! 41
В стречаем HTML5: П ризнания новой версии HTM L 45
П росим встать НАСТОЯЩ ЕГО HTM L5... 46
Как на самом деле работает HTM L5... 48
Кто и что делает? 50
Ваша первая миссия: разведка в стане браузеров 51
Ч то м ож но сделать с помощ ью JavaScript 56
Пиш ем серьезны й JavaScript 59
Пиш ем серьезны й JavaScript: проверка ваших ответов 60
Ключевые моменты 65
содержание

знаком ство с JaVa^crij=>t и объектной м°ДеЛь1° Документа (J)Q]^)

Немного кода
Благодаря JavaScript вы откроете для себя нечто новое. Вы уже все
знаете о HTML-разметке (иначе называемой структурой) и CSS-стиле (также из­
вестном как представление), однако вам недостает знаний о JavaScript (или, как
еще говорят, о поведении). Если ваш багаж знаний ограничивается лишь струк­
турой и представлением, то вы, конечно же, сможете создавать прекрасно вы­
глядящие страницы, однако они будут лишь простыми страницами. Но если вы
добавите поведение, прибегнув к JavaScript, то сможете обеспечить для своих
пользователей интерактивное взаимодействие; либо, что еще лучше, вы смо­
жете создавать роскошные веб-приложения. Добавьте в свой инструментарий
веб-разработчика наиболее интересные и универсальные знания о JavaScript
и программировании!

Как работает JavaScript 70


Ч то мож но сделать с помощью JavaScript? 71
О бъявление п ер ем ен н ой 72
Как присваивать им ена перем енны м 74
С ерьезн ое програм м ирование 74
Вы ражения 77
Н Т М ЬЪ -
М ногократное вы полнение одного и того ж е... 80
П ринятие реш ений с использованием JavaScript 83
с м а р сА>
П ринятие дополнительны х реш ений... и добавление
J a v a S c r ip t - перехваты вающ его блока 84
Как и куда добавлять JavaScript в свои х страницах 87
r В еп ери KaKjavaScript взаим одействует с вашей страницей 88
,чес коерУк° ' Рецепт приготовления со б ствен н ой объектной модели
документа (DOM ) 89
Я Р » * * * ° У**4*
яЦИИ
0ОДСТко М ^ н " Ка1 П ер вое испы тание объектной м одели документа (DOM ) 90
НИ*0 ,* е н Н«° 0т Нельзя начинать взаимодействовать с DOM ,
» * ОСГгТэфФе^ и пока веб-страница не загрузилась полностью 98
Для чего ещ е хорош о п одходи т DOM 100
в О»1*
Нельзя ли снова поговорить о JavaScript, или как
осущ ествляется сохр ан ен и е м нож ественны х
значений при использовании JavaScript 101
Как создать массив 101
Phrase-O-Matic 105
Ключевые моменты 109

11
собьшшя, обработчики и Весь эщощ джа£

Немного взаимодействия
Вам все еще не удается соприкоснуться с пользователем. Вы изу­
чили основы JavaScript, однако могут ли ваши веб-страницы взаимодей­
ствовать с пользователями? Когда страницы откликаются на вводимые
пользователем данные, они уже являются не простыми документами,
а живыми, реагирующими приложениями. Из этой главы вы узнаете, как
обрабатывать одну из форм ввода данных пользователем (извините за
каламбур) и привязывать старомодный HTML-элемент < f o r m > к совре­
менному коду. Это может показаться необычным, однако такой подход
также эффективен. Пристегните ремни, поскольку наше путешествие по
данной главе будет проходить на большой скорости: путь от простого
приложения до интерактивного мы пройдем очень быстро.

П риготовьтесь к встрече с W ebville Tunes 120


Приступаем... 121
Когда я нажимаю кнопку A dd Song (Добавить п есн ю ),
ничего не п р ои сходи т 122
О бработка собы тий 123
Составляем план... 124
П олучение доступа к кнопке A dd Song (Добавить песню ) 124
Задание обработчика собы тий click для кнопки 125
Более пристальный взгляд на происш едш ее... 126
И звлечение названия песни 128
Как добавить песню на страницу? 131
Как создать новый элем ент 133
Д обавлени е элем ента в DOM 134
С оединяем все воеди но... 135
...и проводим тест-драйв 135
О бзор того, что мы только что сделали 136
Как добавить приготовленны й код... 139
И нтегрирование пр иготовленного кода 140
Ключевые моменты 142
содержание

объекты и ^ункЦии JavaScript

Серьезный JavaScript
Можете ли вы уже назвать себя создателем сценариев? Впол­
не возможно, поскольку вы уже многое знаете о JavaScript, однако кто
захочет быть простым создателем сценариев, когда можно быть про­
граммистом? Пора проявить серьезность и поднять планку — настало
время познакомиться с функциями и объектами. Они являются клю­
чом к написанию более эффективного, хорошо организованного и лег­
кого в сопровождении кода. Функции и объекты активно используются
наряду с API-интерфейсами HTML5 JavaScript, поэтому чем лучше вы
будете в них разбираться, тем быстрее сможете освоиться с тем или
иным новым API-интерфейсом и начать его использовать. Пристегни­
тесь, поскольку эта глава потребует вашего всецелого внимания...

Расш иряем ваш словарны й запас 148


Как добавить свои собственны е функции 149
Как работает функция 150
Локальные и глобальные перем енны е 157
Функции ещ е являются и значениям и 162
Ч то м ож но сделать посредством функций как значений? 163
Как создать объект на JavaScript? 166
Ч то м ож но сделать с объектами 167
П оговорим о передаче объектов функциям 170
Наш следующ ий сеанс состоится в... 174
Объекты также могут обладать поведением ... 176
В озвращ аемся к прилож ению W ebville C inem a... 177
Д обавлени е ключевого слова this 179
Как создать конструктор 181
Воспользуемся нашим конструктором 182

Как на самом деле работает t h i s ? 183


Сразу ж е проведем тест-драйв нашего конструктора 187
Ч то такое объект window? 189
Более пристальный взгляд на w indow .onload 190
Еще один взгляд на объект d o cu m en t 191
Более пристальный взгляд на d o cu m en t.getE lem en tB yld 191
Еще один объект, о котором нужно знать: объект элем ента 192
Ключевые моменты 194

13
содержание

API-интерфейс Geolocation
Куда бы вы ни отправились, вас можно найти. Порой бывает так, что знание
того, где вы находитесь, имеет существенное значение (особенно для веб-приложений).
Из этой главы вы узнаете, как создавать веб-страницы с поддержкой определения ме­
стоположения. Иногда вы сможете определять местонахождение своих пользователей
вплоть до угла, на котором они стоят, а иногда вам будет удаваться определить лишь
район города, в котором они находятся (однако вы по-прежнему будете знать, какой это
город!). Время от времени вы вообще не сможете получить хоть какую-нибудь информа­
цию о местоположении пользователей в силу технических причин или просто потому, что
им не нравится ваше чрезмерное любопытство. Да, представьте себе! Так или иначе, но
в данной главе мы рассмотрим API-интерфейс JavaScript под названием Geolocation. Бе­
рите свое самое лучшее устройство с поддержкой определения местоположения (даже
если это будет ваш настольный компьютер), и давайте приступим к работе.

М естоп ол ож ен и е, м естоп ол ож ен и е... 200


Ш ирота и долгота... 201
Как API-ин терф ейс G eolocation опр едел яет
м естоп ол ож ен и е пользователя 202
Так где ж е вы находитесь? 206
Как все это работает 210
Раскрываем наше тайное убеж ищ е... 213

чv Н аписание кода для опр едел ения расстояния


О тобр аж ение вашего м естополож ения на карте
Как добавить карту к странице
215
216
217
Прикалываем булавку на карту... 220
П р оч ие интересны е вещ и, которы е мож но сделать
с использованием API-ин терф ейса G oogle Maps 222
f
г
М ож ем ли мы поговорить о точности? 225
“W herever you g o , there you are” 226
Приступаем к созданию прилож ения 227
Д орабаты ваем наш стары й код... 228
П ора отправляться в путь! 230
Параметр p osition O p tion s... 232
Мир парам етров tim eo u t и m axim um A ge... 233
Ш лифуем наше прилож ение! 238
И нтеграция наш ей новой функции 239
Ключевые моменты 241

14
содержание

общение с веб—сл уж б а м и

Приложения-экстраверты
Что-то вы слишком засиделись на своей странице. Настало время немного
пообщаться с веб-службами с целью сбора данных и последующего возврата этой
информации, что даст вам возможность создавать более эффективные веб-ресурсы,
которые объединяют собираемые данные. Это важный момент в написании современ­
ных НТМ1_5-приложений, и чтобы успешно им заниматься, вам необходимо знать, как
происходит общение с веб-службами. Об этом мы и поговорим, а также научимся вне­
дрять данные от веб-служб в свои страницы. Усвоив изложенный материал, вы сможе­
те обращаться и взаимодействовать с любой веб-службой по своему выбору. Мы даже
расскажем вам о новомодном жаргоне, которым следует пользоваться при общении с
веб-службами. Вы познакомитесь с некоторыми новыми API-интерфейсами — так на­
зываемыми коммуникационными API-интерфейсами..

К омпании M ighty G um ball требуется веб-прилож ение 248


П о д р о б п ее о систем е M ighty G um ball 250
Как выполпяются запросы , адресованны е веб-службам? 253
Как выполпять запросы из JavaScript 254
П одвинься, XML: встречайте JSO N 260
О тобр аж еп и е данны х об уровне продаж жвачки 264
Как установить собствепны й веб-сервер 265
Д орабаты ваем код с целью использования JSON 270
П ер еходи м к использованию действую щ его сервера 271
вас оЖиЭает Н еож иданпы й поворот собы тий! 273
hwm поворот!
П ом н ите, как мы столкпулись с пеож идапны м повор отом
собы тий? Н еполадки с прилож ением 276
Ч то за браузерная политика безопасности? 278
Какие у нас вариапты? 281
Знакомство с JSONP 286
Ч то означает буква Р в аббревиатуре JSONP? 287
О бн овление кода веб-прилож ения M ighty G um ball 290
Д орабаты ваем прил ож епи е M ighty Gum ball 298
О бн овление URL-адреса JSO N с целью включения
lastreporttim e 309
К лючевые моменты 311
Специальпое со общ ен и е из главы 7... 313
содержание

раскрываем Б се^е художника

Элемент canvas
HTML больше не является просто языком «разметки». Благодаря новому
НТМ1_5-элементу c a n v a s у вас появилась возможность собственноручно создавать
и уничтожать пикселы, а также манипулировать ими. В этой главе мы воспользу­
емся элементом c a n v a s , чтобы раскрыть таящегося в вас художника, — больше
никаких разговоров о HTML, когда речь идет чисто о семантике и отсутствуют пред­
ставления; используя c a n v a s , мы начнем раскрашивать и рисовать цветом. Теперь
все будет опираться на представления. Вы узнаете, как вставлять элемент c a n v a s
в свои страницы, как рисовать текст и графические изображения (естественно, ис­
пользуя JavaScript) и даже как поступать в случае с браузерами, не поддерживаю­
щими данный элемент. С чудесным элементом c a n v a s вы встретитесь не только
в этой, но и в других главах книги.

Наш повы й стартап: TweetShirt 316


Взгляд па «оригинал-макет» 317
биммлимя/
Как добавить canvas в свою веб-страницу 320
Как увидеть свой canvas 322
Рисование в элем енте canvas 324
Вы ходим до сто й н о из пр обл ем н ой ситуации 329
TweetShirt: общ ая картина 331
Спачала напиш ем н еобходим ы й HTM L 334
Теперь добавим <form > 335
П риш ло время добавить JavaScript для вы числений 336
Н аписапие функции drawSquare 338
Д обавлени е вызова fillB ackgroundC olor 341
Тем врем енем , возвращаясь к TweetShirt.com ... 343
Ч ер ч ен и е контуров 345
П о д р о б п о е исследование м етода arc 348
Н ебольш ой прим ер использования метода arc 350
Я говорю «градус», вы говорите «радиан» 351
Возвращ аемся к написанию TweetShirt-кода
для рисования кругов 352
Пиш ем фупкцию drawCircle... 353
И звлечение твитов 357
Заверш аем написание функции drawText 365
Ключевые моменты 372

16
содержание

телевидение для нового поколения

Элемент video... и наш особый гость — элемент canvas


Нам больше не нужны какие-либо плагины. Элемент v i d e o отныне является пол­
ноценным членом HTML-семейства — просто вставьте его в свою страницу, и вы обеспечите
прямую поддержку воспроизведения видео на большинстве устройств. Однако v i d e o —
это нечто значительно большее, чем просто элемент: это API-интерфейс JavaScript, по­
зволяющий управлять воспроизведением, создавать пользовательские видеоинтерфейсы и
интегрировать видео с остальными HTML-элементами совершенно новыми способами. Го­
воря об интеграции, следует отметить, что между v i d e o и c a n v a s существует связь, —
вы увидите, что объединение этих элементов открывает новые широкие возможности по об­
работке видео в режиме реального времени. В этой главе мы сначала научимся внедрять
элемент v i d e o в веб-страницу, а затем поговорим об использовании соответствующего
API-интерфейса JavaScript. Вы будете поражены тем, что можно сделать с помощью не­
большого количества разметки, JavaScript и элементов v i d e o и c a n v a s .

Знакомство с W ebville TV 384


Включите этот «телевизор» и протестируйте его... 385
Как работает элем ент video? 387
П ристальны й взгляд на атрибуты элем ента vid eo... 388
Ч то п еобходи м о зпать о ф орм атах видео 390
Как ж онглировать всеми этими форм атам и... 392
Я слышал, там будут API-интерфейсы ? 397
Н ем ного «программирования» содер ж им ого W ebville TV 398
Как написать обработчик «конца видео» 401
Как работает м етод canPlayType 403
Распаковка дем облока 409
Р ассм отрение остальной части «заводского» кода 410
О бработчики setEffect и setV ideo 412
Реализация элем ентов управлепия видео 418
Реализация остальны х элем ентов управления видео 419
Д орабаты ваем один нюанс... 420
Как п р ои сходи т обработка видео 426
на Webville TV
Как обрабаты вать видео с использованием
врем епного буф ера 427
Реализация врем енного буф ера в canvas 429
Займемся написапием эф ф ектов 433
Как использовать собы тия error 440
содержание

с о х р а н я е м Д анны е Л°КаЛьНо

API-интерфейс Web Storage


Устали от того, что клиентские данные приходится втискивать
в тесные шкафы файлы cookie? В 1990-е годы это не было проблемой,
однако сейчас, в случае с веб-приложениями, запросы намного возросли.
Как бы вы отнеслись к тому, если бы мы сказали, что у вас есть возмож­
ность выделять по 5 Мбайт на браузер каждого пользователя? Вы, веро­
ятно, подумали бы, что мы шутим. Однако не стоит быть скептичными,
поскольку API-интерфейс HTML5 Web Storage как раз и позволят делать
это! Из данной главы вы узнаете обо всем, что необходимо для сохране­
ния объектов локально на устройстве пользователя и использования их
в работе ваших веб-приложений.
Трудно разобраться во всех
своих делах, если после того,
как и х сделаешь, нельзя избавиться Как работает браузерпое хранилищ е (1 9 9 5 -2 0 1 0 ) 448
от клейких заметок, на которых они
были записаны. Нельзя ли снабдить
Как работает Web Storage HTM L5 451
и х функцией удаления? Заметка для себя... 452
Были ли локальное храпилищ е и массив
разделены при рож дении? 458
С оздапие и п тер ф ей са 463
Теперь добавим JavaScript 464
Заверш аем создапи е и н тер ф ей са пользователя 465
П рервем ся для небольш ого заплапированпого
м ероприятия 468
П оддерж ка типа «сделай сам» 469
Д орабаты ваем наше прил ож епи е с использованием
массива 474
В песепие изм ен еп и й в createSticky с целью
использования массива 475
Функция deleteSticky 483
Как выбрать заметку для удалепия? 484
Как извлечь заметку для удаления, используя объект event 485
Удаление заметки также из DOM 486
О бновление и н тер ф ей са пользователя для выбора
цвета зам еток 487
М етод JSO N .stringify — не только для массивов 488
И спользование нового объекта stickyObj 489
Теперь, когда вы изучили localStorage, как вы соби р аетесь
использовать его? 496

18
содержание

п о м е н я е м J a v a S c rip t н а д е л е

API-интерфейс Web Workers


Медленный сценарий — хотите продолжить его выполнение? Если вам дово­
дилось достаточно тесно работать с JavaScript или путешествовать по Интернету, то
вы, вероятно, сталкивались с диалоговым окном Slow Script (Медленный сценарий).
Но как же сейчас, когда в компьютерах устанавливаются многоядерные процессоры,
сценарии могут выполняться слишком медленно? Все потому, что JavaScript поддер­
живает выполнение только одного действия за раз. Однако с появлением HTML5 и
Web Workers все изменилось. Теперь у вас есть возможность создавать множествен­
ные JavaScript-объекты w o r k e r для одновременного выполнения нескольких дей­
ствий. Независимо от того, пытаетесь ли вы создать более отзывчивое приложение
либо просто хотите по максимуму задействовать все возможности центрального про­
цессора, API-интерфейс Web Workers придется кстати.

Устрашающее диалоговое окно Slow Script (М едлепны й


JavaS cript-n o m o k сценари й) 508
Как JavaScript проводит свое время 508
| Выполнение функции init Когда одн оп оточ п ость — это П Л О Х О 509
^ Обработка события click П оток веб-сцепария worker 510
Как работаю т веб-сценарии worker 512
IЗначение времени таймера |
истекае т _
Ваш первы й веб-сценарий worker... 517
Обработка события submit
Н аписание manager.js 518
Чух-Чух
П олучение со общ ен и й от веб-сцепария worker 519
ж -ж -ж чух-чух А теперь папиш ем worker 520
чух-чух Захват виртуальных земель 528
Как вычисляется м нож ество М андельброта 530
О бработка массива данных
Как задействовать сразу несколько веб-сценариев worker 531

чух-чух ж -ж -ж Займемся созданием прилож епия Fractal Explorer 537


С оздание веб-сценариев worker и раздача им задач... 542
ж -ж -ж чух-чух
Н аписание кода 543
Запуск веб-сцепариев worker 544
■Обработка след, события click * Реализация кода worker 545
О бновление объектной Возвращ аемся к коду: как осущ ествляется обработка
^модели документа DOM
результатов работы worker 548
Выборка данных формы _
П одгоняем canvas под размеры окна браузера 551
______________-
I Ьалидация введенных t
пользователем данных Дотош ны й-ш сф п ов ар -программист 552
Время ф ипального тест-драйва! 553
Ключевые моменты 558

19
приложение: оставш иеся т е м ы

Десять важных тем (которые мы не рассмотрели)


Мы рассмотрели массу различных тем,
и вы почти закончили читать книгу. Нам
грустно с вами расставаться, но прежде чем это
сделать, нам необходимо поведать еще кое о
чем, чтобы подготовить вас к свободному пла­
ванию. В этот сравнительно небольшой раздел
нельзя уместить все, что вам требуется знать.
Вообще-то сначала мы включили все, что чита­
телю следует знать о HTML5 (не рассмотренное
в предыдущих главах), уменьшив размер шриф­
та до 0,00004. Все поместилось, однако текст
стал слишком мелким и нечитаемым. Поэтому
мы прилично сократили приложение и оставили
только десять самых важных тем.

№ 1. M odernizr 566
№ 2. Э лем ент audio и API-ип терф ейс A udio 567
№ 3. j Q uery 568
№ 4. XHTM L мертв, да здравствует XHTM L 570
№ 5. SVG 571
№ 6. А втоном ны е веб-прилож ения 572
№ 7. API-ип терф ейс Web Sockets 573
№ 8. Д ополнительно об API-ин тер ф ейсе Canvas 574
№ 9. API-интерф ейс Selectors 576
№ 10. Однако есть даже ещ е кое-что! 577
HTM L5-pyкoвoдcтвo по новым конструкциям 579
Вебвилльское руководство по семантическим
элементам HTM L5 580
Вебвилльское руководство по CSSS-свойствам 582
введение

как пользоваться эл!°й книГой

Введение
Не могу поверить,
что они включили такое
в книгу о программирова­
нии на HTML5!

«т«к 6« -о * а " ТАКОЕ

дальше ► 21
как работать с этой книгой

Для кого написана эта книга?


Если вы ответите утвердительно на все следующие вонросы:

( l ) У вас есть компьютер с установленным веб-браузером


и текстовым редактором?

Вы хотите узнать и разобраться, как создавать веб­


приложения, руководствуясь наилучшими методиками
и самыми современными стандартами?
Вам больше по душе оживленная интересная беседа,
нежели сухие и скучные академические лекции?

т о э т а к н и г а — д л я вас.

Кому зли книга пе подойдет?

Если вы ответите ,™ «рД„тель„о на любой „ з с л е д я щ и х вонросов:

/ Ознакомьтесь с книгой « Изуча-


Вы являетесь абсолютным новичком в созда­
* ем H T M L , X H T M L u C SS» (Head
нии веб-страниц? First HTML with CSS & X H T M L ),
где вы найдете превосходное
(5 ) Вы уже заняты разработкой веб-приложений введение в мир веб-разработок,
и ищете справочник по HTML5? а зат ем возвращайтесь и п р и ­
соединяйтесь к нам .
Вы боитесь пробовать что-то новое? Вы пред­
почитаете однообразный узор цветному рисун­
ку? Вы полагаете, что техническая книга не мо­
жет считаться серьезной, если в нее включены
кадры из забавных образовательных фильмов
1950-х годов и наделенные человеческими каче-
ствами API-интерфейсы JavaScript?

т о э т а к н и г а — н е д л я вас.

[Заметка от отдела продаж:


вообще-то эта книга для любого,
у кого есть деньги.]

22 введение
введение

Мы знаем, о чем вы думаете


«Как это можно назвать серьезной книгой но програм м ированию на HTML5?»
«Почему здесь так много картинок?»
«Можно ли так чему-нибудь научиться?» М о зг
ч^ 0 Э г о ~Я СЧЫ^ е^ ,
/ U важно.
U мы знаем, о чем думает баш мозг

Ваш мозг жаждет новизны . О н ностоянно ищет, вы сматрива­


ет, ждет чего-то необы чного. Таким его создала нрирода, и это
номогает нам выжить.
Так что же ваш мозг делает со всеми рутинны ми, заурядны
ми, обычными вещами, с которы м и вы сталкиваетесь? Все,
что он может сделать, это не нозволить им номеш ать своей
истинной работе, —ф иксированию того, что имеет значение.
О н не сохраняет в намяти скучную информацию ; она никог­
да не нробьется через ф ильтр «это не является важным».
А как мозг осознает, что именно является важным? Донустим
вы выш ли на нрогулку, и вдруг неред вами выскакивает тигр.
Ч то нроисходит у вас в мозге и в теле? Замечательно.
А ктивизирую тся нейроны . Всныхиваю т эмоции. П роисходят Еще 562 сухих,
химические реакции. И тогда ваш мозг нонимает.... скучных страниц
ТЗач*
" С » это
Конечно, это важно! Следует запомнить! гае. v*
не
л л о*ко
Но нредставим, что вы находитесь дома или в библиотеке. длинам-
В безонасном, уютном месте, где не бывает никаких тигров.
Вы что-то учите. Готовитесь к экзамену. Или нытаетесь освоить
какой-то сложны й технический материал, на что, как считает
ваш босс, уйдет неделя или, самое большее, десять дней.
И тут возникает нроблема. Ваш мозг будет ны таться ока­
зать вам большую услугу. О н станет следить за тем, чтобы
явно несущ ественные сведения не засоряли ценны е ресур­
сы намяти. Эти ресурсы лучше нанравить на сохранение
действительно важ ной инф орм ации. Н анрим ер, о том, что
надо онасаться тигров, остерегаться огня или никогда боль­
ше не кататься на сноуборде в одних ш ортах.
Но нри этом нельзя нросто сказать своему мозгу: «Послу­
шай, мозг, снасибо тебе, конечно, большое, однако н е­
важно, насколько скучна книга или что она не вы зы вает
во мне сильных эм оций в данны й момент. Я в самом деле
хочу заномнить инф орм ацию из нее».

дальше ► 23
как работать с этой книгой

КнцГа ДЛЯ i» e x , К ш ° хоЧ еш учц щ ьса.

Как мы что-то узнаем? Сначала нужно это «что-то» понять, а потом не забыть. Затолкать
в голову побольше фактов недостаточно. Согласно новейшим исследованиям в области
когнитивистики, нейробиологии и психологии обучения, для усвоения мат ериала тре­
буется что-то большее, чем простой текст на странице. Мы знаем, как заставить ваш мозг
работать.

Основные принципы серии «Head First»:

Наглядность. Графика запоминается гораздо лучше, чем


обычный текст, и значительно повышает эффективность воспри­
ятия информации (до 89 % по данным исследований). Кроме того,
материал становится более понятным. Текст размещается
на рисунках, к которым он относится, а не под ними или на
соседней странице.

Разговорный стиль изложения. Недавние исследова­


ния показали, что при разговорном стиле изложения материала
(вместо формальных лекций) улучшение результатов на итоговом тести­
ровании достигает 40 %. Рассказывайте историю, вместо того чтобы читать лекцию.
Не стоит быть слишком серьезным. Что вам самим больше по душе: вести оживленный разговор
с интересным собеседником или слушать лектора?

Активное участие читателя. Пока вы не начнете напрягать


извилины, в вашей голове ничего не произойдет. Читатель должен
быть заинтересован в результате; он должен решать задачи, фор­
мулировать выводы и овладевать новыми знаниями. А для этого
необходимы упражнения и каверзные вопросы, в решении которых
задействованы оба полушария мозга и разные чувства.

Привлечение и удержание внимания читателя. Ситуация, знакомая каждому:


«Я очень хочу изучить это, но засыпаю на первой странице». Мозг обращает внимание
на интересное, странное, притягательное, неожиданное. Изучение сложной технической
темы не обязано быть скучным. Интересное узнается намного быстрее.

Обращ ение к эмоциям. Известно, что наша способность запоминать в значительной


мере зависит от эмоционального сопереживания. Мы запоминаем то, что нам небезраз­
лично. Мы запоминаем, когда что-то чувствуем. Нет, сентименты здесь ни при чем: речь
идет о таких эмоциях, как удивление, любопытство, интерес, и чувстве «Да, я крут!» при
решении задачи, которую окружающие считают сложной, — или когда вы понимаете, что
разбираетесь в теме лучше, чем всезнайка-Боб из технического отдела.

24 введение
введение

Метапознание: учимся учиться


Е сли вы действительно хотите бы стрее и глубже усваивать новы е зн а­
ния —задумайтесь над тем, как вы задумываетесь. Учитесь учиться.
Мало кто из нас изучает теорию м етанознания во время учебы. Нам
положено учиться, но нас редко этому учат.
Н о раз вы читаете эту книгу, то, вероятно, хотите научиться разраба­
ты вать нрилож ения, к нримеру, для iPhone, и но возмож ности
быстрее. Вы хотите запомнить нрочитанное, а для этого абсо­
лю тно необходимо сначала понять н рочитанное.
Ч тобы извлечь максимум нользы из учебного нроцесса, нуж­
но заставить ваш мозг восприним ать н овы й материал как Н е­
что Важное. К рити чное для вашего сущ ествования. Такое же
важное, как тигр. И наче вам нредстоит бесконечная борьба с
вашим мозгом, которы й всеми силами уклоняется от запомина­
ния н овой инф орм ации.

Как же УБЕДИТЬ мозг, что знание HTML5 (и JavaScript)


не менее важно, чем тигр?
Есть снособ медленный и скучный, а есть бы стры й и эф ф ек­
тивны й. П ервы й основан на туном новторении. Всем известно,
что даже самую скучную инф орм ацию можно заномнить, если н овторять ее
снова и снова. П ри достаточном количестве н овторен и й ваш мозг нрикиды-
вает: «Вроде бы несущ ественно, но раз одно и то же н овторяется столько раз...
Ладно, уговорил».
Б ы стры й снособ основан на повы ш еппп актпвпостп мозга и особенно на со­
четании разны х ее видов. Д оказано, что все ф акторы , перечисленны е на п ре­
дыдущей странице, номогаю т вашему мозгу работать на вас. Н анрим ер, ис­
следования ноказали, что разм ещ ение слов внутри рисунков (а не в ноднисях,
в основном тексте и т. д.) заставляет мозг анализировать связи между текстом
и граф икой, а это нриводит к активизации большего количества нейронов.
Больше н ей ронов — выше вероятность того, что инф орм ац ия будет сочтена
важ ной и достойной заноминания.
Разговорны й стиль тоже важен: обычно люди н роявляю т больше внимания,
когда они участвуют в разговоре, так как им н риходится следить за ходом бе­
седы и высказы вать свое мнение. П ричем мозг соверш енно не интересует,
что вы «разговариваете» с книгой! С другой стороны , если текст сух и ф ор­
мален, то мозг чувствует то же, что чувствуете вы на скучной лекции в роли
нассивного участника, —его клонит в сон.
Н о рисунки и разговорн ы й стиль —это только начало.

дальше ► 25
как работать с этой книгой

Вот что сделали МЫ


Мы иснользовали рпсункп, нотому что мозг лучше нриснособлен для воснри-
яти я граф ики, чем текста. С точки зрен и я мозга рисунок действительно стоит
ты сячи слов. А когда текст комбинируется с граф икой, мы внедряем текст нря-
мо в рисунки, нотому что мозг нри этом работает эф ф ективнее.
Мы иснользуем пзбы точпость: новторяем одно и то же несколько раз, нриме-
н яя разны е средства нередачи и нф орм ации, обращ аемся к разны м чувствам —
и все для новы ш ения вероятн ости того, что материал будет закодирован в не­
скольких областях вашего мозга.
Мы иснользуем конценции и рисунки несколько пеож пдаппы м образом, но­
тому что мозг лучше восприним ает новую инф орм ацию . К роме того, рисунки
и идеи обы чно имею т эмоциональное содержание, нотому что мозг обращ ает вни­
мание на биохимию эмоций. То, что заставляет нас чувствовать, лучше заноми-
,
нается, —будь то шутка удивление или интерес.
Мы иснользуем разговорный стиль, нотому что мозг лучше восприним ает ин­
формацию , когда вы участвуете в разговоре, а не нассивно слушаете лекцию.
Это нроисходит и н ри чтении.
КЛЮЧЕВЫЕ
В книгу вклю чены м ногочисленны е унраж нения, нотому что мозг лучше зано- МОМЕНТЫ ^
минает, когда вы что-то делаете. Мы ностарались сделать их ненросты ми, но
интересны м и —то, что нредночитает больш инство читателей.
Мы совместили несколько стилей обучения, нотому что одни читатели нредно-
читаю т нош аговые онисания, другие стрем ятся сначала нредставить «общую
картину», а третьи м хватает ф рагм ента кода. Н езависим о от ваших личны х
н редночтений нолезно видеть несколько вариантов нредставления одного ма­ Кроссворды
териала.
Мы ностарались задействовать оба полушария вашего мозга; это новы ш ает веро­
ятность усвоения материала. П ока одна сторона мозга работает, другая часть
им еет возмож ность отдохнуть; это новы ш ает эф ф екти вн ость обучения в тече­
ние продолж ительного времени.
А еще в книгу вклю чены истории и унраж нения, отраж аю щ ие другие точки
зрения. М озг глубже усваивает инф орм ацию , когда ему нриходится оценивать
и вы носить суждения.
В книге часто встречаю тся вопросы, на которы е не всегда можно дать н ростой
ответ, нотому что мозг бы стрее учится и заноминает, когда ему нриходится
что-то делать. Н евозм ож но накачать мышцы, наблюдая за тем, как занимаю тся
другие. Однако мы нозаботились о том, чтобы усилия читателей были нриложе-
ны в верном нанравлении. Вам не нридется ломать голову над невразумитель­
ными нрим ерам и или разбираться в сложном, неренасы щ енном техническим
ж аргоном или слишком лаконичном тексте.
В историях, нрим ерах, на картинках фигурирую т люди — нотому что вы тоже
человек. И ваш мозг обращ ает на лю дей больше внимания, чем на неодушевлен­
ные предметы.

26 введение
введение

Что моЖете сделать ВЫ, чтобы


заставить свой мозг повиноваться
Мы свое дело сделали. О стальное за вами. Эти советы станут
отнравной точкой; нрислуш айтесь к своему мозгу и опреде­
лите, что вам нодходит, а что не нодходит. Пробуйте новое.

(Т ) Не торопитесь. Чем больше вы поймете, (? ) Говорите вслух.


тем меньше придется запоминать. Речь активизирует другие участки мозга. Если
Просто читать недостаточно. Когда книга вы ны таетесь что-то нонять или нолучше за-
задает вам вонрос, не нереходите к ответу. номнить, нроизн есите вслух. А еще лучше,
П редставьте, что кто-то действительно задает нонробуйте объяснить кому-нибудь другому.
вам вонрос. Ч ем глубже ваш мозг будет мыс­ Вы будете бы стрее усваивать материал и, воз­
лить, тем скорее вы нойм ете и заномните ма­ можно, откроете для себя что-то новое.
териал.

(? ) Выполняйте упражнения, делайте заметки. (7[) Прислушивайтесь к своему мозгу.


Мы вклю чили унраж нения в книгу, но вынол- Следите за тем, когда ваш мозг начинает уста­
нять их за вас не собираемся. И не разглядывай­ вать. Если вы начинаете новерхностно вос­
те унраж нения. Б ерите карандаш и ниш ите. приним ать материал или забы ваете только
Ф изические действия во время учения новыша- что н рочи тан н ое — нора сделать нереры в.
ю т его эф ф ективность. С определенного момента ноны тки «затол­
кать» в мозг дополнительную инф орм ацию не
только не ускоряю т обучение, а скорее идут во
0 Читайте врезки.
вред ему.
Это значит: читайте все. Врезки —часть основно­
го материала! Н е нронускайте их.
(? ) Чувствуйте!
(^ Не читайте другие книги после этой Ваш мозг долж ен знать, что м атериал книги
перед сном. действительно важен. П ереж ивайте за героев
Часть обучения (особенно неренос инф орм а­ наш их историй. П ридумывайте собственные
ции в долгосрочную намять) нроисходит но- нодниси к ф отограф иям . П ом орщ иться над
сле того, как вы отклады ваете книгу. Ваш мозг неудачной шуткой все равно лучше, чем не но-
не сразу усваивает инф орм ацию . Если во вре­ чувствовать ничего.
мя обработки ностунит новая инф орм ация,
часть того, что вы узнали ранее, мож ет быть (9 ) Творите!
нотеряна.
П онробуйте нрим енить новы е знания в своей
новседневной работе. П росто сделайте хоть
(б ) Пейте воду. И побольше. что-нибудь, чтобы нриобрести практический
М озг лучше всего работает в условиях «высо­ оны т за рамками унражнений. Все, что для
кой влажности». Д егидратация (которая мо­ этого нужно, — это карандаш и нодходящ ая
ж ет настунить еще до того, как вы ночувствуе- задача... задача, в которой изучаемые методы
те жажду) сниж ает когнитивны е функции. и инструменты могут нринести нользу.

дальше ► 27
как работать с этой книгой

Примите к сведению
Это учебник, а не снравочник. Мы намеренно убрали из книги все, что могло бы номешать
изучению материала, над которым вы работаете. И нри нервом чтении книги начинать следу­
ет с самого начала, нотому что книга нреднолагает наличие у читателя определенных знаний
и оныта.
Мы предполагаем, что вы знаете HTML и CSS.
Если вы не знаете разм етки HTM L (то есть ничего о HTM L-документах, об элементах, атрибу­
тах, структуре свойств, структуре в сравнении с презен тац и ей ), то н рочи тай те книгу Э. Ф риме­
н а ^ . Ф римен «Изучаем HTM L, XHTM L и CSS» (СПб.: П итер, 2012) неред тем, как нристунить
к этой. Если же соответствующ ие знания у вас есть, то все в норядке.
От вас не требуется знание JavaScript.
Если у вас имеется какой-либо оны т нрограм м ирования или нанисания сценариев (пусть и не
на JavaScript), то это вам номожет. Однако в данной книге мы не ждем от вас знаний JavaScript;
ф актически, это издание является продолж ением книги «Изучаем HTM L, XHTM L и CSS», где
нанисание сценариев отсутствует.
Мы рекомендуем использовать разные браузеры.
Тестируйте страницы и веб-нриложения, иснользуя сразу несколько браузеров. Так вы узнае­
те, чем отличаю тся разны е браузеры, и научитесь создавать страницы , нормально работаю щ ие
в разны х браузерах. Советуем иснользовать Google C hrom e и Apple Safari, но скольку они наи­
более соответствуют соврем енны м стандартам. Также рекомендуем вам нрим енять для тести­
р ован ия и новейш ие версии других распространенны х браузеров, таких как In tern et Explorer,
Firefox и O pera, а также мобильные браузеры на устройствах с онерационны м и системами iOS
и A ndroid.
Упражнения ОБЯЗАТЕЛЬНЫ.
Н е игнорируйте унраж нения —они являю тся частью основного м атериала книги. Одни из них
номогут вам заномнить материал, другие —нонять его, а третьи —н рим енить изученное н а нрак-
тике. Н е нронускайте унраж нения. Важны даже головоломки, носкольку они номогаю т мозгу ус­
воить конценции и даю т возмож ность обдумывать изучаемые новы е слова и терм ины в разном
контексте.
Повторение применяется намеренно.
У книг этой серии есть одна нринциниальная особенность: мы хотим, чтобы вы действительно
хорош о усвоили материал. И чтобы вы зано мнили все, что узнали. Больш инство снравочников
не ставит своей целью уснеш ное заноминание, но это не снравочник, а учебник, ноэтому неко­
торы е конценции излагаю тся в книге но нескольку раз.
Упражнения «Мозговой штурм» не имеют ответов.
В некоторы х из них нравильного ответа вообщ е нет, в других вы долж ны сами реш ить, насколь­
ко нравильны ваши ответы (это является частью нроцесса обучения). В некоторы х упраж нени­
ях «М озговой штурм» нриводятся но д сказки, которы е номо гут вам найти нужное нанравление.

28 введение
введение

Системные требования
Д ля нанисания и работы с кодом на HTM L5 и JavaScript вам нонадобится текстовы й
редактор, браузер и, врем я от времени, веб-сервер (он мож ет локально располагаться
на вашем настольном ком нью тере).
В онерац и онн ой системе Windows мы рекомендуем иснользовать такие текстовы е р е­
дакторы , как PSPad, TextPad или EditPlus (но вы, если нридется, мож ете пользоваться
нрограм м ой N o tepad (Блокнот)). Для нлатф орм ы Мае советуем TextW rangler, TextMate
или TextEdit. Если вы работаете в Linux, то в вашем распоряж ении масса встроенны х
текстовы х редакторов, о которы х, как мы нолагаем, рассказывать не нужно.
Надеемся, что вы н рочи тали нункт о браузерах (см. нредыдущую страницу) и устано­
вили как минимум два из них у себя в системе. Если нет, сделайте это. Вам также стоит
уделить время и научиться работать с инструментами разработчика, встроенны м и в
браузеры; в каждом из наиболее распространенны х браузеров имеется встроен н ы й ин­
струментарий, которы й можно нрим енять для и нснекти ровани я консоли JavaScript (вы
сможете просм атривать ош ибки и вывод, генерируем ы й носредством c o n s o l e . l o g ,
что является альтернативой a l e r t ) , использования веб-хранилища, объектной модели
документа DOM, CSS-стиля, прим ененного к элементам, и многого другого. Н екоторы е
браузеры даже ноддерж иваю т нлагины , нозволяю щ ие добавлять новы е инструменты
разработчика. Ч тобы освоить книгу, эти инструменты вам не нотребую тся, однако если
у вас есть ж елание н отрати ть врем я на изучение того, как ими пользоваться, то нроцесс
разработки будет легче.
Н екоторы е н арам етры HTM L5 или API-интерф ейсы JavaScript требуют, чтобы файлы
не нросто загружались, а ностунали нри этом с реального веб-сервера (то есть URL-
адрес долж ен начинаться с h t t p : / / , а не с f i l e : / /) . В соответствующ их местах книги
мы указали, в каких случаях вам нотребуется сервер, но если у вас возникло ж елание,
рекомендуем установить веб-сервер у себя в системе нрямо сейчас. В онерационны х
системах Mac OS и Linux им еется встроен н ы й сервер A pache, ноэтому вам нужно лишь
убедиться, что вы знаете, как но лучить к нему достун и где размещ ать свои файлы , что­
бы их можно было загружать, иснользуя свой локальны й сервер. В Windows вам н отре­
буется установить A pache или IIS; если вы нредночтете A pache, то вам станет достунна
масса инструментов с откры ты м исходным кодом, нанрим ер WAMP и ХАМРР, которы е
довольно нросты в установке.
Вот и все! Удачного вам времянровож дения...

дальше ► 29
обзор команды

^ Дэвцд Пауэрс
Технические рецензенты У _____________

Пол bappu Б ернл £>эйилс

Он не просто рецензент, Наш главный технический


а о п ы т н ы й а в т о р , на с ч е т у к о т о Не только занимается
рецензент. рецензированием, но также
р о го т а к и е к н и г и , к а к « И з у ч а е м
P y th o n » (H e a d F irst P y th o n ) пишет книги! Как он только
все успевает...
и « И зуч а ем пр огр а м м и р о ва ни е» Ребекка Д а н -К эн
(H e a d F irst P r o g r a m m in g )!
Тревор Фарлоу
^ A у bapp

Наш рецензент, выложившийся


Мы пытались убедить ее, на Н О %. Он даже совершал
что нам нужна только п о ­ пробежки по ночам, тестируя
мощь с графикой, но она не Ребекка стала нашей лишней парой наш геолокационный код.
удержалась и выступила глаз; она помогала нам с кодом, вы­
также техническим рецен­ искивая в нем мелкие ошибки, кот о­
зентом. рые никто не замечал (включая нас!)

Выражаем огромную п рнзпательпость комапде паш их технических рецепзептов. С воей рабо­


той опи доказали, что мы пе смогли бы обойтись без их технических зпапий и опыта, а также
впим апия к деталям. Дэвид Пауэрс, Ребекка Дап-Кэп, Тревор Фарлоу, П ол Б арри, Луиза Барр
и Б ер т Бэйтс прилож или максимум усилий в своих рецепзиях, благодаря чему эта кпига стала
пампого-пампого лучше. Вы молодцы, ребята!

30 введение
введение

Благодарности
За прекрасное техническое рецензирование:
Э то уже превращ ается в традицию в иаш их киигах, и мы Заметка для редактора:
хотим еще раз горячо поблагодарить Дэвида Пауэрса, па- ^ м о ж н о ли застолбить
шего уважаемого технического рец еп зеп та и автора мпо- этого парня на три
гих издапий, вклю чая кпигу «РНР. Создапие дипам ических нами следующие книги?
страпиц» (РНР Solutions: Dynamic Web Design M ade Easy). Причем на эксклюзивных
Благодаря зам ечапиям Д эвида содерж имое кпиг всегда
правах!
зпачительпо улучшается, и пам крепче спится по почам от
зпапия того, что если текст прош ел ч ерез Дэвида, то в тех­
ническом плапе там все отличпо. Еще раз спасибо, Дэвид.
Группе O’Reilly:
Н а плечи К ортпи Нэш легла тяж елая обязаппость по руковод­
ству пе только проектом кпиги «Изучаем програм м ирование па
HTML5», по и пами. К ортпи расчистила все нути для пас и де-
ликатпо оказывала пе обходимое давлепие па каждого редактора,
чтобы кпига смогла вы йти в свет. Одпако глав пая заслуга К ортпи
заклю чается в том, что опа обеспечила пеоцепимую обратную
связь касаемо кпиги и ее содерж имого, в результате чего текст под­
вергся ряду серьезпы х доработок. Благодаря усилиям К ортпи эта
кпига стала пампого лучше. Выражаем ей свою призпательпость.

К ор тн и Нэщ _ У
Лу Б арр также стала неотъем ле­
м ой частью процесса работы пад
кпигой и впесла свой вклад, вы­
ступив в массе ролей: рецепзепта,
граф ического дизайпера, главпого
художпика, веб-дизайпера и масте­
ра Photoshop. Спасибо тебе, Лу,
без тебя у пас пичего бы пе полу­
чилось!

\ А у Б арр j снова! (И Тоби.)

,
И спасибо всем остальным людям благодаря труду которых эта книга
увидела свет:
Благодарим остальпых члепов комапды из O ’Reilly за их разпосто-
роппю ю поддержку. Это М ай к Х еи д ри ксои , М ай к Л уки дес, Лоу-
р е л Рума, К а р е й Ш е й и е р , С аи дерс К л я й и ф е л ь д , К р и с т е и Б о р г,
К а р е й М о н тго м ери , Р э й ч е л М оиагаи, Д ж ули Хоукс и Н эи си
Р эй и х ар д т.

дальше ► 31
благодарности

U еще благодарности*
Также спасибо всем остальным
Д ж ейм с Х еистридж паписал оригипальпы й код, легш ий в оспову
и рилож еии я Fractal Explorer из главы 10, которое мы адаптировали
в кпиге под свои нужды. И звипяемся, Джеймс, если приведеппы й в
тексте код окаж ется пе столь элегаптпы м, как в исходпом виде. Ак­
тер, художпик и исполпительпы й д иректор Star buzz Л оуреис Заи-
коивски припим ал активпое участие в создапии кпиги и помогал те­
стировать видеоприлож епие из главы 8 (пе пропустите!). Городская
ассоциация Б эйибридж Айлеид лю безпо разреш ила пам использо­
вать свой зам ечательпы й логотип, придумаппый Д эпиз Х аррис, как
символ ш таб-квартиры W ickedlySmart. Благодарим Э итоии Виззари
и А&А Studios за возможпость приводить ф отоспим ки их прекраспы х
ф отокабипок. В паш ем прим ере со стартапом TweetShirt вы увидите
красивы е икопки, предоставлеппы е C hethStudios.N et. Выражаем
п ризпательпость Internet Archive за кадры из фильмов, которы е мы
использовали для Webville TV. И спасибо Д эииелу Ш тейибергу, ко­
то р ы й там работает и всегда готов пам помочь.

К э т ц Сиерра

,
И наконец выражаем благодарность
Кэти и Берту
И последпими, по пичуть пе в мепь-
ш ей степепи, благодарим К эти Си-
ерру и Б ерта Бэйтса — участпиков
и М О ЗГО В О Й Ц ЕН ТР всей паш ей
операции, которы е к тому же являю т­
ся осповополож пикам и серии «Head
First». Надеемся, что паша кпига зай­
мет достойпое место в этой серии.

5
Усердно п р о в е р я е м на п р а к т и к е
с и с т е м у П арелли

*Так много благодарностей мы высказываем потому, что проверяем теорию о том, что каждый из
упомянутых здесь людей захочет купить минимум один ее экземпляр (возможно даже больше, например,
для своих родственников). Поэтому если вы желаете, чтобы мы упомянули вас в благодарностях
в нашей следующей книге и у вас много родственников, пишите нам.

32 введение
введение

О т издательства
Ваши зам ечапия, предлож ения и вопросы отправляйте по адресу электроп пой
почты vinitski@ m insk.piter.com (издательство «Питер», ком пью терная редакция).
Мы будем рады узпать ваше мпепие!
Н а сайте издательства h t t p : / /w w w .piter.com вы пайдете подробную ипф орм ацию
о паш их кпигах.

дальше ► 33
1 знак°сщВо с htroljj

* Добро пожаловать
в Вебвилль
Мы отправляемся в Вебвилль!
Там столько прекрасных домов в стиле
HTML5, что просто безумие жить в каком-
то другом месте! Давайте с нами, и мы
покажем вам все местные достопримеча-
V тельности. / '

HTML стремительно развивается. Да, изначально HTML представлял


Примечание: собой простой язык разметки, однако с выходом все новых версий он по­
язв!К XHTML степенно наращивал «мускулатуру». В настоящее время мы располагаем
получил
«прощ аль ~ версией HTML, заточенной под создание полноценных веб-приложений с
Иое письмо» поддержкой localStorage, 20-рисования, автономного режима работы, со­
в 2.004 году, кетов, потоков и т. д. История развития HTML не всегда была радужной:
о чем m w еще
1л.ого6ориМ- она полна драматизма (об этом мы поговорим позже), но в этой главе мы
для начала совершим увеселительную поездку по Вебвиллю, чтобы вы
могли разобраться во всем, что вкладывается в понятие «HTML5». Поэто­
му запрыгивайте к нам — мы отправляемся в Вебвилль, где за 3,8 страни­
цы (ровно) пройдем путь от исходной точки до HTML5.
Переходите на H T M L 5 СЕГОДНЯ! Зачем Ждать?
Воспользуйтесь нашим новым

НТМЫЗ-модернизатором
и сделайте зто всего за ТРИ ПРОСТЫХ ШАГА

Не раздумывайте! Акция действует в течение ограниченного вре­


мени. Мы возьмем ваши старые HTML-страницы и модернизируем
их до HTML5 за ТРИ ПРОСТЫХ ШАГА. J

/
Неужели все действительно так просто? Конечно! Мы даже под­
готовили для вас небольшую демонстрацию.
Взгляните на этот старый, потрепанный, видавший лучшие
дни HTML; мы превратим его в HTML5 прямо у вас на глазах:
< ! DOCTYPE h tm l PUBLIC " -//W 3 C //DTD HTML 4 .0 1 //E N "
т
4
" h t t p ://w w w .w3 .org/TR / h t m l 4 / s t r i c t .dtd." >
щк

<meta http-equiv="content-type"

< /h e a d >
<body>
c o n t e n t = " t e x t / h t m l ; cha r s e t = U T F - 8 ">

Clink type="text/css" rel="stylesheet" h r e f = " l o u n g e .c s s " >


<script type=" text/javascript" src="lounge .j s " X / s c r i p t >

Э т о вполне заурядны й код в е о -


^ й x
I
Л
у

(
<Ь1>Добро пожаловать в Head First Lounge</hl> с т р а н и ц ы Неа ЯлаЖ^Н
м ■ HTM L 4-.ОИ, к о т о р ы м должен
& бы т ь 6 д м знаком по к н и ^ *5,,
< im g s rc = "d r in k s .g if" a lt= " D r in k s " > цаеМ H T M L » (H e a d F ir s t H T M L )
< /p > (а если и н е т , не беспокойт есь,
3tVV0 $.$COAK}tVVHO и^ ййжно )
Каждый вечер присоединяйтесь к нам для разговора
за напитком <а href="elixirs .html" >elixirs</a>,
и, возможно, игры в two of Тар Тар Revolution.
К вашим услугам беспроводной доступ; ЗССВС (Захватите Свой Собственный Веб-Сервер).
< /р >
< /b o d y >

М 9

Ш ТУРМ
* Г 0 * 9 Й ________________________________________________________________________________________________________________________________________ __________

Вы увидите, насколько просто писать код на HTML5


!
Изучите приведенный выше пример кода, который написан на HTML 4.01 (это предыдущая вер­
сия языка). Взгляните на все строки и вспомните, что каждая из них делает. Отмечайте прямо
на странице. Далее мы с вами разберемся в том, как переделать его в HTML5-KOfl.

V
знакомство с HTML5

^ Возьми в руку карандаш

Внимательно взглянув на HTML-код на странице 36, заметили ли вы там какие-либо фраг­


менты разметки, которые могут претерпеть изменения при их переделке в HTML5? Или что
бы вы сами там изменили? Дадим вам одну подсказку: определение d o c t y p e .

Это просто озна- В этой части говорится, что


чает, что данный мы используем HTML версии 4 .0 1
d o c tu pe дляW m l - ст андарт я б д я - “ что разметка написана
ЭИД° ч т о н а м н у ж н о ' - ^ ^ т с я открытым на английском языке (EN)
то

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"


"http://www.w 3 .org/TR/html4/strict.dtd">

t
Это указание на файл , который опреде­
ляет соответствующий стандарт

Определение doctype относится к верхней части HTML-файла и сообщает браузеру, какого


типа этот документ, в данном случае — HTML 4.01. Благодаря d o c t y p e браузер более точ­
но может осуществлять интерпретацию и рендеринг страниц. Настоятельно рекомендуем
вам использовать d o c t y p e .

Итак, что подсказывают ваши дедуктивные способности в плане того, как будет выглядеть
определение d o c t y p e для HTML5? Напишите ответ здесь (вы сможете проверить его по­
сле того, как мы разберемся во всем чуть позже):

Ллихего
Зля

дальше ► 37
обнови свой html

Представляем наш новый МШ-модернимтор.


Обновите свой HTML прямо сейчас!

Шаг 1 у д и в и т вас: мы начнем с верхней части HTML-страницы Head First


Lounge и обновим определение d o c t y p e , придав ему новый блеск HTML5.
Вот как выглядела старая версия d o c ty p e в случае HTML 4.01:

< 'DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" я


"http://www.w3.org/TR/html4/strict.dtd"> ИзбмНЯб
п еред т е м м .
к т о успел
Вы, наверное, подумали, что в d o c t y p e мы собираемся заменить c3eAamt> себе
любое упоминание «4» на «5»? А вот и нет Преимущество в том, татуировку
ЧТО d o c t y p e для HTML5 ВЫГЛЯДИТ совсем просто: , doctype- 4 .< 3 i
<! doctype html> на |лЯлЛЯт17'

Вам больше не потребуется Google, чтобы узнать, как выглядит d o c t y p e


для HTML5, как и не потребуется копировать и вставлять его из другого
файла, поскольку это определение отличается крайней простотой и вам не
составит труда его запомнить.
Однако постойте, есть еще кое-что...
Данное определение d o c t y p e подходит не только для HTML5, но и для
всех будущих версий языка HTML. Другими словами, оно останется не­
изменным. Кроме того, оно будет работать и в старых версиях браузеров.

zztzz eQJ
Если вы фанат телешоу «Фабрика красоты» (Extreme Makeovers) или
«Потерявший больше всех» (The Biggest Loser), то шаг 2 вам понравится.
Здесь у нас имеется тег m e ta с атрибутом c o n t e n t . . . впрочем, взгляните
на картину «до» и «после»:
<шеta http-equiv="content-type" content="text/html; charset=UTF-8">
И д О (H T M L 4 )
<meta charset="utf-8">
П OCAB (H T M L S )

Да, новый тег m e ta значитеяы ю -похудел намного более прост При исполь­
зовании тега m e ta в HTML5 нужно лишь указать его наряду с кодировкой
символов. Верите вы или нет, но все браузеры (новых и старых версий) уже
понимают такое метаописание, поэтому его можно использовать в коде
любой страницы — и оно будет работать.

38 глава 1
знакомство с HTML5

А теперь шаг 3, заключительный. Здесь мы сосредоточим внимание на элемен­


те < h e a d > и модернизируем тег l i n k . Вот что у нас имеется на текущий момент:
тег l i n k с атрибутом t y p e со значением t e x t / c s s , указывающий на каскадную
таблицу стилей (значение s t y l e s h e e t ) :
Clink t y p e = " text/css" rel="stylesheet" href="lounge.css ">
mapoM HTML
\С.од НД С
Чтобы обновить этот код до HTML5, нужно просто убрать атрибут t y p e . По­
чему? Потому что CSS объявлен стандартным языком стилей для HTML5 по
умолчанию. Таким образом, после того как мы удалим атрибут t y p e , наш об­
новленный тег l i n k приобретет следующий вид:
< l i n k г e l = " s t y l e s h e e t " h r e f = " lo u n g e . c s s " > ^
HTMLS

Поскольку вы работали быстро, у насесть специальный бонус для вас. Мы еще


больше облегчим вам жизнь, упростив тег s c r i p t . JavaScript в случае HTML5
стал стандартным языком сценариев по умолчанию, поэтому вы можете уда­
лить атрибут t y p e также и из тегов s c r i p t . Вот каким станет наш тег s c r i p t без
атрибута t y p e . i~i& беспокойтесь, если вы
< s c r i p t s г с = пl o u n g e . j s " X / s c r i p t > i T ' не слишком много знаете о теге
script, мы еще дойдем до него...
Либо, если вы будете иметь дело со встроенным кодом, можете просто напи­
сать свой сценарий следующим образом:
< s c r ip t >

v a r youR ock = t r u e ; n
y Beet? бяид
</script> J a v a S c rip t Подробнее о JavaScript
ёудет здесь- мы поговорим позже.

Поздравляем, теперь вы сертифицированы


модернизировать любой HTML-код до HTML-5!

Как продвинутый пользователь НТМ1_5-модернизатора,


вы обладаете всем необходимым для того, чтобы обновить
любую нормальную HTML-страницу до HTML5. Дерзайте, пришло
время реализовать полученные знания на практике!

дальше ► 39
больше чем разметка

Постойте-ка, столько суеты


вокруг H TM L5, и вдруг оказы­
вается, что это все, что от меня
потребуется? О чем же тогда
оставшаяся часть книги?

Ладно, ладно, вы нас поймали. Пока мы вели


речь о модернизации кода HTM L-страниц, создан­
ных с помощью старой версии этого языка, с це­
лью паделить их всеми преимуществами, которы е
дает HTML5. И, как можно было убедиться, если
вы зпакомы с HTM L 4.01, то это просто отлично,
поскольку HTM L5 — это расш иренны й HTM L 4.01
(то есть практически все имею щ ееся в нем под­
держ ивается и в HTM L5), и вам потребуется лишь
зпать, как определять d o c ty p e и остальные теги в
элемепте < head> , чтобы начать программировать
па HTM L5.
Но вы правы в том, что мы повели себя несколько
глупо, поскольку, конечно же, язы к HTML5 —это не­
что большее, чем просто модернизация нескольких
элемептов. Разработчиков в нем привлекает воз­
мож ность создавать насы щ енны е, интерактивны е
страпицы (или даже сложные веб-приложения),
а также то, что оп вклю чает в себя целое семейство
технологий, которы е работаю т рука об руку с этим
язы ком разметки.
Одпако пе будем спеш ить. П реж де чем двинуться
дальше, сделаем еще кое-что, чтобы окопчательпо
разобраться с паш ей HTM L-разметкой.
знакомство с HTML5

Возьми в руку карандаш_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


Вы ближе к НТМ1_5-разметке, чем думаете!
Здесь приведена разметка на старом HTML, которая нуждается в обновлении. Осуществите
НТМ1_5-модернизацию и обновите этот написанный на HTML 4.01 код до HTML5. Не бойтесь
делать пометки в книге, вычеркивайте приведенную здесь HTML-разметку и добавляйте новый
код, который вам потребуется. Мы немного помогли вам и выделили области, нуждающееся
в изменениях.

Закончив, напечатайте код (или внесите изменения в файл упражнения, если вам так больше
нравится), загрузите его в браузер и, откинувшись на спинку стула, насладитесь своим первым
творением на HTML5. Ах да, наши ответы вы найдете на следующей странице.

^ Чтобы загрузить весь код и файлы примеров для этой книги ,


посетите страницу h ttp ://w ic ke d lysm a rt.c o m /h fh tm ls.

< !DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"


"http://www.w3.org/TR/html4/strict.dtdn>
<html>
<head>
<title>Head First Lounge</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link type="text/css" rel="stylesheet" href="lounge.css">
< script type="text/javascript" src= "lounge.js"X/script>
</head>
<body>
<Ь1>Добро пожаловать в Head First Lounge</hl>
<P>
< img src="drinks .gif11 a l t = 11D r i n k s 11>
< /p >
<p>
Каждый вечер присоединяйтесь к нам для разговора
за напитком <а href="elixirs .html11>elixirs</a>,
и, возможно, игры в Тар Тар Revolution.
Всегда к вашим услугам беспроводной доступ; ЗССВС (Захватите Свой
Собственный Веб-Сервер).
< /р >
</body>
< /html>

дальше ► 41
решение упражнения

г< й Возьми в руку карандаш


Решение
Вы ближе к HTML 5-разметке, чем вы думаете!
Здесь приведена разметка на старом HTML, которая нуждается в обновлении.
Осуществите HTMLS-модернизацию и обновите этот написанный на HTML 4.01
код до HTML5. Не бойтесь делать пометки в книге, вычеркивайте приведенную
здесь HTML-разметку и добавляйте новый код, который вам потребуется. Мы не­
много помогли вам и выделили области, нуждающиеся в изменениях.

Вот наше решение.

Вот четыре строки ,


Обновленный код будет выглядеть так:
благодаря измене­
нию которых наша
yz. Определение doctype веб-страница Head
< ! d o c ty p & k t m l >
First Lounge получила
<html> официальное право
<head> называться HTMLS-
<title>Head First Lounge</title> страницей.

< m e ta c k a r s e t= " u tf- 2 " > ^ ' Тег m eta


< l i n k r e l = " s t y l e s h e e t " P \r e f= " lo u n g e .c s s " > Тег lfnk
< s c rip t s r c = " lo u n g e .js " x /s c r ip t> 2=— . Тег script
<
</head>
<body>
<Ь1>Добро пожаловать в Head First Lounge</hl>
<P>
<im g s r c = 11drinks .gif11 a l t = 11D r i n k s 11>
</ p >
<p>
Каждый вечер присоединяйтесь к нам для разговора
за напитком <а h r e f = nelixirs .html11>elixirs</a>,
и, возможно, игры в Тар Тар Revolution.
Всегда к вашим услугам беспроводной доступ; ЗССВС (Захватите Свой
Собственный Веб-Сервер).
</ р >
</body>
</html> Не в е р и т е н а м ? З а й д и т е п о
адресу
k t t p Y / v a h d a t o r . w s . o r g / , и вы у д е -

„ иС* ~ °На nP W od^ валидацию


к а к H T M L s - с т р а н и ц а . Вез ш у т о к '

42 глава 1
знакомство с HTML5
Часш°
^адаВ аеМ ы е
В опросы

А как все это работает в старых версиях браузеров? Все 0 : Да, это так, особенно пока HTML5 не обрел 100%-ную под­
эти новые doctype, meta и т. д... ведь как-то же могут старые держку всеми браузерами. Об этих аспектах мы поговорим позже.
браузеры работать с этим новым синтаксисом?
А почему вообще все это имеет значение? Я вот написал
0 : Да, могут. Взгляните на атрибуты t y p e тегов l i n k и код веб-страницы без doctype и тега meta, и она отлично рабо­
s c r i p t ; сейчас имеет смысл избавиться от них в HTML5, по­ тает. Зачем мне лишняя головная боль, если в таком подходе
скольку CSS и JavaScript теперь являются стандартами (и, конечно нет абсолютно ничего неправильного?
же, технологиями по умолчанию для работы со стилями и написания
сценариев соответственно). Как оказалось, браузерам уже заранее 0 : Да, браузеры легко пропускают мелкие ошибки в HTML-
было известно, что CSS и JavaScript являются таковыми. Так, по файлах. Однако если вы включите соответствующие d o c t y p e
стечению обстоятельств новый язык разметки HTML5 уже довольно и теги m e ta , то сможете быть уверены в том, что браузеры будут
долгое время поддерживается существующими браузерами. Тоже знать, что именно вы от них хотите, а не гадать об этом. Кроме того,
самое справедливо и в случае с d o c t y p e и тегом m e ta . в случае с людьми, пользующимися старыми версиями браузеров,
указание нового d o c t y p e означает, что они будут использовать
А как насчет нового doctype? Что-то с ним все стало слиш­ стандартный режим, что как раз вам и нужно. Стандартный режим —
ком просто; у него нет даже версии или идентификатора DTD. это режим, в котором браузер считает, что написанный вами HTML-
код соответствует стандарту, поэтому он будет пользоваться прави­
лами данного стандарта при интерпретации вашей страницы. Если
0 : Да, кажется немного необычным, что после многих лет при­
вы не укажете d o c t y p e , то некоторые браузеры могут перейти
менения комплексных d o c ty p e теперь мы можем упростить их до
в режим совместимости и посчитать, что ваша страница написана
фразы «мы используем HTML». А произошло вот что: HTML ранее
для старых версий браузеров, когда соответствующий стандарт
основывался на стандарте SGML, который требовал как комплекс­
еще не был на должной высоте, и неправильно интерпретировать
ных форм d o c ty p e , так и DTD. Новый стандарт отошел от SGML,
страницу (или решить, что она просто некорректно написана).
преследуя этим цель сделать язык HTML проще и гибче. Таким
образом, нужда в комплексных формах отпала. Здесь не обошлось
А что случилось с XHTML? Ведь еще несколько лет назад
без некоторой доли везения в том плане, что почти все браузеры
казалось, что за ним будущее.
просто ищут HTML в определении d o c t y p e , чтобы убедиться
в том, что они осуществляют разбор именно HTML-документа.
Q j Да, так оно и было. Однако потом гибкость возобладала над
строгим синтаксисом, и XHTML (XHTML 2, если быть точными) по­
Это было всерьез, когда вы говорили, что d o c t y p e
степенно стал умирать, поскольку новый HTML5 оказался более
останется неизменным? Как мне казалось, для браузеров
либеральным в плане написания людьми веб-страниц (и осущест­
важен контроль версий. Почему бы не использовать <!doctype
вления их рендеринга браузерами). Но пусть вас это не смущает,
html5>? Наверняка в будущем появится HTML6. Ведь так?
так как знание XHTML лишь сделает из вас еще более успешного
HTML5-pa3pa6oT4HKa. Кстати, если вы испытываете привязанность
0 : Подход к использованию d o c t y p e претерпевал изменения, kXML, знайте, что существует также способ написания HTML5-KOfla
и разработчики браузеров применяли его для того, чтобы дать ука­ в строгой форме. Подробнее об этом мы поговорим позже...
зание своим браузерам осуществлять рендеринг в их собственном
стандартном режиме. Теперь, когда у нас имеется намного более • Что такое UTF-8?
точный стандарт, d o c t y p e в HTML5 сообщает любому браузеру,
что конкретный документ является стандартным HTML, будь он
0 : UTF-8 — это кодировка символов, поддерживающая множе­
версии 5, б или любой другой. ство алфавитов, включая незападные. Вам, вероятно, доводилось
сталкиваться с другими наборами символов, использовавшимися
Предполагаю, что разные браузеры пользователей будут в прошлом, однако UTF-8 продвигается как новый стандарт. Она
поддерживать различающиеся наборы возможностей HTML5. также быстрее и легче запоминается, чем предшествующие коди­
Что делать в таком случае? ровки символов.

дальше ► 43
что вы должны знать

М С ЛШ ТМ )
Мы все-таки ие ож идаем, что вы зиаете HTML5.
Даже если вы пикогда рапее пе запимались HTML5,
это пе проблема, одпако у вас долж еп иметься опы т
работы с HTM L и зпапие таких базовых аспектов,
как элемепты , теги, атрибуты, влож епия, попима-
пие разп и цы между семаптической разм еткой и до­
бавлением стиля и т. д.
Если вы пе зпакомы с даппы ми аспектами, то мы
возьмем па себя смелость дать вам пеболы пой со­
вет (и бесстыдпым образом кое-что прореклам и­
ровать): есть еще одпа кпига из этой серии, назы ­
вающ аяся «Изучаем HTM L, XHTM L и CSS», и вам
следует ее прочитать. Если же вы отчасти зпакомы
с язы ками разм етки, мож ете бегло ознаком иться с
даппым издапием или использовать его как спра-
вочпик при чтеп ии даппой кпиги.

Мы также предусм от ре­


ли небольшое руководство
по размет ке HTMLS и CSS3
в приложении. Если вам
нужен краткий обзор ново­
введенийj то вы найдете его
в конце книги.

44 глава 1
знакомство с HTML5

Интервью недели:
Признания новой версии HTML

Head First: Д обро пож аловать, HTM L5. Весь Ип- пия последпих. К счастью, с людьми, работающими
терп ет просто гудит от разговоров о Вас. Как пам пад специф икациям и HTML5, мы полпостью схо­
кажется, Вы во мпогом похож и па HTM L 4. В чем димся во взглядах.
же п р ичи па всеобщ его аж иотаж а вокруг Вас?
Head First: В озвращ аясь к п реды дущ ей в ер си и
HTML5: Всеобщ ий аж иотаж объяспяется тем, что HTML, Вы отмечали, что являетесь расш ирепием
я предоставляю возмож пости по создапию совер- HTM L 4.01. То есть Вы обратпо совместимы с пей,
ш еппо пового п околеп и я веб-прилож епий и обе­ правильп о? О зп ач ает ли это, ч то Вам п р и д етс я
спечению качествеппого взаимодействия с пими. справляться с пе всегда удачпыми в плапе дизайпа
веб-страпицами из прошлого?
Head First: Согласеп, по почему HTM L 4 или казав­
шийся многообещающим XHTML пе сделали этого? HTML5: Обещаю, что приложу максимум усилий для
HTML5: XHTM L 2 оказался тупиковой ветвью эво­ того, чтобы справиться со всем, что мпе подкинут
лю ции. К аж ды й, кому д овелось п и сать код веб- из прош лого. Но отмечу, что это пе зпачит, что со
стр ап и ц п а это м язы к е , т е р п е т ь его больш е пе мпой так и нужпо обращаться. Я хочу, чтобы созда­
может. XHTML запово изобрел подход к паписапию тели веб-страпиц приобщ ались к повейш им стан­
разм етки веб-страпиц, которы й уже и так исполь­ дартам и использовали мепя паилучшим образом.
зуется, и пе привпосил в страпицы пичего пового. Благодаря этому опи смогут получить максимальную
Я сказал: «Постойте-ка, я ведь могу делать повы е отдачу от моего примепепия. Но, с другой сторопы,
вещи и п ри этом заключаю в себе все те возмож ­ я пе спасую и смогу обеспечить отображепие старой
пости , к о то р ы е сущ ествовали до мепя». Я имею веб-страпицы в силу своих возможностей, даже если
в виду, что если что-то работает, то зачем запово опа пе была м одерпизировапа до HTM L5.
и зобретать колесо. Такова моя ф илософ ия. Head First: М ой следующий вопрос звучит так...
Head First: Н о и звестп о ли вам, что п ек о то р ы е HTML5: Стойте, стойте!!! Все эти вопросы касаются
разработчи ки стандартов по-прежпему заявляют, прош лого. Мы с Вами пе говорим о том, что важпо
что И п тер п ету будет лучше, если оп стапет п р и ­ здесь и сейчас. П оскольку реч ь и дет о м оей р аз­
держ иваться их «безупречпых» стандартов? метке, хочу сказать, что моя персопальпая миссия
HTML5: Зпаете, мпе все равпо, что опи там говорят. заключается в том, чтобы охватить своими объяти­
Я прислушиваюсь к людям, которые реальпо запяты ями весь И птерпет, впедрить повы е структурпые
паписапием веб-страпиц: как опи используют мепя, элементы, облегчающие жизпь веб-разработчикам,
как я могу им помочь. Вторыми в моем списке идут и помочь всем создателям браузеров поддерживать
создатели веб-браузеров. А разработчики стандар­ согласованную семаптику вокруг разметки HTML5.
тов стоят в этом списке последними. Я стапу п ри ­ Но па самом деле я здесь для того, чтобы рассказать
слушиваться к их словам только при условии, что Вам о своем дополпительпом предпазпачепии: веб-
опи пе расходятся с мпепием пользователей. приложе...
Head First: Почему же? Head First: ...Жаль, HTML5, по паше время истекло.
Спасибо, в следующем иптервью мы обязательно
HTML5: Потому что если пользователи и создатели
поговорим обо всем, о чем Вы пож елаете.
браузеров пе согласпы с разработчикам и стандар­
тов, то это пав од ит па мысли о правильности мпе- HML5: Б-р-р -р, терпеть пе могу, когда так случается!

дальше ► 45
отзывы об html5

Просим встать НАСТОЯЩЕГО HTML5...


И так, вы терпеливо выслушали паше шуточпое повествовапие о «НТМ Ьб-модерпизаторе», и мы уве-
репы , что вы уже догадались о том, что HTM L5 представляет собой печто пампого большее, чем там
было сказало. Если поспраш ивать разпы х людей, то в ответ можпо услышать, что, по слухам, HTM L5
устрапяет необходимость в плагипах, мож ет использоваться повсюду, пачипая от просты х страпиц и
закапчивая играми типа Q uake, является кремом из взбиты х сливок па десерте. Каждый по-разпому
представляет себе, что такое HTML5...

HTM L5 — это все


о мультимедиа, о том, как
избавиться от плагинов, о воз­
можностях собственной под­
держки аудио и видео.

Вообще-то он касается создания


насыщенных клиентских интернет-приложе­
ний. Вместо того чтобы создавать их с помощью ин­
струментов вроде Flash, теперь я могу использовать
элемент canvas, трансформации и JavaScript для гене­
рирования классных интерфейсов и анимаций.

46 глава 1
знакомство с HTML5

Замечательная вещь в HTM L5 — хранение


информации на стороне клиента и кэши­
рование. Как вам возможность автономного
доступа к данным из Интернета?

Так здорово, что я могу исполь­


зовать Web W orkers для повыше­
ния эффективности моего JavaScript
и увеличения отзывчивости веб­
страниц.

В CSS также есть


масса всего нового, что
можно использовать вместе с HTML5:
продвинутые селекторы, анимации и — да,
эффект отбрасывания тени!

И не забудьте о мо­
бильных устройствах. Мне
нравится возможность создавать
страницы с поддержкой опре­
деления местоположения.

Хорош ая новость заклю чается в том, что HTML5 действительно является


всем тем, о чем сказано выше. Когда люди говорят о HTM L5, они имею т
в виду семейство технологий, которы е в сочетапии друг с другом образуют
целую повую палитру для создапия веб-страпиц и прилож епий.

дальше ► 47
как работает html5

Как на самом 9еле работает HTML5...


В приложении вы
И так, как было сказало выше, в оспове HTM L5 леж ит семейство техпологий, / • найдете замеча­
по что это зпачит? Ч то ж, как вам уже известпо, существует HTM L-разметка тельное Вебвилль­
сама по себе, которая была расш ирепа с целью вклю чепия ряда повы х эле- ское руководство
мептов. К роме того, с выходом CSS3 мпого пового появилось в каскадпых та­ по новой HTML-
блицах стилей, что откры ло еще более ш ирокие возмож пости по стилизации размет ке и свой­
веб-страпиц. Также существует турбопагпетатель под пазвапием JavaScript и ствам CSS3.
целы й повы й пабор API-иптерф ейсов JavaScript, доступпых вам.
Д авайте загляпем за кулисы и посмотрим, как все это объединяется.

Браузер загружает документ, вклю­ При загрузке страницы браузер также соз­
чающий HTML-разметку и CSS-стили. дает внутреннюю модель документа, ко­
торая будет содержать все элементы вашей
HTML-разметки.
г
т
WelcometotheHeadFirst [.nun^e- html

M body
I I I I
title script hi I h2 P
l
em
/
Для каждого элемента ...Это дерево называется объ­
в вашей HTML-размет ке ектной моделью документа
браузер создает объект,
объект, (Vocum ent object Model, РОМ),
который будет представ- g w б дете часто ст алки-
лять соответствующий ват ^ся с ней ходу кни­
элемент, и размещает ги, поскольку данная модель
его в древовидной ст р ук ­ играет важную роль в т ом ,
туре со всеми остальны­ как мы добавляем поведение
ми элементами... к веб-странии,ам с помощью
J a va S c r i p t (подробнее в главе £)■

Стиль страницы (при наличии такового) берет ­


ся из CSS3, который стал расширением CSS2
и включил в себя множество распространенных
_____ идиом, используемых в Интернете (например,
71 отбрасывание тени и закругленные углы).

Сг н и е м HTMLS р а з м е н „ р е в е л а ^

из них в * в ^ессе « «»»>■

48 глава 1
знакомство с HTML5

сЦ еной

При загрузке страницы браузер также


загружает ваш JavaScript-ко д , выполне­
ние которого обычно запускается сразу
после окончания загрузки страницы.

Применяя JavaScript, вы сможете взаимо­


действовать со своей страницей пут ем
манипулирования объектной моделью
документа (РОМ), обеспечивать реакцию
на действия пользователя или генериру­
емые браузером события либо использо­
вать весь набор новых API -интерфейсов.

JavaScript взаимодействует
с вашей страницей посред­ API -интерфейсы, также
ством объектной модели известные как интерфейсы
документа (РОМ). прикладного программирова­
ния (Application Programming
Interfaces), обеспечат для вас
набор объектов, методов и
свойств, которые вы сможе­
API-интерфейсы обеспечат вам до­ те использовать для дост у­
ступ к элементам a u d io и v id e o , па ко всей функциональности
20-рисованию с использованием этих технологий. Многие из
canvas, к lo c a lS to r a g e и прочим этих API -интерфейсов мы
замечательным технологиям, необ­ рассмот рим далее.
ходимым для создания приложений.
И не забывайте, что для использова­
ния всех этих API-интерфейсов необ­
ходим JavaScript.

Авто­ Local
номное
Знакомьтесь: кэширо­ Storage
API-интерфейсы вание
JavaScript
Web
Workers Geolocation
Forms

дальше ► 49
семейство html5

К Т 9 И НТ<

Мы с вами говорили о «семействе технологий» столько раз, что уже кажется, что мы сами одна семья. Однако мы
по-настоящему так и не разобрались в том, что конкретно они собой представляют, поэтому, наконец, сделаем
это. Ниже представлен перечень большинства членов этого семейства, посмотрите, сможете ли вы разобраться,
кто есть кто. Мы вас опередили и в качестве примера соотнесли одно из описаний с нужной позицией. Не бес­
покойтесь, мы знаем, что это ваша первая встреча с членами семейства HTML5, поэтому
ответы вы найдете в конце главы.

Используя мепя, вы мож ете рисовать прямо п а своей веб-страпице.


CSS3 Благодаря мпе можпо рисовать текст, изображ епия, липии, круги,
прямоугольпики, узоры, прим епять градиепты. Я помогу вам рас­
кры ть таящ егося в вас художпика.
М епя использовали в HTM L 4 для ввода и пф орм ации, по я стал
Web Workers
еще лучше в HTML5. Я могу требовать от вас заполпять все поля и
способеп проверять, ввели ли вы адрес электроп пой почты , URL-
адрес или пом ер телеф опа туда, куда требуется.
Forms Рапее для обеспечепия фупкциопальпости, апалогичпой пашей,
вам приходилось использовать плагипы , по теп ерь мы стали пол-
поцеппы м и члепами семейства элемептов HTML. Х отите посмо­
треть или послушать что-либо? Тогда мы нужпы вам.
Автономные веб-
Мы здесь для того, чтобы помочь вам со структурой и семаптиче-
прилоЖения
ским зпачепием ваш ей страпицы и обеспечить повы е способы соз-
дапия секций, заголовков, пиж пих колоптитулов и павигации па
ваших страпицах.
Audio и Video Я самый стильпы й во всем семействе. Зпаете ли вы, что теперь я
могу апим ировать ваши элемепты , придавать их углам закруглеп-
пость и даже обеспечивать эф ф ект отбрасы вапия тепи?

Новые элементы Используйте мепя как часть локальпого храпилищ а в браузере лю­
бого пользователя. Вам пеобходимо сохрапять устаповки, элемеп­
ражетки ты, помещ еппы е в электропную корзину, или, возмож по, даже п ри ­
п рятать больш ой кэш для увеличения производительпости? Тогда
я нужпый вам API-иптерфейс.
Local Storage
Вам требую тся прилож ения, способпые работать даже тогда, когда
отсутствует подклю чепие к Сети? Я могу вам помочь.

Canvas Я —API-иптерф ейс, которы й помож ет вам определить свое место­


полож ение, и отличпо работаю с К артами Google.

Я потребуюсь, когда вам будет пеобходимо, чтобы песколько сцена­


Geolocation риев вы полпялись параллельпо в ф оповом реж им е, благодаря чему
ваш иптерф ей с пользователя сможет оставаться отзы вчивы м.

50 глава 1
ВАШ А М и с с и я
■■■вели вы на нее со знакомство с HTML5

4% ,
%
Р СЯ'^ОСКОЛЬКу ИСТИНд
%

ВАША ПЕРВАЯ МИССИЯ:


с °1 *Ш Ч П Е 1 Щ о
РАЗВЕДКА В СТАНЕ БРАУЗЕРОВ
СЕК РЕТН О
ВАМ ПОРУЧАЕТСЯ ОПРЕДЕЛИТЬ
■ ■ И Н Н ТЕКУЩИЙ УРОВЕНЬ ПОДДЕРЖКИ ПО КАЖДОМУ ИЗ ПРИВЕДЕННЫХ
НИЖЕ БРАУЗЕРОВ (ПРИМЕЧАНИЕ: ВЫ СМОЖЕТЕ ОТЫСКАТЬ НУЖНУЮ ИНФОРМАЦИЮ ПО
АДРЕСУ H T T P ://WICKEDbYSMART.COM/HFHTML5/BROWSERSUPPORT.H T M L , Щ Щ Ш Ш Ш •
ПРИНИМАЙТЕ ВО ВНИМАНИЕ НОВЕЙШИЕ ВЕРСИИ БРАУЗЕРОВ. ПО КАЖДОМУ БРАУЗЕРУ,
ПРИВЕДЕННОМУ В СТОЛБЦЕ «БРАУЗЕР/ВОЗМОЖНОСТЬ», ОТМЕТЬТЕ ВОЗМОЖНОСТИ,
КОТОРЫЕ ОН ПОДДЕРЖИВАЕТ, А ЗАТЕМ ДАЙТЕ СВОЮ СУБЪЕКТИВНУЮ ОЦЕНКУ ТОГО,
НАСКОЛЬКО ХОРОШО ОН СОВМЕСТИМ С HTML5 Н Н Н Н В В В Н Н ’ ПО ВОЗВРАЩЕНИИ
ПРЕДСТАВЬТЕ ОТЧЕТ ДЛЯ ПОЛУЧЕНИЯ НОВОГО ЗАДАНИЯ*
Возможность

Автономные веб­
/

Storage

Geolocatoin

Workers

приложения
Canvas
Video

Audio

Web
Web
UJ

Firefox

Safari

Chrome

Устрой­ Mobile
ства под WebKit
уп р а в-
лением Opera
операци -
онны х с и ­ IE 6, 7
с т е м iO S
и A n d r o id
IE 8
(среди
прочих)
IE 9

дальш е ► 51
брэузерная разе едка

ВАША ПЕРВАЯ МИССИЯ


С О В ЕРШ ЕН Н О
%
РАЗВЕДКА В СТАНЕ
СЕКРЕТНО
БРАУЗЕРОВ Mbl немного схитрили при ответе и поставили флажки, ори -
ентируясь на ситуацию, которая сложимся к Z O I S году. Но ваши
ответы должны отражать положение вещей на момент чтения
книги. Нам кажется, вам будет интересно заглянуть в будущее.

Автономные веб­
Возможность

Storage

Geolocation

Workers

приложения
Canvas
0 0
$

Web
Web
0J
В!

i> 1

Firefox
/ / / / / !/ /
Safari
/ / / / / / /
Chrome
/ / / / / /
Mobile
WebKit / / / / / / /
Opera
/ / / / / / /
IE 6, 7

IE 8 /
IE 9 / / / / /

Поддержку, вы бу УеТСЯ Как°е-то врем я п


зоваться и м и з а д о л Шать’ Какие имепгю ^°’ ЧТобы стапдарт НТМ г к
О д ер ж и в а ю т ся сои Д° ЭТ° Г° события ф я РаузеРы Полностью ег ° брСЛ Повсеместну.«

глава 1
Г аС ™ ;“ — про.
И НС m m U ne'
знакомство с HTML5

Постойте-ка, если я начну использовать


HTM L5 прямо сейчас, разве не получится так, что я
оттолкну пользователей старых браузеров? Или мне
придется писать две варианта своих веб-страниц: один
для браузеров с поддержкой HTM L5, а другой — для
старых версий браузеров?

Притормозите, сделайте глубокий вдох.


Прежде всего HTML5 — расш ирение предыдущей вер­
сии HTML, поэтому вам придется писать только один
вариант своих веб-страниц. Вы правы в том, что возмож­
ности, поддерж иваемы е браузерами, могут отличаться
в зависимости от того, насколько новой является вер­
сия веб-обозревателя и как часто ваши пользователи об­
новляю т его. Таким образом, необходимо иметь в виду,
что некоторы е из новейш их возмож ностей HTML5
могут не поддерж иваться браузерами пользователей,
и это возвращ ает нас к вопросу о том, что делать в та­
ком случае.
Сейчас один из принципов HTM L5-дизaйнa подразу­
мевает, что своим страницам необходимо давать воз­
можность плавно деградировать, то есть если браузер
вашего пользователя не поддерж ивает какую-то новую
фупкцию, вы долж пы позаботься о достойпой альтерпа-
тиве для пего. В кпиге мы покаж ем вам, как писать свои
страпицы с учетом этого.
Х орош ая повость заклю чается в том, что все браузеры
двигаю тся по паправлепию к стапдарту HTM L5 и свя-
заппым с пим техпологиям (даже мобильпые браузеры),
в силу чего со времепем плавпая деградация стапет ско­
рее исклю чением, чем правилом (хотя вы всегда будете
хотеть сделать все возмож пое, чтобы обеспечить для
пользователей достойпое взаимодействие со своими
веб-страпицами независимо от того, какие браузеры у
пих будутустаповлепы).

дальше ► 53
общие вопросы html5
4acm°
Задаваем ы е
БоЭЭроСЬ!

»Я слышал, что стандарт HTML5 не получит статус финаль­ >Chrome, Safari, Firefox, множество мобильных браузеров...
ной [
НОИ рекомендации до 2022 года! Это правда? вам не кажется, что ситуация лишь усугубляется? Будут ли
наши страницы нормально работать во всех этих браузерах?
Q : W3C - :■это организация по разработке стандартов, которая
формально рекомендует стандарт HTML5. Входящие в W3C люди 0 : Несмотря на конкуренцию на рынке браузеров (для настольных
любят действовать осторожно, причем настолько, что предпочитают компьютеров и мобильных устройств), на самом деле большинство
дождаться, пока сменится несколько поколений НТМ1_5-браузеров, из них основано всего на нескольких общих HTML-движках. Напри­
прежде чем решиться сделать данный шаг. И это правильно, по­ мер, Chrome, Safari и мобильные браузеры для Android и iPhone
скольку со стандартом все окончательно утрясется в ближайшие базируются на Web К it, который представляет собой браузер ный
два года, а разработчики браузеров уверенно движутся по пути его движок с открытым исходным кодом. Поэтому веб-страницы, по
реализации. Так что, да, может пройти какое-то время, прежде чем большей части, смогут успешно работать в разных браузерах.
HTML5 обретет статус «финальной рекомендации». Ожидается,
что он станет стандартом уже к 2014 году, и использовать HTML5
в практических целях следует начинать уже сейчас.
В
б
А почему бы просто не использовать Flash, чтобы из­
бежать
ежа проблем с межбраузерной поддержкой?

Что произойдет, когда все окончательно решится с HTML5? Q : Flash - <- отличныи инструмент, который получил повсеместное
распространение в операционных системах и браузерах настоль­
0 : Появится HTML6? Мы понятия не имеем, но, вероятно, что бы ного сегмента. HTML5 со своим семейством технологий предлагает
там ни было, оно придет к нам вместе с летающими автомобилями, вам сделать с использованием открытых стандартов многое из того
ракетными костюмами и обедами в таблетках. Помните, что даже же, что и Flash. Что вам предпочесть? Задумайтесь о том, какой
если мы перейдем на HTML6, d o c t y p e не изменится. Если пред­ объем инвестиций в технологии HTML5 вкладывают такие компании,
полагать, что W3C сдержит свое обещание и будущие версии HTML как Google, Apple, Microsoft и др. В долгосрочной перспективе HTML5
окажутся обратно совместимыми друг с другом, то мы сможем без станет крупным игроком, а в мобильном сегменте он уже является
проблем перейти на нечто новое, что будет следующим на очереди. таковым. Выбор за вами, обе эти технологии будут в обиходе еще
долгое время, индустрия движется по направлению к открытым
стандартам.

археология
Мы провели раскопки и оьнаружили код, вложенный в HTML-страницу. Надеемся, вы
поможете нам взломать данный код и выяснить, что он означает. Мы не ожидаем от вас
толкования этого кода, а просто пытаемся разогреть ваш мозг, заставив его немного
порассуждать дедуктивным путем...

<script>
var w a l k s L i k e " d u c k 11 ;
var s o u n d s L i k e = d o c u m e n t . g e t E l e m e n t B y I d ( " s o u n d s l i k e " ) ;
i f (walksLike = = "dog") { Подсказка: docum ent пред­
s o u n d s L i k e .i n n e r H T M L = "Woof! Woo f ! " ;
ставляет целую HTML -
} e l s e if (walksLike == "duck") {
страницу , a getElem entBy Id,
s o u n d s L i k e .i n n e r H T M L = "Quack, Quack"
} else {
возможно, имеет от но­
s o u n d s L i k e .i n n e r H T M L = " C r i c k e t s . . . " ; шение к HTML-элемент ам
} и идентификаторам.
< / script>

54 глава 1
знакомство с HTML5

Я просто хочу сказать, что если


вы намерены серьезно заняться создани­
ем веб-приложений и использованием
HTM L5, то вам потребуются навыки работы
\ с JavaScript. ^

У нас к вам есть разговор.


Если вы рапее прочитали кпигу «Изучаем HTM L, XHTM L и CSS», то мы по­
лагаем, что вы, вероятпо, хорош о разбираетесь в использовапии язы ков
разм етки и таблиц стилей для создапия прекраспы х веб-страпиц. О риеп-
тируясь в обеих этих техпологиях, вы сможете преодолеть длиппы й нуть...
С появлепием HTML5 веб-страпицы превращ аю тся в пасы щ еппы е п рило­
ж ения, обладающие поведепием, обповляю тся па лету и взаимодействуют
с пользователями. Создапие страпиц подобпого рода требует изрядпого
труда программиста, и если вы собираетесь писать код, которы й будет вы­
полняться в браузере, то вам пеобходимо использовать JavaScript.
Если вам доводилось рапее запиматься програм м ировапием или папи-
&олее
сапием просты х сцепариев, то вам это пригодится: JavaScript (песм отря
увлека­
па слухи) является фаптастическим язы ком, и в этой кпиге мы поведаем тельного
вам обо всем, что пеобходимо зпать для паписапия прилож ений. Если же способа
у вас п ет опы та програм м ирования, мы сделаем все возмож пое, чтобы научиться
ввести вас в курс дела. В лю бом случае, одпим из огромпы х преимуществ програм ­
JavaScript является легкость его попим апия для программистов-повичков. мированию
Итак, что теперь? Д авайте кратко ознакомимся с JavaScript, а затем по- мы и пред­
пастоящему глубоко погрузимся в пего в главе 2. Н е старайтесь разобрать­ ставить
ся во всех деталях па п ротяж ени и пескольких следующих страпиц —здесь не можем!
вы долж пы лиш ь почувствовать, что такоеJavaScript.

дальше ► 55
что умеет javascript Взаимодействуйте со своими страницами новыми
способами, которые подходят как для настольного
сегмента, так и для портативных устройств.

Что моЖно С9елать с помощью JavaScript? * *

JavaScript открывает целый новый мир выражений


и функциональностей для ваших веб-страниц. Да­
вайте взглянем на ряд вещей, которые вы сможете
сделать с помощью JavaScript и HTML5...

£ p T » i! 7 гр» этом не потребуются никак»

Внедряйте в свои страницы под­


держку определения местополо­
жения, чтобы можно было узнать,
где находятся ваши пользователи,
показать им, что располагается
поблизости, помочь отыскать то,
что им нужно, задать им направле­
ние либо собрать людей с общими
интересами в одном месте.
Используйте Web Workers, чтобы ускорить свой
JavaScript-код и произвести важные вычисления
либо сделать свои приложения более отзывчивы­
ми. Вы даже можете еще эффективнее задейство­
j
вать потенциал многоядерных процессоров, уста­
новленных на компьютерах ваших пользователей!

Получайте доступ к любой


веб-службе и передавайте
полученные от нее данные
своему приложению почти в
режиме реального времени.

\ Кзшируйте данньые
локально, используя
исполь
Для воспроизведения
ораузерное хранилище видео больше не нужны
для ускорения работы специальные плагины.
мобильных приложений

Создавайте собственные
элементы управления вос­
Интегрируйте свои страницы
произведением, исполь­
с Картами Google и давайте
зуя HTML и JavaScript.
пользователям возможность
отслеживать их собственное
перемещение в режиме реаль­
ного времени.

56 глава 1
знакомство с HTML5

Попрощайтесь с браузер-
ными cookie-файлами и *
используйте локальное
хранилище в браузере.
Забрать ( D
вещи I Выпить Купить
из хим- ' К0Фе ехце один
чистки гаджет
Используя JavaScript, вы сможете сохра­ от ^ppie
нять множество установок и данных для
своих пользователей локально в брау­
зере и даже сделать так, чтобы к ним Слетать
на Фиджи Помыть
имелся автономный доступ. Испечь

Браузер теперь не просто


инструмент для просмотра
скучных документов. Благодаря
JavaScript вы сможете рисовать
пикселы прямо в окне браузера.

Зарядите свои формы по­


средством JavaScrip ,
бы обеспечить настоящую
эпюгп те Создавайте веб-страницы,
[ интерактивность.
повелся которые по-новому объединя­
_ яоклонник ются с видео.
Если вы ф утболк и TW
носите

Используйте мощь JavaScript


«Юtep для тщательной обработки видео
в своем браузере. Создавайте спец­
эффекты и напрямую манипулируй­
те отдельными видеопикселами.

Вы, вероятно, подумали, что мы об­


шарили весь Интернет, чтобы найти
наиболее захватывающие примеры.
На самом деле это не так. Мы просто
сделали скриншоты созданных нами
примеров, с которыми вы будете стал­
киваться в книге. Правда, они здорово
выглядят? Итак, теперь, когда вы уже
в Вебвилле, пришло время научиться
местному языку — JavaScript. Что ж,
приступим.

дальше ►
знакомство с javascript

jg ) B C "
С
Интервью недели:
Признания языка сценариев
Head First: Добро пожаловать, JavaScript. Мы рады, что Вы смогли выкроить для пас время в своем
плотпом граф ике. Позвольте сразу спросить вот о чем: HTML5 превращ ается в зпамепитость,
а как пасчет Вас??
JavaScript: Я пе стремлюсь быть в цептре впимапия, а остаюсь за кулисами. Я бы сказал, что пе-
малая часть похвалы, высказы ваем ой в адрес HTML5, долж па отпоситься ко мпе.
Head First: Почему Вы так считаете?
JavaScript: Существует целое семейство техпологий, которы е делаю т работу «HTML5», куда,
паприм ер, входят 2D canvas, localStorage, Web W orkers и др. А правда заклю чается в том, что для
того, чтобы действительно пользоваться ими, нужеп я. К опечпо, HTML5 позволяет создавать
веб-страпицы и представлять их впимапию пользователей, по без мепя у людей пе будет ипте-
респого взаимодействия с пими вообщ е. Но все пормальпо. Ж елаю успеха HTM L5, а я просто
продолжу делать свою работу дальше.
Head First: Что бы Вы посоветовали разработчикам , реш ивш им п ерей ти па HTML5?
JavaScript: Ну, здесь все просто. Если вы действительно хоти те овладеть HTM L5, п отратьте
врем я па изучепие JavaScript и всех библиотек, работаю щ их с HTML5.
Head First: Зпаете, у Вас пе всегда была хорош ая ренутация. В одпой из статей в 1998 году о Вас
высказались так: «JavaScript —это пезрелы й, вычурпый язы к сцепариев».
JavaScript: Это обидпо. Может, я и пе пачал свою ж изпь в безупречпой академической среде
мпогих язы ков програм м ировапия, по смог п реврати ться в одип из паиболее ш ироко использу­
емых язы ков всех времеп, поэтому па тот момепт я бы пе стал списывать мепя со счетов столь
опром етчиво. К роме того, в то, чтобы сделать м епя падежпым и крайпе эф ф ективпы м язы ком,
были вложепы огромпые ресурсы. Я стал быстрее по мепыней мере в 100 раз, чем был 10 лет пазад.
Head First: Это впечатляет.
JavaScript: Да, и если Вы еще пе слышали, то проипформирую Вас, что разработчики стапдартов
совсем педавпо пазвали мепя языком сцепариев по умолчапию для HTML5. Таким образом, я здесь,
чтобы остаться падолго. Замечу, что программистам больше пет нужды указывать J a v a S c r i p t
в своих тегах < s c r i p t > . Может, мепя и пазы вали вычурпым в 1998 году, по где теперь все эти
JScript, VBScript, Java-annTieTbi и проваливш иеся попы тки с браузерпыми языками?
Head First: Ч то ж, Вы действительно являетесь ключом к создапию отличпых НТМ Ьб-страпиц.
Но у Вас есть ренутация язы ка, с которы м возпикает нутапица.
JavaScript: Н есмотря па слухи, я являюсь очепь мощпым языком, и чтобы успеш по использовать
мепя, пеобходимо затратить пекоторое время п а изучепие. С другой сторопы , я понуляреп, по­
тому что мепя легко освоить. То есть я вобрал лучшее из обоих миров, как Вы считаете?
Head First: П охоже, что так опо и есть! Спасибо вам, JavaScript, заи п тервью .
JavaScript: Всегда пожалуйста.

58 глава 1
знакомство с HTML5

Пишем серьезный JavaScript


Д ерж им пари, что все эти разговоры о JavaScript разож гли в вас
ж елапие п ерейти, пакопец, пепосредствеппо к паписапию кода.
С ерия пе зря пазы вается «Изучаем...», и пиж е вас ож идает пагляд-
пое суперсерьезпое бизпес-приложепие, па котором мы скопцеп-
трируем ваше впимапие. Д ля пачала пройдитесь по коду, чтобы
прочувствовать его. Н апиш ите, что, как вам кажется, делает каж­
дая строка. Н е беспокойтесь, мы пе ожидаем, что вы с ходу во
всем разберетесь, по уверепы, что у вас будут успеш пые догадки
пасчет того, что делает этот код. Закопчив, п ереверп и те стра-
пицу и посм отрите, пасколько близко вам удалось подобраться
к правильпы м ответам...
Свои 0 №&&W\b\
N/ ил\лиШи\ЛЛ£ 3 dcct>-
о Э с ^ б ^ е с.«Ы
var drink = "Energy Drink" ; своего А
var lyrics = 6 w M 020 НЯ1Л.и^кЯ.

var cans = 99;

while (cans > 0 ) {


lyrics = lyrics + cans + " cans of "
+ drink + " on the wall <br>";
lyrics = lyrics + cans + " cans of "
+ drink + "<br>";
lyrics = lyrics + "Take one down, pass it around,<br>";

if (cans > 1 ) {
lyrics = lyrics + (cans-1 ) + " cans of "
+ drink + " on the wall <br>";
}

else {
lyrics = lyrics + "No more cans of "
+ drink + " on the wall <br>";
}
cans = cans - 1 ;

document.write(lyrics);

дальше ► 59
ваш первый javascript

Пишем серьезный JavaScript: проверка ваших ответов


Снова нройднтесь но коду и но см отрите, что нривлекло ваше внимание. Вам нужно
нросто нрочувствовать этот код; далее нош агово разберем ся во всех деталях.

var drink = "Energy Drink"; Объявляем первую переменную и п р и ­


сваиваем ей значение "Energy Prink"
var lyrics = ""; Объявляем вторую переменную и п р и ­
сваиваем ей пустое строковое значение.
v a r cans = 99; Объявляем трет ью переменную и п р и ­
сваиваем ей числовое значение <?<?.
Это цикл while. Он говорит: «Пока
количество банок превышает О, вы­
while (cans > 0 ) { полнять все, что заключено в ф игур­
ные скобки. Остановиться, когда банок
больше не останется»
/Добавляем следующую строку песни
lyrics = lyrics + cans + " cans of " в переменную lyrics с использованием
оператора конкатенации строк « + »
+ drink + " on the wall <br>"; Завершаем строку посредством разры­
ва строки HTML.
lyrics = lyrics + cans + " cans of " Повторяем снова.
+ drink + "<br>";
lyrics = lyrics + "Take one down, /Добавляем следующую строфу, снова
pass it around,<br>"; с использованием конкатенации.
if (cans > 1 ) { Если остались еще банки (то есть зна­
чение количества банок превышает 1)...
lyrics = lyrics + (cans-1) + " cans of " ...то добавить последнюю строку.
+ drink + " on the wall <br>";
}

else { в противном случае, когда банок


не осталось...
lyrics =lyrics + "No more cans of " ... добавить 11No more cans of 11 в конец
lyrics.
+ drink + " on the wall <br>";
}

cans = cans - 1; Уменьшаем количество оставшихся


банок на 1.

Мы сохранили все строки песни в пере­


менной lyrics, поэтому теперь даем
document.write(lyrics) ; веб-странице команду записать ее.
Это означает, что строка будет до­
бавлена на страницу, в результате чего
вы увидите текст песни.
60 глава 1
знакомство с HTML5

ТЕСТАРЛИ*
Вы же не думали, что, провернув всю сложную работу по выполнению упражнения, вы так и не подвергнете
практическому испытанию наш JavaScript-код? Вам необходимо взять код с предыдущей страницы и перенести
его (вместе с HTML-разметкой, приведенной ниже) в файл (например, index.html), а затем загрузить в браузере.
Результат можно увидеть внизу:

^ з а б ы в а й т е , ч т о для т о г о , ч т о б ы з а г р у з и т ь
<! doctype html> эт о№ весь к о д и ф а й л ы п р и м е р о в для к н и г и , с л е д у е т
з а й т и п о а д р е с у h t t p . / / w i c k e d ly s m a ir t . c o m / h f h t m ls .
< html>
<head>

<meta charset="utf- 8 ">

<title>MY First JavaScript</title>


</head> Теги <script> и </script> окружают JavaScript-код.
Они говорят странице, что все, что в них заклю­
чено, является JavaScript-кодом, а не HTML.

Сюда нужно вставить JavaScript-


код с предыдущей страницы.

;= s £ g = 2 -
А вот результат нашего тестового про­
**c«anоsврo5.fdP--JT,

tnin,PMi IktK
'‘rotM
und,
гона данного кода. Он генерирует текст
лирической песни о ЯЯ -бутылках банках w*i
%Scans<vfpn”tPWa
гш&а энергетического напитка на полке » «аз g**ona»'W aJ
и записывает его в документ браузера.

93fans<jf SniUod>

« с*вд^2й22?в,,,1в»«ц

tew»u

дальше ► 61
некоторые тонкости htm!5

Часш°
Задаваем ы е
В сЩ роСъх

Почему в теле приведенного ранее HTML- Вы используете термины «веб-страница»


f t
доку
документа нет ничего, кроме тегов script? и «веб-приложение»; под ними понимается
что-то разное? Что именно делает нечто веб­
приложением?
0: Мы решили начать с пустого элемента b o d y ,

0:
поскольку создали все содержимое данной страницы,
используя JavaScript-код. Да, можно было бы просто Это отличный вопрос, поскольку мы используем
внести текст лирической песни прямо в элемент b o d y эти термины в широком смысле. Технически никакой
(и при этом нам бы пришлось долго печатать на клави­ разницы между двумя этими понятиями нет; другими
атуре), либо мы могли позволить коду выполнить всю словами, вам не нужно делать что-то особенное для
тяжелую работу за нас (что мы и сделали), а затем того, чтобы превратить страницу, написанную на HTML,
дать ему команду вставить текст песни на страницу JavaScript и/или CSS, в веб-приложение. Появление
посредством d o c u m e n t . w r i t e . различий — это скорее одна из возможных перспектив.

Имейте в виду, что здесь мы пока прощупываем поч­ Когда у нас имеется страница, ведущая себя скорее
ву, а по ходу книги будем тратить намного больше как приложение, нежели как статичный документ, мы
времени, рассматривая то, как можно динамически начинаем думать о ней больше как о веб-приложении
заполнять страницу содержимым с помощью кода. и меньше как о веб-странице. Приложение мы рассма­
триваем как нечто такое, что обладает рядом особен­
ных качеств, например способностью поддерживать
Я понял, что мы сгенерировали весь текст
множество состояний, управлять более комплексными
лирической песни, но что конкретно сделал метод
взаимодействиями с пользователем, отображать
document.write и как текст попал в документ?
динамические и постоянно обновляемые данные без
необходимости в обновлении всей страницы или даже
0 : Метод d o c u m e n t. w r i t e берет строку текста выполнять более сложные задачи либо вычисления.
и вставляет ее в документ; фактически, он помещает
ее точно туда, где располагается тег s c r i p t . Та­ Весь этот JavaScript, конечно, замечательная
ким образом, в данном случае d o c u m e n t . w r it e вещь, но как насчет CSS? Мне не терпится восполь­
вставляет строку прямо в тело страницы. зоваться преимуществами CSSS-нововведений,
Вскоре вы познакомитесь с более тонкими способа­ чтобы улучшить внешний вид своих страниц.
ми изменения текста живого документа с помощью
JavaScript, а данный пример призван дать вам по­ 0 : Да, CSS прошел долгий путь, и мы с воодушев­
чувствовать, как код способен динамически вносить лением смотрим на то, насколько хорошо он работает
изменения в страницу. с HTML5. Несмотря на то что эта книга не о CSS, мы
с вами обязательно воспользуемся преимуществами
некоторых новых возможностей этого языка. Как вы,
возможно, знаете, многие из трюков, к которым мы
прибегаем для добавления закругленных углов и
теней на изображениях при использовании HTML и
создания простых анимаций на JavaScript, теперь мо­
гут быть с легкостью воспроизведены с помощью CSS.
Так что в этой книге мы воспользуемся мощью CSS
и обратим ваше внимание, когда это произойдет.

62 глава 1
знакомство с HTML5

Мы поговорили о массе вещей, включая


H TM L-разметку, A P I-интерфейсы JavaScript,
«семейство технологий» и CSS. А что именно
представляет собой HTML5? Не может же он
быть лишь простым языком разметки, кото­
рый сумел пробудить всеобщий интерес...

Дадим вам неофициальный ответ:

^ HTMLS*
Язык разметки + д
API -интерфейсы JavaScript + CSS = Пум.уим .... Щ■г

Отметим, что когда многие люди говорят о том, что такое


HTM L5, они подразумевают совокупность всех этих техно­
логий. То есть у нас есть язы к разм етки для н остроен и я ос­
н овн ой структуры страниц, JavaScript вместе со всеми сво­
ими API-интерф ейсами для добавления новедения и новой
функциональности, а также CSS для стилизации страниц —
все эти технологии мы будем иснользовать для создания
веб-нрилож ений завтраш него дня.
Но ночему же мы сказали «неофициальный»? Ч то ж, есть
люди, которы е лю бят нроводить ж есткие разграничитель­
ны е лин и и между этими технологиям и и говорить, к какому
стандарту относится каждая из них. Это в норядке вещ ей и
им еет место. Однако для нас важно вот что: какие техноло­
гии ноддерж иваю тся браузером и достаточно ли они п рора­
ботаны для того, чтобы иснользоваться для создания наших
страниц и нрилож ений? Н а наш взгляд, HTML5 —это язы к
разм етки + API-интерф ейсы JavaScript + CSS, и мы считаем,
что именно это, как нравило, имею т в виду люди, когда гово­
рят о HTML5 как о технологии.

Если вам действительно интересно , как


эти технологии объединяются в единый
набор стандартов (а интересовать это
должно каждого), то совет уем посет ит ь
ресурс w3.org для получения дополни­
тельной информации по данному вопросу .

дальше ► 63
ваш первый код на htm!5

]J°3A paBjlffeM , Б ы З а к о н ч и л и
f
и з д а т ь ГЛ аВ у Jи н а п и са Л и сВ о й

первы й Код н а 1 Л М §! ^ И свой первый код


J на JavaScript!
П режде чем н ерей ти к следующей главе,
вынолним еще одно задание на закренле-
ние изученного материала. И снользуйте
нриведенны е внизу карточки со словами
для составления формулы, реш аю щ ей
уравнение «что такое + HTML5?». Будьте внимательны , но-
скольку в эту кучу добавлены слова, которы е могут сбить вас
с толку. С нравивш ись с задачей, немного отдохните и осве­
ж итесь, а затем нристунайте к главе 2.

Г HTML5 I A P I -и н т е р ф е й с ы J a v a S c r i p t
JavaScript
CSS
XML ! Canvas I

R e d Vines M r . Pi b b
XHTML Forms
Язык
CSS3
I Geol o c a t i o n
I
<script>

64 глава 1
знакомство с HTML5

КЛЮЧЕВЫЕ
МОМЕНТЫ

■ HTML5 — это самая современная версия HTML. HTML5 включает элементы, которые привносят
Она включает новые упрощенные теги, а также новую семантику в станицы, открывая перед
семантические и медиаэлементы, полагается вами больше возможностей, связанных с соз­
на набор JavaScript-библиотек, обеспечиваю­ данием структуры веб-страниц, чем было в
щих функционирование веб-приложений. HTML 4.01. Мы не будем рассматривать их в
книге, однако в приложении вы найдете не­
■ XHTML больше не является стандартом для большое руководство по ним.
веб-страниц. Вместо него разработчики и W3C
решили продолжать расширять и совершен­ Для использования многих возможностей
ствовать HTML. HTML5 наилучшим образом вам потребуется
JavaScript.
■ Новое и более простое определение d o c ty p e
Применяя JavaScript, вы сможете взаимодей­
в HTML5 поддерживается старыми версиями
ствовать с объектной моделью документа
браузеров: когда они сталкиваются с ним, то
(Document Object Model, DOM).
переходят в стандартный режим.
Объектная модель документа (DOM) — это
■ Атрибут ty p e больше не требуется в теге
браузерное внутреннее представление веб­
< s c r i p t > или в ссылке на таблицу стилей
страницы. Используя JavaScript, вы сможете
CSS. JavaScript и CSS стали языками по умол­ получать доступ к элементам, изменять их,
чанию для HTML5. а также добавлять новые элементы в объект­
■ Тег < m eta> , используемый для указания набо­ ную модель документа.
ра символов, был упрощен и теперь включает API-интерфейсы JavaScript (Application
только кодировку символов. Programming Interface — интерфейс приклад­
ного программирования) позволяют управлять
■ UTF-8 сейчас является стандартной кодировкой
всеми аспектами HTML5 (20-рисованием, вос­
символов, используемой в Интернете.
произведением видео и др.).
■ Изменения в d o c t y p e и теге < m e ta > не ска­
JavaScript является одним из наиболее попу­
жутся отрицательно на страницах, загружаемых
лярных языков в мире. Реализации JavaScript
в старые версии браузеров.
значительно усовершенствовались за послед­
■ Совокупность новых элементов HTML5 пред­ ние годы.
ставляет собой расширенный набор элементов Вы можете выяснять, поддерживается ли та
HTML 4. Это означает, что старые страницы или иная новая функция браузером, и обе­
смогут нормально функционировать в совре­ спечивать плавную деградацию веб-страниц в
менных браузерах. случае отсутствия такой поддержки.
■ Работы над стандартом HTML5 не будут офи­ CSS — это стандартный язык стилей для
циально завершены до 2014 года, однако HTML5; многие люди вкладывают CSS в по­
большинство современных браузеров станет нятие «HTML5», когда используют его для опи­
поддерживать его задолго до этого (а многие сания семейства технологий, применяемых для
поддерживают уже сейчас!). создания веб-приложений.

дальше ► 65
кроссворд

Ц Щ 5 - К Г 0С С В 0Г Д

Н астало врем я дать отдохнуть нрав о му нолушарию вашего мозга и за­


ставить ноработать левое. В нриведенном ниж е кроссворде все слова
связаны с HTML5 и взяты из текущей главы.

По горизонтали По вертикали
3. __________ реклама, также называемая спамом. 1. Нам необходимо, чтобы деградация наших веб-страниц про­
4. Ваша миссия заключалась в том, чтобы провести___________ исходила ___________ .
в стане браузеров. 2. Новейшие____________ HTML5 привносят новую семантику
5. Инструмент, позволяющий обновить старый код до HTML5 и открывают дополнительные возможности, связанные с соз­
за три шага__________ . данием структуры веб-страниц.
9. Стандартный язык сценариев для HTML5. 6. Истинная мощь HTML5 заключается в __________ JavaScript.
10. Это определение теперь стало намного проще, чем было 7. Стандартный язык стилей для HTML5.
в версии HTML 4.01. 8. Тег <___________ > говорит браузеру, что все, что следует да­
12. Этот язык получил «прощальное письмо» в 2009 году. лее, является JavaScript-кодом, а не HTML.
14. Используйте цикл___________ для генерирования вывода 10. ___________ — это внутреннее представление веб-страницы.
строк песни. 11. Данный атрибут тегов l i n k и s c r i p t больше не требует­
15. JavaScript стал быстрее в раз, чем был 10 лет назад. ся, если вы используете HTML5.
13. Версия HTML, предшествующая HTML5.

66 глава 1
знакомство с HTML5

+
+
S f c e / * ! т?

Мы с вами говорили о «семействе технологий» столько раз, что уже кажется, что мы сами одна семья. Однако мы
по-настоящему так и не разобрались в том, что конкретно они собой представляют, поэтому, наконец, сделаем
это. Ниже представлен перечень большинства членов этого семейства, посмотрите, сможете ли вы разобраться,
кто есть кто. Не беспокойтесь, мы знаем, что это ваша первая встреча с членами семейства HTML5, поэтому
приводим решения задания.

Иснользуя меня, вы мож ете рисовать нрямо н а своей веб­


странице. Благодаря мне можно рисовать текст, изображ ения,
линии, круги, нрямоугольники, узоры, нрим енять градиенты.
Я номогу вам раскры ть таящ егося в вас художника.
М еня иснользовали в HTM L 4 для ввода и нф орм ации, но я стал
Web Workers еще лучше в HTML5. Я могу требовать от вас занолнять все
поля и снособен нроверять, ввели ли вы адрес электрон ной но-
чты, URL-адрес или ном ер телеф она туда, куда требуется.

Forms Ранее для обеснечения ф ункциональности, аналогичной на­


шей, вам нриходилось иснользовать плагины, но тен ерь мы
стали полноценны м и членами семейства элементов HTML. Хо­
Автономные веб- тите но см отреть или но слушать что-либо? Тогда мы нужны вам.
прилоЖения Мы здесь для того, чтобы номочь вам со структурой и семанти­
ческим значением ваш ей страницы и обеснечить новы е сносо-
бы создания секций, заголовков, ниж них колонтитулов и нави­
гации на ваших страницах.
Audio и Video
Я самый стильны й во всем семействе. Знаете ли вы, что тенерь
я могу аним ировать ваши элементы , нри давать их углам закру­
гленность и даже обеснечивать эф ф ект отбрасы вания тени?
Новые элементы
ражетки Иснользуйте меня как часть локального хранилищ а в браузере
лю бого пользователя. Вам необходимо сохранять установки,
элементы , помещ енны е в электронную корзину, или, возмож­
но, даже н рин рятать больш ой кэш для увеличения производи­
Local Storage
тельности? Тогда я нужный вам API-интерфейс.

Вам требую тся прилож ения, снособные работать даже тогда,


когда отсутствует подклю чение к Сети? Я могу вам номочь.
Canvas Я —API-интерф ейс, которы й номож ет вам онределить свое ме­
стополож ение, и отлично работаю с К артами Google.

Я нужен, чтобы несколько сценариев вы нолнялись нараллель-


Geolocation но в ф оновом реж име, благодаря чему ваш интерф ей с пользо­
вателя сможет оставаться отзывчивым.

дальше ► 67
I еэеиг gg

'V c fo g ^ > o c b l — ЁМН «ВР


egdosooodn епнетес!
2 Знакомство с JaVa^cript и объектной М°ДеЛь1°
Д о ку м ен та Ф о1» ) +

+ Немного кода*

Благодаря JavaScript вы откроете для себя нечто новое. Вы уже все


знаете о HTML-разметке (иначе называемой структурой) и CSS-стиле (также
известном как представление), однако вам недостает знаний о JavaScript
(или, как еще говорят, поведении). Если ваш багаж знаний ограничивается
лишь структурой и представлением, то вы, конечно же, сможете создавать
прекрасно выглядящие страницы, однако они будут лишь простыми стра­
ницами. Но если вы добавите поведение, прибегнув к JavaScript, то сможете
обеспечить для своих пользователей интерактивное взаимодействие; либо,
что даже еще лучше, вы сможете создавать роскошные веб-приложения.
Приготовьтесь добавить в свой инструментарий веб-разработчика наиболее
интересные и универсальные знания о JavaScript и программировании!
X. Ае-сли вам н у ж н а дополнительная мотивация,
то и наиболее, полезные!
как работает javascript

Как работает JavaScript


Наша цель заключается в том, чтобы написать JavaScript-код,
который будет выполняться в браузере после загрузки веб­
страницы. Данный код мог бы, например, реагировать на дей­
ствия пользователя, обновлять или изменять страницу, общаться
с веб-службами и, в целом, создавать ощущение, что ваша стра­
ница ведет себя скорее как приложение, нежели как обычный до­
кумент. Давайте посмотрим, как это все работает.

<html>
<head>
<script>

</script>
<body>
0
<hl>My first JavaScript</hl>
< p x /p > | html"
<script>
X = X + 2;
</script>
| head~ body
</body>
</html> | title | script [ | hi ^ | h2 \| p [
\~errT\

Написание Загрузка Выполнение


О
Вы пишете свою разметку Браузер извлекает и загружает JavaScript-код продолжает
на HTML и код на JavaScript, вашу страницу, осуществляя выполняться, используя DOM
а затем сохраняете их в фай­ разбор ее содержимого сверху для исследования страницы,
лах, скажем, i n d e x . h t m l вниз. ее изменения, получения от нее
и i n d e x . j s (либо и то и дру­ событий или запроса браузера
Когда браузер обнаруживает
гое в одном HTML-файле). на извлечение дополнительных
JavaScript-код, он разбирает его
данных с веб-сервера.
и проверяет на правильность,
после чего выполняет этот код.
Браузер также создает внутрен­
нюю модель HTML-страницы,
называемую объектной моде­
лью документа (DOM).

Л
70 глава 2
javascript и dom

Что моЖно сделать с помощью JavaScript?


Если у вас имеется страница с элементом < s c r i p t >
(или со ссылкой на отдельный JavaScript-файл), то вы
готовы нристунать к нанисанию кода. JavaScript явля­
ется нолноценным языком нрограммирования, с номо-
щью которого можно сделать очень многое из того, что
нредоставляют другие языки, и даже еще больше, но­
ско льку вы будете программировать внутри страницы!
JavaScript нозволяет следующее.

О Ф орм ировать операторы


Создавайте переменные и присваивайте им значения, склады­
вайте числа, производите другие вычисления, используйте
встроенную функциональность библиотек JavaScript.

var temp = 98.6;


var beanCounter = 4;
var reallyCool = true;
var motto = "I Rule";
temp = (temp - 32) * 5 / 9 ;
motto = motto + " and so do you!";
var pos = Math.random () ;

ф Д е л а т ь ч т о - т о дваЖды, неоднократно

Выполнение операторов может осуществляться снова и снова, столько раз,


сколько вам потребуется.

while (beanCounter > 0 ) {


processBeans();
beanCounter = beanCounter - 1;
}

О Принимать решения
П иш ите условный код, зависящий от состояния вашего приложения.

if (isReallyCool) {
invite = "You're invited!";
} else {
invite = "Sorry, we're at capacity.";

дальше ► 71
объявление переменных

Объявление переменной
П ерем енны е содерж ат данные. В случае с JavaScript они могут содержать
массу различны х вещей. Д авайте объявим несколько нерем енны х, содер­
жащих данные. winners
Целочисленные значения .
var winners = 2 ; Или числовые значения с плаваю - boilingPt
var boilingPt = 212.0; точкой.
var name = "Dr. Evil"; 4 Или строки символов
(кратко «строки»).
var isEligible = false;
Или логические значения
(true или false).
name
Три шага по созданию переменной
isEligible

v a r sco o p s = 1 0 ; Переменные—
П ервы й шаг заклю чается в объявлении нерем енной, в данном слу­
этоконтейнеры
чае s c o o p s . Следует отметить, что JavaScript, в отличие от неко­
торы х других язы ков, не требует указания тина нерем енной, а нро-
длязначений.
сто создает кон тей н ер общего тина, в котором мож ет содерж аться JavaScript-
масса вещей:
иеременные
неимеютстрогих
scoops
типов, поэтому
Далее нам необходимо значение, которое будет размещ аться в не­
любаяизних
рем енной. Указать значение можно несколькими снособами: можетсодержать
Значение может быть литеральным ,
например числом или строкой.
числовое,
var scoops = 10; Или значение может быть
результат ом оценки вы­
строковое
var scoops = totalScoops / people;
var scoops = Math.random () * 10;
ражения. нлнлогическое
значение.

72 глава 2
javascript и dom

<3> Н аконец, у нас имею тся нерем енная и значение (лите­


ральное значение, нанрим ер 10, или результат оценки О синтаксисе
вы раж ения (вроде totalScoops / people). И все, что
нам осталось сделать, — нрисвоить значение наш ей
нерем енной.
■ Каждый оператор должен заканчиваться
точкой с запятой.
х = х + 1;

■ Однострочный комментарий должен на­


чинаться двойным слешем. Коммента­
рии — это просто заметки о коде, пред­
scoops
назначенные для себя или для других
Создав неременную , вы, конечно же, сможете изм енить ее разработчиков. Они никак не оцениваются.
значение в лю бой момент или даже нрисвоить ей значение, / / Э то ком м ентарий
имею щее другой тин. Вот ряд нримеров:
■ Пробелы неважны (почти везде).
м ы можем присвоить переменной
£— scoops, другое целочисленное значение. х = 2233;

scoops = 5 ; Или даже использовать scoops ■ Строки символов следует заключать


в выражении, которое изменит в двойные кавычки.
scoops = scoops * 1 0 ; ее значение. В данном случае "Y o u r u l e ! 11
значение scoops будет равно 50.
■ Переменные необходимо объявлять с ука­
scoops = "Tired of being an integer"; занием v a r и имени. JavaScript не требу­
f4 Либо мы можем изменить значение ет указывать тип в отличие от некоторых
scoops = null; и тип переменной scoops, в данном других языков программирования.
случае — на строковое значение v a r w id t h ;
t
3 JavaScript даже и соответственно тип. Но будьте
■ Не заключайте в кавычки логические зна­
есть значение, кото осторожны, поскольку это может
привести к большим проблемам чения t r u e и f a l s e .
рое означает «зна­
чения нет». Оно на­ в коде, если вы ожидаете, что scoops r o c k i n = t r u e ;
зывается null. О его будет иметь числовое значение.
■ Переменным необязательно присваивать
использовании мы Подробнее об этом — чуть позже.
значения при объявлении:
поговорим позже.
Ч асцю var w id t h ;
^адаВ аеМ ы е
БоЦр»оСьх

Каким будет значение моей переменной, если я просто 1Мне доводилось иметь дело с другими языками програм­

напишу так: мирования, в которых переменные объявляются с указанием


типа. Например, i n t х или S t r i n g у. Разве в JavaScript
var w in n e r ; нет типов?

0: После выполнения данного оператора переменной winner


будет присвоено значение undefined, которое является другим
значением и типом JavaScript. О том, где и как его использовать,
0 :'! В JavaScript есть типы, однако, в отличие от других языков, он
предусматривает динамическую типизацию, которая означает, что
мы поговорим позже. интерпретатор JavaScript сам определит, какой тип использовать.

дальше ► 73
присвоение имен переменным

( ^ ь е З Н о е п р о г р а м м и р о в а н и е 1

Как присваивать имена переменным


У вас мог возникнуть вонрос: «А как вы бирать им ена для
своих неременных?». Если вам доводилось нрисваивать
им ена идентиф икаторам в случае со своими HTM L- В JavaScript n u m b e r , s t r i n g
элементами, то аналогичная нроцедура в отнош ении и B o o l e a n называются прими­
нерем енны х нокаж ется вам схожей. Есть только не­ тивными типами. В переменных
сколько нравил нри ф орм и рован ии имен неременны х. также можно сохранять объекты.
Об объектах мы поговорим до­
вольно скоро, а пока вы можете
Правило 1. Начинайте имена своих переменных с буквы, рассматривать объект как кол­
лекцию некоторых вещей, тогда
символа подчеркивания или знака доллара.
как примитив — это просто вещь,
П ри грамотном нрисваивании имен своим нерем енны м которая не может быть разделе­
необходимо не нросто нридумывать им вы разительны е на на что-либо еще.
названия, но также иснользовать букву (в ниж нем или
верхнем регистре), символ подчеркивания или знак
доллара в начале их имен. Вот ряд нримеров:

var thi s IsNo tAJoke ; Имя начинается с числа ,


var 3zip;
а это неправильно.
var _myVariable; var %entage;
var $importantVar; Имя начинается с недопу­
.var ~approx;
стимых символов (% и ~).
*
Правильно Неправильно

Правило 2 . З а т е м вы моЖете указывать любое количество букв,


цифр, символов подчеркивания или знаков доллара.
П родолж айте иснользовать буквы, знаки доллара и символы под­
черкивания н ри ф орм и рован ии имени своей нерем енной. После
нервого символа вы также н ри ж елании мож ете указывать числа:
S---
my3sons; Здесь имеется недопустимый пробел var zip code;
cost$; var first-name
Знаки « - » и «±» недопусти­
vitaminBl2; var to+do;
мы и сильно сбивают с толку
^ JavaScript.
Правильно Неправильно

74 глава 2
javascript и dom

Правило 3 . избегайте всех зарезервированных слов JavaScript.

Я зык JavaScript вклю чает ряд зарезервированны х слов, нанрим ер i f , e ls e , w h ile , f o r (это
лиш ь часть из них), и не будет слишком лю безен, если вы ноны таетесь иснользовать их в качестве имен
для своих нерем енны х. П еречень зарезервированны х слов JavaScript нриведен ниже. Н е нужно сию же
минуту заноминать их, но ходу освоения JavaScript у вас вы работается нонимание, что же они собой
нредставляю т. Но если когда-либо JavaScript станет «ругаться» н а то, как вы объявили свои нерем енны е,
то вам следует мыслить следующим образом: «Хм, а может, слово, которое я нытаю сь иснользовать,
является зарезервированны м?».

abstract delete goto null throws


as do if package transient
boolean double implements private true
break else import protected try
byte enum in public typeof
case export instanceof return use
catch extends int short var
char false interface static void
class final is super volatile
continue finally long switch while
const float nam espace synchronized with
debugger for native this
default function new throw
x* Избегайте использования этих слов
'— в качестве имен для переменных!
Часто
Задаваем ы е ........
В опросы

l b ™ — Чувствителен ли JavaScript к ре­ Как я понял, JavaScript позволяет


рованное слово как часть имени своей гистру? Другими словами, есть ли присваивать нужное значение перемен­
переменной? Могу ли я присвоить пере­ разница между написанием myvariable ной (числовое, строковое и т. д.) в любой
менной, например, имя ifOnly (то есть в и MyVariable? момент. Однако что произойдет, если я
ее имени будет содержаться зарезерви­ добавлю две переменные, одна из ко­
рованное слово if)? 0 : Если вам доводилось иметь дело в ос­ торых будет иметь числовое значение,
новном с HTML-разметкой, то, возможно, вы а другая строковое, вместе?
0 : Конечно можете, просто избегайте привыкли к нечувствительным к регистру
точного совпадения имени переменной с языкам, ведь, в конце концов, < h e a d > и 0 : JavaScript старается осуществлять
зарезервированным словом. Также целе­ < h e a d > трактуются браузером как одно и умное преобразование типов по мере не­
сообразно писать понятный код, в котором, то же. Однако в случае с JavaScript регистр обходимости. Например, если вы добавите
как правило, не используются слова вроде имеет значение, поэтому m y v a r ia b le и сразу две переменные с числовым и строко­
e lz e , которое можно перепутать с e ls e . M y v a r ia b l e будут рассматриваться как вым значениями, то он, как обычно, попы­
две разные переменные. тается преобразовать числовое значение в
строковое и конкатенировать их. Не во всех
ситуациях это нужно. Держите эту мысль
в уме, мы вернемся к ней совсем скоро.

дальше ► 75
присвоение имен переменным

Вебвилльское руководство
по вы бору оптим альны х имен
Вам предоставляется немалая свобода при выборе имен для своих переменных, поэтому
мы возьмем на себя смелость дать несколько советов, чтобы облегчить вам эту задачу.

Отдавайте предпочтение именам, которые что-то означают


Такие имена переменных, как, например, _ш, г и f о о , могут что-то означить для вас, однако в Вебвил­
ле на них, как правило, смотрят неодобрительно. Не только потому, что вы сами, скорее всего, забудете
их со временем, но и в силу того, что ваш код будет более удобочитаемым, если вы предпочтете ис­
пользовать в нем переменные с именами вроде a n g l e , c u r r e n t P r e s s u r e и p a s s e d .

При формировании имен переменных из нескольких слов используйте стиль


CamelCase
В определенный момент у вас возникнет необходимость решить, как указать имя переменной, которая
олицетворяет, скажем, огнедышащего двуглавого дракона. Просто используйте стиль CamelCase, кото­
рый подразумевает, что первая буква в каждом новом слове должна указываться в верхнем регистре
(кроме слова, идущего первым): t w o H e a d e d D r a g o n W i t h F i r e . Стиль CamelCase прост в ис­
пользовании, широко распространен в Вебвилле и обеспечивает достаточную гибкость в формировании
настолько специфических имен переменных, насколько вам потребуется. Существуют также и другие
подходы, однако этот является одним из наиболее часто используемых (даже за пределами JavaScript).

Используйте переменные, имена которых начинаются с символов _ и $, только


по очень веской причине
Переменные, имена которых начинаются с $, обычно зарезервированы для JavaScript-библиотек и, не­
смотря на то что некоторые программисты используют переменные с именами, начинающимися с сим­
вола в силу различных соглашений, они не имеют широкого хождения. Мы рекомендуем держаться
от них подальше, если только у вас не будет веской причины поступить иначе (если она появится, вы,
естественно, будете это знать).

Будьте осторожны
Проявляйте осторожность при присваивании имен переменным. Далее в книге мы дадим еще
ряд советов по этой теме, а пока знайте, что для переменных нужно выбирать понятные имена,
избегать зарезервированных слов и всегда указывать v a r при объявлении переменной.

76 глава 2
javascript и dom

ВыраЖения
Мы с вами уже видели, что представляют собой операторы JavaScript:

О п е р а т о р Ja v a S crip t

sc o o p s = sc o o p s - 1;
П еременная
—^ ]
^ '— 1/--------------
v
^
г ^ а а В ы раж ение
П рисваивание г

Однако давайте более пристально взглянем на выражения вроде того, которое приведено в дан­
ном операторе. Оказывается, выражения повсеместно встречаются в JavaScript, поэтому важно
знать, какого рода вещи вы сможете выражать. Вот ряд примеров...

Вы м о ж е т е п и с а т ь в ы р а ж е н и я ,
р е з у л ь т а т о м оцен ки к о т о р ы х
б у д у т чис ло вы е значения... Вы м о ж е т е п и -
с а т ь вы раж ения, ^
результ ат ом Логические ВыраЖения
о цен ки к о т о р ы х
Числовые Выражения б у д ут логические
2 > з
s ta r tT :ime >
nov
(9/5) * tempC + 32
зн а ч е н и я t r u e tenqpF < 7 5

и л и false (они level == 4


* - 1 соот вет ст вен­ = "Duck"

Math. random() * 10 но н а з ы в а ю т с я
логическим и вы ­
2.123 + 3.2 ра ж е н и ям и ).

...a т а к ж е п и с а т ь в ы р а ж е н и я , р е з у л ь т а
т о м о цен ки к о т о р ы х б у д у т с т р о к о в ы е
зн ачен и я.

Строковые выражения Также с у щ е с т в у ю т д р у г и е


т ипы выраж ений, о к о т о ­
"super" + "cali" + youKnowTheRest р ы х м ы п о г о в о р и м позже.

♦ -2 1 - * - f P
phoneNumber. substring (0 , 3) Прочие выражения

function ()
Внимательно отнеситесь к выражениям, представленным
document.getElementByld("pink")
на нескольких следующих страницах (не говоря уже об
оставшейся части книги), и вы поймете, как они использу­ new Array (10)
ются для проведения вычислений, многократного повто­
рения действий и принятия решений в вашем коде.

дальше ► 77
упражнение

г Возьми в руку карандаш


В ы р ази те себя!
Ранее вы познакомились с различными типами вы­
Взяв за основу свои текущие зна­
ражений, которые можно использовать в JavaScript-
ния о переменных, выражениях
коде. Теперь пора применить эти знания на практике
и операторах JavaScript, посмо­
и самим оценить несколько выражений. Свои отве­ трите, сможете ли вы сказать, ка­
ты вы сможете проверить в конце главы. кие из этих операторов являются
допустимыми, а какие приведут
(9/5) * tempC + 32 к выводу ошибки.

Каким окажется результат, если значением te m p C будет 10? В приведенном ниже перечне об­
ведите допустимые операторы.

"Number" + " " + "2м va r х = 1138;

Какова будет результирующая строка? . va r у = 3 /8 ;

va r s = "3 -8 ";

level >= 5 x = у ;

Каким окажется результат, если значением l e v e l будет 10? va r n = 3 - 11o n e " ;

va r t = "o n e " + "tw o " ;


А каким окажется результат, если значением l e v e l будет 5?
va r 3po = tru e ;

Подсказка: « / » va r le v e l_ = 11;
color != "pxnk"
% означает «не».
va r h ig h N o o n = fa ls e ;
Каким окажется результат, если значением color
будет blu e ? ______________ va r $ = 2 1 .3 0 ;

va r z = 2000;
(2 * Math.PI) * г
va r is B ig = у > z;
Каким окажется результат, если значением г будет 3?
z = z + 1;

с П одсказка: Math.Pl возвращ ает


з н а ч е н и е п и (о н о , к а к вы з н а е т е ,
z— ;

z y ;
р а в н о 3 ,П4 ...)
x = z * t;

w h ile ( h ig h N o o n ) {

z— ;

Так выражаться не стоит!

78 глава 2
javascript и dom

Похоже, что все идет как по маслу, если


я прибавляю числа к числам, а строки
к строкам, но что, если я прибавлю число
к строке или целочисленное значение
к числу с плавающей точкой?

Помните, мы говорили, что программирование на JavaScript


легко освоить? Одна из п ричин этого заклю чается в том, что
JavaScript сам преобразует одни типы в другие но мере необхо­
димости, чтобы вы раж ения имели смысл.
В качестве прим ера допустим, что у вас имеется следующее вы­
раж ение:

m essage = 2 + м if by sea";

Нам известно, что символ + мож ет как иснользоваться для


слож ения чисел, так и выступать оператором конкатенации
строк. Так какую же роль он вы полняет в данном случае? Ч то ж,
JavaScript знает, что строка " i f b y s e a " никогда не станет
похож ей на число, поэтому он решает, что перед ним строковое
вы раж ение, преобразует 2 в строку "2м и присваивает нерем ен­
ной message значение "2 i f b y s e a " .
Л ибо, если у нас будет такой онератор:

v a lu e = 2 * 3.1;

JavaScript нреобразует целочисленное значение 2 в число с нла-


ваю щ ей точкой, а результат будет равен 6.2.
Как вы уже догадались, JavaScript не всегда делает то, что вам
нужно, и в некоторы х случаях ему требуется небольш ая номощ ь
в осущ ествлении преобразований. К этой теме мы вернем ся не­
много нозже.

Ш ТУ РМ
Каков будет результат оценки следующих операторов со стороны
JavaScript?
numORStringl = 113 м + "4м

numORS tring2 = "3м * "4м

И почему?

дальше ► 79
javascript итерации

while (j u g g l i n g ) {
keepBallsInAir() ;
}

Многократное выполнение одного и того Же...


Е сли бы в JavaScript-HporpaMMe все вынолнялось лишь один раз, то она, скорее
всего, была бы довольно скучной. Вы сами неоднократно делаете массу вещей:
сноласкиваете голову водой, наносите шампунь, затем снова новторяете про­
цедуру, нока ваши волосы не станут чистыми, либо нродолжаете ехать до тех
нор, нока не достигнете места назначения, либо непрерывно чернаете моро­
женое ложкой, нока не съедите его нолностью. Для обработки нодобных ситу­
аций JavaScript предусматривает несколько снособов циклического выполне­
ния блоков кода.

Вы можете иснользовать JavaScript-цикл w h i l e для того, чтобы делать что-то


до тех нор, нока удовлетворяется соответствующее условие:

у нас имеется банка мороженого, в которой его


осталось г о ложек. Вот переменная, которую мы
объявляем и инициализируем значением ZO.
Цикл while использует логическое выражение результат ом
t i Z u к о ^ г о г о Л ж ,™ f a m e true « ш М и . В true » Э ,
расположенный далее, будет выполняться
var scoops = 10;
Пока ложек мороженого будет оставаться более нуля, мы
г- ^ продолжим выполнять все, что имеется в этом блоке кода.
while (scoops > 0) { г ч у
alert ("More icecream!11) ;

scoops = scoops - 1;
При каждом выполнении цикла while мы уведомляем
пользователя о том, что мороженое еще осталось
а затем удаляем одну ложку мороженого пут ем ее '
вычитания из общего числа ложек.
alert("life without ice cream isn't the same");

^ ■ Когда значением условия (scoops > О) становится


false, цикл завершается, а выполнение кода продол­
жается здесь, независимо от того, какова будет
следующая строка программы.

80 глава 2
javascript и dom

V
Таким образом, в нрим ере с циклом w h i 1 е мы инициализируем значение, в данном
случае —ноказатель количества оставш ихся лож ек м орож еного, которы й проверяет­
ся циклом w h i l e , и если выдается t r u e , то мы выполняем блок кода. В результате
работы этого блока кода в определенны й момент нроисходит обновление вовлечен­
ного в нр о верку условия ноказателя до такого уровня, нри котором значением условия
становится f a l s e и цикл заверш ается.
ИНИЦИАЛИЗИРОВАТЬ

var scoops = 10;

ОСУЩЕСТВЛЯТЬ ПРОВЕРКУ УСЛОВ1


while (scoops > 0 ) {
ВЫПОЛНЯТЬ ДАННЫ Й ълок
alert ("More icecream!11) КОДА, ПОКА ПРОВЕРКА
УСЛОВИЯ В Ы Д А Е Т T R U E
scoops = scoops - 1;
ОБНОВЛЯТЬ
> ПРОДО ЛЖ АТЬ ВЫПОЛНЕНИЕ К О Л А
/ ------- ЗД Е С Ь ПОСЛЕ Т О Г О , К А К П РО ВЕРКА
^ УСЛОВИЯ В Ы Д А С Т FALSE
alert("life without ice cream isn't the same");

JavaScript также предусматривает наличие цикла f o r , которы й еще больше формализует данную
структуру. Вот как будет выглядеть наш код из н рим ера с морож еным, нерен и сан н ы й с прим енени­
ем цикла f o r :
ИНИЦИАЛИЗИРОВАТЬ
ОСУЩЕСТВЛЯТЬ ПРОВЕРКУ УСЛОВИЯ
I \ ^ ------ ОБНОВЛЯТЬ

ВЫПОЛНЯТЬ ДАННЫЙ БЛОК


for (scoops = 10; scoops > 0; scoops— ) {
КОДА, ПОКА П РО В ЕРК А
alert("There 1s more ice cream!") ; ^ УСЛОВИЯ В Ы Д А Е Т TRUE

ПРОДО ЛЖ АТЬ ВЫПОЛНЕ­


НИЕ К О Д А З Д Е С Ь ПОСЛЕ
alert("life without ice cream isn't the same")
ТОГО, К А К ПРОВЕРКА
УСЛОВИЯ В Ы Д А С Т FALSE
Ч асцю

................................................... Зад аваем ы е ..............................................................


В сЩ роСъх

В • Я не вижу никакой разницы между циклами while и for. Как понять, когда следует использовать каждый из них?

0 : В целом, вы сможете выполнять одни и те же задачи, используя либо цикл f o r , либо цикл w h i l e . Однако, как вы
могли убедиться в примере с мороженым, цикл f o r обеспечивает немного большую компактность, a w h i l e делает код
более удобочитаемым. Как правило, циклы f o r чаще используются для совершения итераций по фиксированному количеству
значений (например, по элементам, помещенным в электронную корзину в интернет-магазине), a w h i 1 е чаще применяются
для циклического выполнения чего-либо до тех пор, пока удовлетворяется соответствующее условие (например, заставлять
пользователя проходить тест до тех пор, пока он не сделает все правильно).

дальше ► 81
упражнения

СТАНЬ 6раумр«м
К а ж д ы й из п о в ед ен н ы х на эт< > й с т р а н и ц е J a V a ^ c I ip t- Фрагмент 1
с^раГменшоБ представляет со£ой ©цельный £лок
var count = 0;
Т С °Д а . ^ а Ш а задач а З а к л ю ч а ется В т °М , Ч т °# ы сы ­
for (var i = 0; i < 5; i++) {
г р а т ь р °Л ь бр аузер а и оД ен и т ь В се
count = count + i;
^ р а Щ е н т ы К °Д а д л я о щ В ет а н а В о­

п росы ° р е з у л ь т а т а х . J J a n u H iu m e с В о й
alert (11count is 11 + count);
о щ В ет н а к а ж д ы й В опрос п о д с о о т в е т ­

ств ую щ и м ^ р а Щ ен т °М . Какой показатель общего


количества будет отображен
Свои ответы вы сможете в диалоговом окне alert??
ФрДГМСМП2 проверить в конце главы.

var tops = 5;
while (tops > 0 ) {
for (var spins = 0; spins < 3; spins++) {
alert("Top is spinning!");
}
tops = tops - 1;

Сколько раз на экране появится Фрагмент 3


диалоговое окно alert с сообще­
for (var berries = 5; berries > 0; berries— ) {
нием "Top is spinning!"?
alert("Eating a berry");

Сколько ягод вы съели? ^


Фрагмент 4
for (scoops = 0; scoops < 10; scoop++) {

alert("There1s more ice cream!");

}
alert("life without ice cream isn't the same");

Сколько ложек мороженого вы съели?

82 глава 2
javascript и dom

if (c a s h ln W a lle t > 5) {
o rd e r = “I'll tak e th e works: cheeseburger, frie s and a coke
} else {
o rd e r = "I'll ju s t have a glass o f water";

Принятие решений с использованием JavaScript


Мы с вами иснользовали логические вы раж ения в онераторах for и while для н роверки условий
с целью реш ить, долж но ли нродолж аться циклическое вы нолнение. Их также можно исноль­
зовать для н р и н яти я реш ений в JavaScript-коде. Рассмотрим нример:

__ Вот наше логическое выражение, используемое для проверки


количества оставшихся ---------- - • прооерки
ложек мороженого.
Когда останется менее трех ложек , мы будем
if (scoops < 3) { выполнять соответствующий блок кода.
alert (нIce cream is running low!11) ;
}
Мы также можем предусмотреть нроведение более чем одной Бы сможете добавить нужное
нроверки: количество проверок с использо­
ванием else if, каждая из которых
if (scoops < 3) {
будет ассоциирована со своим
alert("Ice cream is running low!"); блоком кода> выполняемым , когда
} else if (scoops > 9) { значением условия является true.
alert("Eat faster, the ice cream is going to melt!");
}

дальше ► 83
javascript условия

Принятие дополнительных решений... и добавление


перехватывающего блока
Вы мож ете предусмотреть нерехваты ваю щ пй блок для своих он ераторов i f — ф иналь­
н ы й e l s e , которы й будет вынолняться, если все н рочи е условия окажутся оценены как
f a l s e . Д авайте добавим еще несколько i f / e l s e , а также нерехваты ваю щ ий блок:

Обратите внимание , что мы внесли изменение


Т ~ > а к? то°Р °г0 соответствующее сообщение
if (scoo* s — з> t выведено только тогда , когда количество
if (scoops — 3 ) { ложек окажется равным именно 3.
alert("Ice cream is running low!");
} else if (scoops > 9) {
alert("Eat faster, the ice cream is going to melt!");
} else if (scoops == 2) {
alert("Going once!"); Мы добавили дополнительные
условия для того , чтобы обрат­
} else if (scoops = 1) {
ный отсчет шел до нуля ложек.
alert("Going twice!");
} else if (scoops == 0) {
alert("Gone!");
} else {
alert("Still lots of ice cream left, come and get it.");
, *
A „ „аш n e p e x f W , 1 л о к есяи ш одно т ^ т Ш ^

тся.
/
ш.

пражнение Возьмите приведенный выше код и вставьте его в цикл w h i l e внизу. Пройдитесь по цик­
лу w h i l e и напишите сообщения диалоговых окон a l e r t в той последовательности,
в которой они будут выводиться. Проверить свои ответы вы сможете в конце главы.

v a r scoops = 1 0;

w h il e (s c o o p s > = 0 ) {

Вставьте сюда код> приведенный вверху .

s c o o p s = s co o p s
T
Генерируемый вывод
напишите здесь.
a le r t( " lif e w it h o u t i c e c re a m i s n ' t th e s a m e " );

84 глава 2
javascript и dom

развлечения с м а гн и т а м и
Данный код отображает известный палиндром в диалоговом окне a l e r t . Проблема заключа­
ется в том, что часть кода находилась на магнитных табличках, прикрепленных к холодильнику,
однако они упали на пол. Ваша задача заключается в том, чтобы восстановить целостность кода
и отобразить палиндром. Будьте внимательны, поскольку на полу уже лежало несколько табличек,
не имеющих отношения к данному коду, зато некоторые из табличек вам придется использовать
более одного раза! Проверьте свои ответы в конце данной главы, прежде чем двинетесь дальше.

var wordl = "а”;


var word2 = "nam"; h ttp ://Jo Ca lh o s t

var word3 = "nal p M; a a plan a canal panama.

var word4 = "lan a c" ;


var word5 = "a man ap" ;

Палиндром — это пред­


var phrase = MM;
ложение, которое одина­
ково читается как слева
for (var i = 0; ) { направо; так и справа
if (i == 0) { налево! Бот палиндром ,
phrase = _____ который вы должны
увидеть?, если правильно
} разместите все таблички
else if (i == 1) { на магнитах по м ест ам .
phrase = _____ + word4;
}
(i == 2) {
= phrase + wordl + word3;

) {
phrase = phrase + + word2 + wordl;

}
alert(phrase);

else if (i == 0) w ord5

i++ else if
J |^^Tord2
phrase
word4 i < 3 vro£ a i 1 < 4

ГШ Л I 1 [Т Т 7 Г ) C D Г 1- I i = 3
] [ word3

дальше ► 85
как добавлять javascript в веб-страницы

Мне сказали,
что мы будем добавлять
JavaScript в свои веб-страницы.
Когда мы, наконец, займемся этим?
Или так и будем ходить вокруг да око­
ло, разбираясь в JavaScript?

Да, в ТОМ-ТО и дело. Для начала вам необ­


ходимо было изучить основы. Как раз этим
мы и занимались до сих пор: теперь вы зна­
ете, как объявлять и использовать перем ен­
ные JavaScript, а также как осущ ествляется
ф орм ирование базовых операторов и вы ра­
жений. Кроме того, вы узнали, как исполь­
зовать их все вместе для написания условно­
го кода с операторам и i f / e l s e , не говоря
уже о циклическом вы полнении с прим ене­
нием операторов w h i l e и f o r .
Вооружившись этими знаниями, теперь вы
мож ете переходить к изучению того, как
добавлять JavaScript в свои веб-страницы и,
что более важно, как JavaScript взаимодей­
ствует с ними. То есть вы узнаете, как опре­
делять, что имеется на вашей странице, как
ее изм енять и, чуть нозже, как нисать код,
реагирую щ ий на то, что нроисходит на ва­
ших страницах.
Таким образом, несм отря на то что мы еще
не закончили с JavaScript, вашему ожида­
нию нриш ел конец. Настало врем я взгля­
нуть, как разм етка и новедение работаю т
сообща...

86 глава 2
javascript и dom

Как u куда добавлять JavaScript в своих страницах


Ч тобы иснользовать JavaScript, его необходимо добавить в страницу. Но куда именно и как? Вы уже
знаете, что существует такой элемент, как < s c r i p t > , ноэтому давайте носмотрим, где мы можем ис­
нользовать его и как это влияет на вы нолнение JavaScript-кода на ваших страницах. Рассмотрим разны е
снособы добавления кода в страницу.

Разместите свой <script> как встроен­


Поместите элементы <scnpt> в <head> ный элемент в <head>.
своей HTML-страницы, чтобы их выполнение
Н аиболее расп р о стр ан ен н ы й снособ до­
осуществлялось до загрузки страницы.
бавления кода в страницу заклю чается в
номещ ении элемента < s c r i p t > в <head>
Вы можете стр ан и ц ы . Если вы д о б ави те Jav a S c rip t-
внести т р е ­ код в элемент <head>, то он будет выпол­
H T M L -файл н ять ся, как только б раузер осущ ествит
буемый код
прямо в код разбор < head> (а делает он это в нервую
| <head > очередь!), но до того, как разбору подверг­
своей веб- \
страницы <script> нется остальная часть страницы.
либо внедрить statement
Добавьте свой <script>, воспользо­
ссылку на </script>
вавшись ссылкой на отдельный
отдельный
I <script src="mycode.js"> JavaScript-файл.
JavaS cript-
файлj вос­ 1</script> Вы также можете указать ссылку на отдель­
пользовавшись ны й файл, содерж ащ ий JavaScript-код. П о­
атрибутом местите URL-ссылку на файл в атрибут s c r
scr тега script <body> откры ваю щ его тега < s c r i p t > и убеди­
тесь, что вы закры л и элем ен т s c r i p t с
номощью < / s c r i p t > . Если вы указы ваете
<script> ссылку н а файл, располож енны й в том же
Или вы м о ­
statement каталоге, то мож ете нросто иснользовать
жете п о ­
statement имя этого файла.
местить
</script>
свой код (либо Добавьте свой код в элемент <body>
ссылку на него) документа либо как встроенный, либо
в элемент посредством ссылки на отдельный
<body> Д а н ­ файл.
ный код будет
■ Чащевсего код добавляется в <Wead>
выполняться , Кроме того, вы можете номестить свой код
страницы. Добавление кода в <body> нрям о в < body> своей H TM L-страницы .
когда загру­
страницы дает небольшие пре­ Онять-таки, заключите свой JavaScript-код
зится тело имущества в плане производитель-
документа. в элем ен т < s c r i p t > (или укаж ите ссыл­
Hocmuj однако поступать так ку н а отд ел ьн ы й ф ай л в атри буте s c r ) .
следует только в т ом случае> если JavaScript в <body> вашей страницы станет
вам действительно необходимо вынолняться, когда браузер будет осущест­
сверхоптимизировать производи­
влять разбор тела страницы (обы чно он
тельность своей страницы. делает это сверху вниз).

дальше ► 87
взаимодействие со страницей

Как JavaScript Взаимодействует с вашей страницей


JavaScript и HTML— это две разные вещи. HTML представляет собой
разметку, a JavaScript — код. Так как же заставить JavaScript взаимо­
действовать с разметкой на своей странице? Для этого необходимо
воспользоваться объектной моделью документа (DOM).

Зам браузер о При загрузке страницы в браузе­


ре он осуществляет разбор HTML
и создает внутреннюю модель Это мы называем
Л документа, которая будет содер­ объектной моделью
жать все элементы вашей HTML- документа (РОМ),
разметки. посредством ко т о ­
рой можно узнать
все о структуре
и содержимом веб­
html
страницы.

head body

| title | script || [ h2

О
Сокращенно мы также
называем ее просто РОМ .

Ваш JavaScript может взаимо­


действовать с объектной моде­
лью документа с целью полу­
чения доступа к элементам и их
Когда JavaScript модифицирует содержимому. JavaScript также
© объектную модель документа использует DOM для создания
(DOM), браузер автоматически или удаления элементов (и вы­
обновляет JavaScript страницу, полнения множества других
благодаря чему на ней отобра­ манипуляций, о которых мы по­
жается новое содержимое. говорим позже).

П осредст вом счит ы вания, реагирования


и и з м е н е н и я о б ь е к т н о й м о д е л и до

2 Т Г 1 JavaScHpt мож^
веб- r ! М На.писания интеРактивных
-страниц/приложений. Из данной
книги вы узнаете, как это делается

88 глава 2
javascript и dom

Рецепт приготовления собственной объектной модели документа (D 0 M )


Д авайте возьмем разметку и создадим для нее объектную <! doctype html>
модель документа (DOM ). Рецент здесь нрост. <html lang="en">
<head>
И н гр ед и ен ты
<title>My blog</title>
О дна норм альная НТМ Ьб-страница <meta charset="utf-8">
<script src="blog. js"X/script>
О дин веб-браузер или более </head>
<body>
<hl>My blog</hl>
Порядок д е й ств и й
<div id=Mentryl">
1. Сначала создайте узел d o c u m e n t, которы й будет рас­ <h2>Great day bird watching</h2>
полагаться в самом верху. <P>
Today I saw three ducks!
document I named them
Huey, Louie, and Dewey.
2. Затем возьм ите элемент верхнего уровня вашей </p>
<P>
HTM L-страницы (в нашем случае это элемент < h tm l> ),
которы й будет именоваться текущим элементом, и до­ I took a couple of photos...
</p>
бавьте его в качестве дочернего элем ента но отнош е­
</div>
нию к d o c u m e n t. </body>
</html>
document j

1 html |

3. В случае с каждым элементом, влож енны м в текущий


элемент, добавьте соответствую щ ий элемент в качестве
дочернего но отнош ению к текущему в объектной моде­
ли документа (DOM).
Мы заранее годность» приго­
товили для вас объектную мо­
document j дель документа. Переверните
страницу - и вы увидите,
как выглядит готовая D0M.
html |

head body |

4. В ернитесь к каждому из только что добавленны х вами


элементов и н овторяйте нроцедуру (шаг 3), нока не до­
бавите все необходимы е элементы.

дальше ► 89
внедрение объектной модели документа

Первое испытание объектной модели документа (D 0 M )


Вся прелесть объектпой модели докумепта заклю чается в том, что опа обеспе­
чивает для пас согласоваппый между всеми браузерами способ получепия досту­ Мы сравнили
па к структуре и содержимому HTM L из кода. И это здорово. А через песколько данную с т р у к ­
мгповепий мы с вами посмотрим, как все это работает... т у р у с деревом,
поскольку « д е ­
Верпемся к примеру. Если вы последуете приведеппому рапее рецепту приготов­ рево» — это
лен и я объектпой модели докумепта, то в результате у вас получится структура, ст руктура
изображ еппая чуть пиж е. Каждая DOM вклю чает объект docum ent, располага­ данных, которая
ю щ ийся вверху, после чего общее дерево дополпяю т ветви и узлы-«листья» для берет свое начало
каждого элем епта в HTM L-разметке. Д авайте взгляпем па пих более пристальпо. в инф орм ат ике.

О бъект d o cu m en t — /
это словно корень
перевернутого с ног
на голову дерева.
L i= :
Z l rn d Z Цемент а.
Эти объекты подобны
^ вет вям дерева.

Эти объекты сродни л и ­


Great Today I took a
ст ьям на дереве (поскольку day bird I saw couple of
внут ри них нет элем ент о в, watching three.. photos...
а имеется только текст).
Объектная модель документа включает содержимое ^ У
страницы, а также элементы (мы не всегда показываем
текстовое содержимое, когда приводим рисунки РОМ,
однако оно т а м п р и с у т с т в у е т ) .
Теперь, когда у нас
имеется объектная модель
документа (DOM ), мы можем
исследовать и изменять ее так,
как нам потребуется.

90 глава 2
javascript и dom

’"-- -+Иhttp Сlio-UXJ9^


Movie Showtimes
Plan 9 from Outer Space
Playing и З ЛОрт. 7:00pm. Spedal Д о И л * щ Д О и midnight!

Forbidden Planet
Playingat5Л0рсп.9:00pm.

СТАНЬ браумром <! doctype html>


<h tml 1ang=11en11>
p a llia ЗаД аЧ а З а к л ю ч а е т с я Б m °M ,
<head>
Ч щ обы сы Г р а ш ь р°Л ь браузера.
<title>Movies</title>
|) а М н е о б х о д и м 0 о с у щ е с т в и ш ь
</head>
разбор -р а З М е т К и и со з­
<body>
д а ш ь Н а 00 оСНоВ0 c B o jo с ° ^ с ш Б 0 н —
<hl>Movie Showtimes</hl>
HTJIO о £ Ь 01С щ н у 1о М °Д 0 Л ь Д°КХ)М0Н—
<h2 id=Mmovieln >Plan 9 from Outer Space</h2>
т аФОМ)- П°э1Г,оМУ — вперед. <p>Playing at 3:0 Орш , 7:0 0pm.
произведите разбор шмь <span>
К о то р ы й н ах о д и тся справа,
Special showing tonight at <em>midnight</em>!
-DO M н а р и с у й т е В низу. Ц а Ч а Л о
</span>
о ^ Ь 0 К т н о й М °Д 0Л и Д о к у М 0 н т а М ы
</p>
у Ж 0 н а р и с о В а Л и , а В аМ п р 0 Д с т ° и т
<h2 id=nmovie2M>Forbidden Planet</h2>
00 з а в е р ш и т ь .
<p>Playing at 5:00pm, 9:00pm. </p>
</body>
Проверьте свои о т в е т ы , </html>
посмотрев решение этого
задания в конце главы,
прежде чем двинетесь
Д ор и су й т е здесь свою POM.
дальше. | docum ent |

1 1 i

дальше ► 91
отношения между javascript и dom

Или история о том, как две абсолютно разные


технологии смогли работать сообща.
HTML и JavaScript, несомненно, прилетели с двух
разных планет. Доказательства? ДНК HTML состоит
из декларативной разметки, позволяющей описывать
P JTM L5 - набор вложенных элементов, входящих в состав
веб-страницы. JavaScript, с другой стороны, сделан
Q из чисто алгоритмического генетического материала,
призванного описывать вычисления.
ja v a S c r ip 1 '
Настолько ли они разные, что даже не способны взаи­
, Венеры модействовать друг с другом? Конечно же, это не так,
т .1чесК ое Р Г ; поскольку у них есть кое-что общее — объектная мо­
„ о у » 4* дель документа (DOM). Посредством DOM JavaScript
воде” „v-wnr®1 может взаимодействовать с веб-страницами, и наобо­
рот. Существует несколько путей сделать так, чтобы
это произошло, однако мы пока сконцентрируемся на
одном из них— на своего рода небольшой червоточи­
не, позволяющей JavaScript получать доступ к любому
элементу, и называется она getElementByld.

Давайте посмотрим, как она работает...

92 глава 2
javascript и dom

Давайте иачием с DOM. Чуть пиж е приведеп п рим ер простой объектпой модели докумепта. Здесь
имеется песколько HTM L-параграфов (< р > ), каждый из которы х обладает i d со зпачепием соответ-
ствеппо g r e e n p l a n e t , r e d p l a n e t и b l u e p l a n e t . Все параграф ы также содерж ат текст. К опечпо,
здесь есть и элемепт < h e a d > , одпако мы отбросили детали в целях простоты .

р id = "greenplanet" j р id = "redplanet"~| p id = "blueplanet"

All is Nothing to All systems


well report A-OK

Теиерь давайте задействуем JavaScript, чтобы стало ии тересиее. Допустим, пам пеобходимо изме-
пить текст п араграф а с i d в виде g r e e n p l a n e t с " A l l i s w e l l " па " R e d A l e r t : h i t b y p h a s e r
f i r e ! " . В будущем вам мож ет потребоваться печто подобпое, в зависимости от действий, п редпри н и ­
маемых пользователем, или от даппых веб-службы. Обо всем этом мы еще поговорим, а пока обповим
текст параграф а с i d в виде g r e e n p l a n e t . Вот код, которы й позволит пам это сделать:

Как вы п о м н и т е , d ocu m ent


предст авляет всю страницу
в браузере и целиком содержит
объектную модель докум ент а,
поэт ом у мы можем « п о п р о ­ Здесь мы просим d o c u m e n t о т ы ­
с и т ь» его чт о-либо сделать: скать э л е м е н т , значение id к о т о ­
нап р и м ер , найти элем ент рого со о т вет ст в ует заданному.
с определенным значением id.

d o c u m e n t .g e t E l e m e n t B y l d (" g r e e n p l a n e t " ) ;

•..после чего
g e tE le m e n tB y ld (‘'greenplanet") возвра­
J a v a S crip t-код
сможет сде­
щ ает элем ен т <р>> значение id к о т о ­
л а т ь с ним
рого с о о т в е т с т в у е т "greenplanet11...
много чего
интересного.

дальше ► 93
использование getelementbyid

Как только getE lem entB yld возвратит требуемы й элемент, вы см ож ете сделать с ним
что-нибудь (папример, измепить его текст па "R e d A l e r t : h i t b y p h a s e r f i r e ! " ) .
Для этого обы чпо требуется присвоить элем епт п ерем еппой, благодаря чему па пего мож-
по будет ссылаться повсюду в своем коде. Д авайте сделаем это, а затем измепим текст:

З д е сь м ы в ы з ы в а е м getElementByld,
Мы присваиваем элемент который отыщет и возвратит
переменной с именем planet. f элемент "greenplanet ''.

i
var planet = docume n t . g e t E l e m e n t B y l d ( " g r e e n p l a n e t " ) ;
I
Теперь мы можем использовать
в своем коде переменную planet
для ссылки на наш элемент.

>1,
p l a n e t .innerHTML = "Red Alert: hit b y phaser fire!";

_ /
Мы^можем использовать
свойство innerHTML на­
7
Мы заменяем содержимое элемента greenplanet
шего элемента planet на наш новый текст... в результате чего объ­
для изменения содержимо­ ектная модель документа (и веб-страница) будет
го требуемого элемента. обновлена с использованием этого нового текста.

О свойствах элементов мы
вскоре погорим подробнее...

| р id =^ re e n p la n e t^ j| | р id = V e d p la n e t“ ] | р id = “blueplanet

Red Alert: hit by Nothing to All systems


phaser fire! report A-OK

г
Любые изменения в объектной модели документа отражаются
на т о м j как браузер осуществляет рендеринг страницы , п о ­
этому вы увидите , что содержимое параграфа стало другим!

94 глава 2
Возьми в руку карандаш javascript и dom

Вот объектная модель документа (DOM),


в которой скрыто тайное сообщение. Раз­
беритесь в приведенном ниже коде, чтобы
раскрыть секрет! Ответ на задание в пере­
вернутом виде вы найдете внизу страницы.

document.getElementByld (11е7" )
document.getElementByld (11е8" )
document.getElementByld ("е1б")
document.getElementByld ("e9" )
document.getElementByld (Mel8")
document.getElementByld ("el3" )
document.getElementByld ("el2 ")
document.getElementByld ("e2" )

воз-
Hп и ш и т е , какой и м ен н о э л е м е н т
1ЛЛДК~
в р а щ а е т каждая из с т р о к кода а
тобы
же со д е р ж и м о е э т о г о э л е м е н т а ,
раскрыть т а й н о е с о о б щ е н и е .1

-(„Qwixvidg xw ? d g
QWlfiHdzgOVI X£QV?H он
f F )h viH V d \M V Q VZVH
-d?g?d?v i онж о]^}„)
q.ovi j.Yiq s'dSvd yvvq
vi л щ v\vo y)o\ „ :wi?gwiQ

дальше ► 95
тестирование кода dom

Tecm-драйб планет
Рапее вы уже видели, как использовать d o c u m e n t. g e tE le m e n tB y ld
для получепия доступа к элементу, a innerHTM L —для изм епепия его
содерж имого. Теперь давайте сделаем это по-пастоящему.
Н иж е приведепа HTM L-разметка веб-страпицы Planets; здесь у пас
имеется элем епт < s c r i p t > в <head>, куда мы будем помещ ать код,
и тр и п араграф а со зпачепиям и i d соответствеппо g r e e n p l a n e t ,
r e d p l a n e t и b l u e p l a n e t . Если вы еще этого пе сделали, то добавь­
те HTM L и JavaScript для обповлепия объектпой модели докумепта
(DOM):
<! doctype html>
<html lang="en">
<head> Мы добавили JavaScript
<title>Planets</title> в <kead> страницы.
<meta charset="utf-8">
<script> Точно т ак же, как и раньше,
var planet = document.getElementByld("greenplanet") s r мы извлекаем элем ент <р>
planet.innerHTML = "Red Alert: hit by phaser fire!" с id в виде "greenplanet" и и з -
</script> ^ *меняем его содержимое.
</head>
<body>
<hl>Green Planet</hl>
Элемент <р>, содержимое
<p id="greenplanet">A11 is well</p>
которого мы изменяем
<hl>Red Planet</hl> с помощ ью JavaScript.
<p id="redplanet">Nothing to report</p>
<hl>Blue Planet</hl>
<p id="blueplanet">All systems A-OK</p>
</body>
</html> О оо ©Janets
*■ -> с л О localhost/~Beth/HTML.. |Г| ф Р , ^ ^

Добавив требуемый код, загрузите страницу в сво­ G r e e n P la n e t


ем браузере, после чего вы увидите, какие волшеб-
пы е м етам орф озы произош ли с параграф ом, имею ­ АД is weH

щим id в виде g r e e n p l a n e t , в объектной модели


докумепта (DOM). R e d P la n e t
01 Х ь ю с т о н , у нас пробле-
Nothing to report
ма: в параграфе с id в виде,
greenplanet по-преж нему
B lu e P la n e t
отображается "All is well"
3 чем дело? All systems A-OK

96 глава 2
javascript и dom

Я трижды перепроверил
[ свою разметку и код, но все равно
О V ничего не получается. Я не вижу ни­
каких изменений на своей странице

Ах да, мы забыли упомянуть об одной вещи.


Чащ е всего имеет смысл начипать вы полпепие своего
JavaScript-кода после того, как страпица полпостью за­
грузится. Почему? Если же вы пе стапете ждать, пока
закончится загрузка страницы , объектпая модель до­
кумента не успеет полностью сгеперироваться, когда
ваш код начнет выполняться. В пашем случае выпол­
нение JavaScript-кода начинается после того, как бра­
узер сначала загрузит элемент < h e a d > страпицы , по
до того, как будет загружена остальпая часть страпицы ,
поэтому объектная модель докумепта окажется еще пе
полностью сгенерированной. А если DOM пе готова,
то и элемент <р i d = " g r e e n p l a n e t 11> пе будет суще­
ствовать!

И что же тогда происходит? Вызов g e t E l e m e n t B y l d


с целью поиска элем епта с i d в виде g r e e n p l a n e t пе
приведет к возврату чего-либо, поскольку соответству­
ющ ий элемепт будет отсутствовать, из-за чего браузер
просто продолж ит двигаться дальше и так или ипаче
произведет репдерипг страпицы после того, как ваш
код выполпится. П оэтому в результате вы увидите
страпицу, прошедшую репдерипг, по текст в параграф е
с i d в виде g r e e n p l a n e t остапется прежпим.
Нам пеобходимо как-то сообщ ить браузеру следующее:
«Выполпять мой код после того, как страпица полпо­
стью загрузится и будет создала объектпая модель до­
кумепта». П осмотрим, как это сделать.

дальше ► 97
ожидание загрузки страницы

Нельзя начинать взаимодействовать с D 0M ,


пока веб-страница не загрузилась полностью
Но как приказать браузеру в ы п о л п я т ь ваш код только после того, как страпица загрузится?
Ч тобы дать указапие браузеру ожидать, преж де чем пачипать вы полпепие кода, мы восполь­
зуемся двумя JavaScript-ипструмептами, с которы м и мы вас еще пе успели позпакомить: это
объект window и фупкция. П одробпее о пих мы поговорим позже, а пока просто воспользуем­
ся ими, чтобы добиться пужпого эф ф екта.
О бповите свой JavaScript, как показало пиж е

Сначала создайте ф у н к ц и ю О б ра т ит е внимание


с именем init и п о м ест ит е на то, что ваш код
в нее уже имеющийся у вас код. должен располагаться
<script>
между открывающей
function init() {
и закрывающей ф и г у р ­
var planet = document.getElementByld ("greenplanet") ными скобками.
p l a n e t .innerHTML = "Red Alert: hit b y phaser fire!"

. я --------------------------------------------------------------------------------
Здесь мы задаем значение
window.onload = init; свойства window.onload
в виде имени нашей функции.
< /s c rip t>
Здесь говорится: «когда
страница полност ью з а ­
Перезагрузите страницу грузится, выполнить код,
располагающийся в init».
Теперь перезагрузите страпицу и посм отрите, все ли встало па свои места:

ООО PEanets
I< |► 1|+ |0 http:f/localhosl/-BethyHead- (5 ](От Google ")»
Да! Теперь в элемент е <р> с id в виде
greenplanet отобразилось новое содер­
G re e n P la n e t жимое. Здорово, не правда ли?
Red Alert: hit by phaser fire!

R e d P la n e t Что ж, на самом деле здорово ТО,


что т еперь вы знаете, как п р и к а ­
Nothing to report зат ь браузеру ждать, пока не будет
полност ью сгенерирована объектная
B lu e P la n e t модель документа, прежде чем вы­
полнят ь код, который обращается
All systems A-OK
к элементам.

98 глава 2
javascript и dom

Возьми в руку карандаш


Ниже приведена HTML-разметка веб-страницы My Playlist, на ко­
торой отображается список песен для воспроизведения (плей­
HTML для лист), однако он пока пуст. Вам нужно завершить JavaScript-
/г* веб-страницы.
<! doctype html> код, чтобы песни добавились в список. Заполните пробелы в
JavaScript-коде, который необходим для выполнения данной
<html lang=nen">
задачи. Проверьте свои ответы, посмотрев решение этого за­
<head> дания в конце главы, прежде чем двинетесь дальше.
<title>My Playlist</title>
<meta charset="utf-811> Это наш J a v a S crip t Данный код б у ­
дет обеспечивать заполнение списка
<script>
песнями, указанными внизу, в <ul>.
____________ addSongs() {
Заполнит е пробелы недоста­
var songl = document.__ ю щ им кодом, чтобы песни
<" были добавлены в список.
.getElementByld (11 ”)
J
.innerHTML "Blue Suede Strings, by Elvis Pagely";
"Great Objects on Fire, by Jerry JSON Lewis";
song3. "I Code the Line, by Johnny JavaScript";

window.
</script>
</head>
<body>
<hl>My awesome playlist</hl>
<ul id="playlist"> Пустой список песен. Приведенный чут ь
<li id=" songl"X/li> выше код должен добавлять содержимое
<li id=" song2"X/li>
в каждый <li> плейлиста.

<li id=" song3"X/li>


</ ul > —Г______MvP(aytlst____
.1--1-->' + llTtP:/i,|ocalho5t/-Beth/Head- (TL/CW1
</body>
M y awesome playlist
</html> Вели вы корректно заполнит е пробе­ * B lue Suede Strings, by E lvis Pagely
• Great Objects on Fire, by Jerry JSON Lewis
лы в Ja vaS cript-коде, то веб-страница Code the Line, by Johnny JavaScript
после загрузки будет выглядеть так.

дальше ► 99
функциональность dom

Для чего еще хорошо nogxogum D0M


О бъектпая модель докумепта (DOM) позволяет делать пампого больше, чем мы видели до сих пор,
и вы будете использовать ее фупкциопальпость далее в процессе чтеп ия кпиги, а пока давайте
просто выполпим краткий обзор, чтобы эти сведепия отложились у вас в подсозпапии.

И щ ит е и извле­ Извлекайте элементы из объектной моде­


кайте один э л е ­ ли документа.
мент или более
Конечно, вы уже знаете, что это можно делать,
из объектной м о ­
поскольку мы с вами использовали d o c u m e n t .
дели документа. fo rm
g e t E l e m e n t B y l d . Однако существуют и другие
V iV y способы извлечения элементов. Вы можете ис­
j пользовать имена тегов, имена классов и атри­
| label
lab input input
буты для извлечения не только какого-то одного
элемента, а целого набора элементов (например,
Создавайте всех элементов, имеющихся в классе " o n _ s a le " ) .
новые эле Кроме того, вы можете извлекать значения фор­
менты.. мы, введенные пользователем (например, текст
элемента ввода).
III
Создавайте и добавляйте элементы в объ­
ектную модель документа.
...и добавляйте Вы можете создавать новые элементы и добав­
их в РОМ п у ­ лять их в DOM. Естественно, любые изменения,
т е м присоеди вносимые вами в объектную модель докумен­
нения к друго­ та, будут незамедлительно проявляться по мере
м у элем ент у ^ того, как браузер будет осуществлять ее ренде­
в дереве. ринг (что просто замечательно!).
Удаляйте элементы из объектной модели
Удаляйте документа.
существу -
Вы также можете удалять элементы из DOM, для
ющие э л е ­
чего необходимо взять родительский элемент и
менты.
удалить какой-либо из его дочерних элементов.
Опять-таки, в окне браузера вы увидите, что эле­
мент удален, как только он будет убран из объ­
ектной модели документа.
Получайте до­
ст уп и н а с т р а - Извлекайте и настраивайте атрибуты эле­
иваите а т р и б у ­ ментов.
ты э л ем е н т о в, Ранее мы с вами получали доступ только к тек­
наприм ер id стовому содержимому элементов, однако вы
или class. также можете получить доступ к их атрибутам.
Например, вам может потребоваться узнать, каков
класс конкретного элемента, а затем «на лету»
изменить класс его принадлежности.

100 глава 2
javascript и dom

Нельзя ли снова поговорить о JavaScript, или как осуществляется


сохранение множественных значений при использовании JavaScript
Мы уже достаточпо поговорили о JavaScript и объектпой модели докумепта (DOM). П режде чем дать
вам пемпого отдохпуть и расслабиться, мы хотим рассказать еще об од пом JavaScript-типе, которы й вы
будете постояппо использовать. Это массив (A r r a y ). Допустим, вам пеобходимо сохрапить пазвапия
32 сортов м орож епого, или пом ера всех элемептов в электроп пой корзипе вашего пользователя, или,
возможпо, почасовы е показатели уличпой температуры. Ч тобы сделать это с использованием просты х
перем еппы х, потребуется масса времепи, особеппо если пужпо сохрапить десятки, сотпи или ты сячи
зпачепий. К счастью, существует массив, которы й пас выручит.
Вы можете добав-
Массив содержит к о л - S л ят ь значения в массив
лекцию значений. \ у /. по м ере необходимости.

Каждое значение
им е ет индексный Д ля каждого индекса
номер j при эт о м в массиве имеется
нумерация начи­ соот вет ст вую щ ее
нается с нуля. значение.

Как создать массив

Ч тобы использовать массив, его спачала пужпо создать, а также п рисвоить этот массив пере-
меппой, чтобы у пас было печто такое, посредством чего мы будем ссылаться па пего в своем
коде. Д авайте создадим массив вроде того, которы й показап выше и содерж ит почасовы е
показатели температуры (по Ф арепгейту): ^
-создание нового пустого
Наша п ер е м е н - массива
ная для массива... ^ >t
^ Мы вернемся к эт о м у синтаксису
, _ __ .
var tempByHour = new Array () ; в главе 4, а пока просто
r з н а й т е J,
что он создает новый массив.
tempByHour [0 ] = 59.2;
tempByHour [1 ] 6 0 .1 ; Д ля добавления новых значений в массив мы
tempByHour [2 ] б3. просто ссылаемся на индексный номер э л е ­
м ент а массива и присваиваем ем у значение.
tempByHour [3 ] 65;
tempByHour [4 ] 62; 4- — Как и в случае с переменными JavaScript,
* вы можете присвоить любое значение
Индекс (или т и п значения) индексу массива.

JavaScript предусматривает также более бы стры й способ создапия


и инициализации массива (мы пазы ваем его «литеральпым масси­
вом») с использованием зпачепий: Данный код создает т о т же массив,
Т
У тт гсго о сг\ л съ
var tempByHour = [59.2, 60.1, 63, 65, 62]; х ЧИЛ0 и ко^> приведенный
1 чут ь выше,
т однако им еет меньший объем.

дальше ► 101
использование массива

Добавление нового элементе в массив

Вы сможете в лю бой м омепт добавить повы й элемепт в свой массив,


просто используя следующий п езап яты й ипдекс:

tempByHour[5] = 61 ;

Используя новый
порядковый индекс,
мы добавляем новый
элем ент в массив.

использование элементов своего массива


Javascript Alert
Вы мож ете извлечь зпачепие элем епта массива путем ссылки Th« tem perature at 5 was 61

па перемеппую массива с использованием ипдекса:

var message = "The temperature at 5 was " + tempByHour[5];


alert (message) ; yj'V

Д ля доступа к значению
т е м пер ат у р ы с индексом S
мы просто ссылаемся
на массив с индексом 5.

Знайте размер своего массива, иначе...

Вы мож ете легко узпать разм ер своего массива путем ссылки


па свойство массива, пазы ваемое l e n g t h : Подробнее о свойствах мы поговорим
в следующей главе, а пока просто
var numlterns = tempByHour.length; ~ зн а й т е , Что каждый массив обладает
свойством length, которое позволяет
узнат ь количество элементов в нем .

Теперь, когда вы уже зпаете, как вы яспить длипу массива, да­


вайте посмотрим, можпо ли объедипить ваши зпапия о циклах
с массивами...

102 глава 2
javascript и dom
Возьми в руку карандаш
Внизу вы найдете веб-страницу со списком пустых элементов, готовых к тому, чтобы ваш JavaScript
заполнил их температурными показателями. Мы привели большую часть кода; вам необходимо
устранить имеющиеся в нем пробелы, чтобы он смог задать содержимое для каждого элемента
списка в виде соответствующего показателя температуры из массива (например, элемент списка
с id = "tempo" получит температурный показатель с индексом 0 в массиве и т. д.). Таким об­
разом, элемент списка с id = "temp3" будет гласить: "The t e m p e r a t u r e at 3 w a s 65".
Попробуйте сделать так, чтобы элемент списка с i d = "tempo" гласил "The t e m p e r a t u r e
at n o o n w a s 59.2" вместо "The t e m p e r a t u r e at 0 w a s 59.2".
<! doctype html>
<h tml 1ang=11en11>
<head> 4r~ 3 mo HTML-
<title>Temperatures</title>
<meta charset="utf-8">
<script>
function showTemps() {
var tempByHour = new ____
tempByHour[0] = 59.2;
tempByHour[1] = 60.1;
tempByHour[2] = 63;
Здесь мы комбинируем
tempByHour[3] = 65; циклы и массивы. Видите,
tempByHour[4] = 62; как мы получаем доступ
for (var i = 0; i < _____ ) { к каждому элем ент у
var theTemp = _______ [i] ;
массива с использованием
var id = "__________ 11 + i ;
индекса переменной?
var li = document. (id) ;
if (i == ) {
li. = "The temperature at noon was " + theTemp;
else {
l i .innerHTML "The temperature at " + ______ + " was " + ___

}
}
window.onload = showTemps;
</script>
</head> К odj приведенный оОо
<body> выше, будет з а п о л ­
<hl>Temperatures</hl> нять каждый элем ент
<ul> списка содержимым Temperatures
<li id=" tempO"X/li> в виде фразы, вклю ча ­ • The temperature at noon was 59 2
<li id=" tempi"X/li> ющей словосочетание • The temperature at 1 was 60.1
<li id=" temp2"X/li> • The temperature at 2 was 63
The tem p e ra tu re at... • The temperature at 3 was 65
<li id=" temp3"X/li>
• The temperature at 4 was 62
<li id=" temp4"X/li>
</ul>
</body>
</html>

дальше ► 103
пример приложения phrase-o-matic

Изучите данный код


новенького приложения Испробуйте наше новое
Phrase- о -Mat! с и п о ­
приложение Phrase-o-Matic,
см о т р и т е, сможете
и вы превратитесь в блестяще­
ли вы п оня т ь, что он
делает , прежде чем го оратора, как ваш босс или
двинетесь дальше... ребята из отдела маркетинга.

<! doctype html>


<html lang="en">
<head>
<title>Phrase-o-matic</title>
<meta charset=Mutf-8M>
<style>
body { Вам показалось, что наше серьезное
font-family: Verdana, Helvetica, sans-serif; бизнес-приложение из главы 1 было
недостаточно серьезным? Ладно.
Тогда воспользуйтесь тем, которое
</style>
приведено здесь, если вам нужно
<script> что-то показать боссу.
function makePhrases() {
var wordsl = ["24/7", "multi-Tier", "30,000 foot", "B-to- I" , "win-win"];
var words2 = ["empowered", "value-added", "oriented", "focused", "aligned"];
var words3 = ["process", "solution", "tipping-point", "strategy", "vision"];

var randl = Math, floor (Math, random() * wordsl.length);


var rand2 = Math, floor (Math, random() * words2 .length) ;
var rand3 = Math, floor (Math, random() * words3 .length) ;

var phrase = wordsl[randl] + " " + words2[rand2] + " " + words3[rand3];


var phraseElement = document.getElementByld("phrase");
phraseElement.innerHTML = phrase;

window.onload = makePhrases;
</script>
</head>
<body>
<hl>Phrase-o-Matic says:</hl>
<p id=" phrase " X / p >
</body>
</html>

104 глава 2
javascript и dom

Phrase-O-Matic
Надеемся, вы догадались, что данны й код нредставляет собой отличны й инструмент для
генери рован ия маркетинговы х слоганов, отображ аемы х на веб-странице. В нрош лом он
уже генерировал такие удачные ф разы , как Win-win value-added solution («Беспроигры ш ­
ное эф ф екти вн ое реш ение») и 2 4 /7 em pow ered process («Процесс, идущий 24 часа в сутки,
7 дней в неделю»), и мы очень надеемся, что и будущие слоганы окажутся не хуже. Д авайте
но смотрим, как он работает.

Сначала мы онределяем функцию makePhrases, которая будет вы нолняться носле


нолной загрузки страницы , благодаря чему мы знаем, что сможем благонолучно
но лучить достун к объектной модели документа (DOM):
Мы определяем функцию с именем makePhrases,
^ кот орую будем вызывать позже.
function makePhrases() {
? г+г Весь код для makePhrases будет размещ ат ься здесь,
} \ и до него мы дойдем через несколько мгновений...
window.onload = makePhrases; выполнять makePhrases,
как только закончится загрузка
страницы.

Вынолнив нредыдущий шаг, мы можем нристунать к нанисанию кода для функции


makePhrases. Н ачнем с создания трех массивов. Каждый из них будет содержать
слова, которы е мы станем иснользовать для ген ери рован ия фраз. Мы нрим еним
бы стры й снособ создания этих массивов:

Мы создаем переменную с именем w o r d s l, кот орую


^ с м о ж е м использовать для ссылки на первый массив■

var wordsl = ["24/7", "multi-Tier", "30,000 foot", "B-to-B", "win-win"];

^ Помещаем пят ь ст рок в массив. Но вы свободно можете


—" зам енит ь их какими-нибудь модными звучными словами.

var words2 = ["empowered", "value-added", "oriented", "focused", "aligned"]


var words3 = ["process", "solution", "tipping-point", "strategy", "vision"]

Здесь вы можете видеть два дополнительных


массива, присвоенных двум новым переменным
с именами wordsZ и words3.

дальше ► 105
как работает phrase-o-matic

( 3 ) И так, у нас есть три новы х массива, содержащ их красивы е звучные слова. Тенерь
мы будем осуществлять случайную выборку но слову из каждого массива, которы е
затем объединим в одну фразу.
Вот как п роизводится вы борка но одному слову из каждого массива:
Мы генерируем по одному случайному числу для каждого массива
и присваиваем его новой переменной ( r a n d l , r a n d z и rand3 с о о т ­
ветственно).

var randl =Math, floor (Math, random() * wordsl.length) ;


var rand2 =Math, floor (Math, random() * words2 .length) ;
var rand3 =Math, floor (Math, random() * words3 .length) ;

Данный код генерирует случайное число исходя из количества элементов


в каждом массиве (в нашем случае их п ят ь, однако вы свободно можете
добавлять элементы в любой массив, и код по-преж нему сможет генери­
роват ь числа, беря за основу уже новое количество элементов).

^ Тенерь сформируем отличны й м аркетинговы й слоган, для чего возьмем все слу­
чайно вы бранны е слова и конкатенируем их друг с другом в одну фразу, разделив
нробелами для удобочитаемости:
Каждое случайное число мы исполь-
Мы определяем еще одну переменную зуе м как индекс в массивах слов...
для размещения фразы.

var phrase = wordsl[randl] + " " + words2[rand2] + " " + words3[rand3];

Мы но чти нодош ли к финалу: у нас есть фраза, которую тенерь необходимо ото-
бразить. Вы уже знаете, как мы будем действовать: нрим еним g e tE le m e n tB y ld
для ноиска нашего элем ента <р>, а затем иснользуем его свойство innerHTM L
для того, чтобы номестить в него новую фразу

^ Извлекаем элем ент <р>


var phraseElement = document.getElementByld ( "phrase") ; с id в виде "phrase".
phraseElement.innerHTML = phrase;

З а т е м задаем нашу фразу


в качестве содержимого
элем ент а <р>.

106 глава 2
javascript и dom

Итак, напечатайте носледнюю строку кода, еще раз окиньте все взглядом и ощутите удов­
л етворен и е от того, что вы довели дело до конца, нрежде чем нерейдете к загрузке стра­
ницы в своем браузере. П роведите ее тест-драйв и нолюбуйтесь на генерируем ые фразы .

О О О Phrase-o-m atfc
д вот кдк [ МI If + 0 h ttp ://lo c a lh o 5 t/-B e th /H e a d F irs t-H T M L S /c h a p te r2 /p h rase.htm l б] 'Q,' Google
выглядит
наша фраза!
Phrase-o-Matic says:
B-to-B focused vision

t Простая перезагрузка страницы открывает перед вами возможноеv


почти бесконечного генерирования все новых фраз. Незамысловатый
код позволяет делать интересные вещи!
Част®
.................... ^аД аВ аеМ ы е ................................................................
В опросы
в myWords, а я при этом попытался
Что именно представляет собой Q ; В отличном справочнике по JavaScript бы получить доступ KmyWords[10].
Math и что делают Math.random и Math, под авторством Дэвида Флэнагана
floor? «JavaScript. Подробное руководство» 0 I Будет возвращено значение
(JavaScript: The Definitive Guide). undefined, являющееся значением пере­
0 : Ma t h — это встроенная JavaScript- менной, которой еще не было присвоено
библиотека, содержащая набор математи­ Ранее вы отмечали, что примитивы некое значение.
ческих функций. Math, random генери­ (значения number, string и boolean) можно
рует случайное число в промежутке между сохранять в переменных или объектах. Можно ли удалить элемент из мас­
О и 1. Мы умножаем его на количество Но мы сохраняем массивы в перемен­ сива? Если да, то что в таком случае про­
элементов в массиве (которое извлекаем ных. Так чем является массив: прими­ изойдет с индексами других элементов?
посредством свойства length массива), тивом или объектом?
чтобы получить число в промежутке между
Q j Удалить элемент из массива можно
О и значением length массива. В резуль­
тате, скорее всего, получится число с плава­ 0 : °'
Отличный вопрос! Массив — это
особый род объекта, который встроен в
двумя разными способами. Вы можете за­
дать значение для массива с соответству­
ющей точкой (например, 3 .2 ), поэтому мы
JavaScript. Особый он потому, что его мож­ ющим индексом в виде null (например,
применяем Math, floor, чтобы получить
но использовать для доступа к значениям, myArray [2] = null). Однако это бу­
целое число, которое сможем использовать
располагающимся в массиве, чего нельзя дет означать, что длина массива останется
в качестве индекса в массиве для выборки
сделать с помощью остальных объектов прежней. Либо вы можете удалить требуе­
случайного слова. Все, что делает M a t h .
(немассивов) или объектов, которые вы соз­ мый элемент полностью (с помощью функ­
floor, — это отбрасывает цифры, идущие
даете сами. О создании своих собственных ции splice). В данном случае индексы
после знака десятичной дроби в числах
объектов мы поговорим в главе 4. элементов, идущих после удаленного вами
с плавающей точкой. Например, Math,
floor (3.2) возвращает результат 3. элемента, сдвинутся вниз на единицу. Таким
Что будет, если я попытаюсь полу­ образом, если myArray [2 ] = "dog" и
чить доступ к индексу массива, кото­ myArray [3] = "cat", а вы удалите
Где можно найти документацию рый не существует? Например, если бы "dog", то myArray [2] = " с а ^ ’,адлина
к Math? у меня было пять сохраненных слов вашего массива станет короче на единицу.

дальше ► 107
Изучение языка является непро­
стой задачей, и важно, чтобы ваш мозг
не только трудился, но и отдыхал. Поэтому,
закончив читать данную главу, устройте себе
передышку, перекусите немного и, прежде
чем перейти к следующей главе, ознакомь­
тесь с рубрикой «Ключевые моменты» и ре­
шите кроссворд, чтобы закрепить изучен­
ный материал.
' о

'■ 3

Мы еще не научились
преобразовывать
цифровые изображе­
ния с едой в нечто
вещественное, т ак
что вам самим п р и ­
дется позаботиться
о закусках.

108 глава 2
javascript и dom

кл ю ч евы е
МОМЕНТЫ

Объявлять JavaScript-переменную необходимо с ис­ Сделать свои веб-страницы интерактивными можно


пользованием var. путем исследования и изменения DOM с использова­
нием JavaScript.
boolean, n u m b e r и s t r i n g — это примитивные
типы. Для получения доступа к требуемому элементу
на своей веб-странице необходимо воспользоваться
Логическими значениями являются tr u e и false.
d o c u m e n t .g e t E l e m entByld.
Числовыми значениями могут быть целочисленные
d o c u m e n t .g e t E l e m e n t B y l d использует зна­
величины или числа с плавающей точкой.
чение i d элемента для поиска этого элемента в объ­
Неинициализированная переменная имеет значение ектной модели документа.
undefined.
Для изменения содержимого элемента следует ис­
u n d e f i n e d и n u l l — это два разных значения. пользовать свойство i n n e r H T M L этого элемента.
Первое означает, что переменной еще не было при­
Если вы попытаетесь получить доступ или изменить
своено значение, a null — что переменная имеет зна­
элементы до того, как веб-страница полностью за­
чение, под которым подразумевается «значения нет».
грузится, появится сообщение об ошибке JavaScript
Результатом оценки числовых, логических и строковых и ваш код не сработает.
выражений будут соответственно числовые, логиче­
Присвойте функцию свойству w i n d o w , onload,
ские и строковые значения.
чтобы выполнение кода, имеющегося в этой функции,
Для повторяющегося выполнения блоков кода следует осуществлялось после того, как браузер завершит за­
использовать цикл while. грузку веб-страницы.
Циклы for и w h i l e позволяют выполнять одни и Используйте массив для сохранения более одного
те же действия; используйте тот из них, который наи­ значения.
лучшим образом подходит в вашей ситуации.
Для доступа к значению в массиве необходимо исполь­
Чтобы выполнение цикла f o r или w h i l e завер­ зовать индекс. Индекс — это целое число, означающее
шилось, проверка условия в некий момент должна позицию элемента в массиве (нумерация при этом
выдать false. начинается с нуля).
Операторы i f / e l s e могут использоваться для при­ Свойство l e n g t h массива позволяет узнать количе­
нятия решений в зависимости от результатов проверок ство элементов в массиве.
условий.
Комбинируя циклы и массивы, вы сможете последова­
Проверки условий являются логическими выражени­ тельно получать доступ к каждому элементу массива.
ями.
M a t h — это JavaScript-библиотека, включающая набор
Вы можете добавлять JavaScript-код в < h e a d > или математических функций.
< b o d y > своей веб-страницы либо размещать его в
отдельном файле, внедрив ссылку на него в страницу.
M a t h . r a n d o m возвращает число с плавающей
точкой в промежутке между 0 и 1 (но никогда ровно 1).
JavaScript-код (или ссылку на него) необходимо за­
M a t h .floor преобразует число с плавающей точкой
ключать в элемент <script>.
в целое число, отбрасывая все цифры, идущие после
Когда браузер загружает веб-страницу, он создает знака десятичной дроби.
объектную модель документа (DOM), которая является
внутренним представлением этой веб-страницы.

дальше ► 109
кроссворд

U IM L 5 -K f° < r B ° fA
Настало врем я заставить ноработать левое нолуш арие вашего
мозга нутем реш ения кроссворда. Удачи!

По горизонтали По вертикали
2. Если написать 3 + 11stooges11, то JavaScript осуществит_______ I. Объектная модель документа (DOM) — это внутреннее представление
3 в строку. веб-___________ .
4 . _________используется для извлечения значения из массива. 3. Браузер созд ает_______________________ документа при загрузке
5. 5 < 1 0 — э т о ____________ выражение. страницы.
7. Вы можете добавлять свой JavaScript-код в ____________ или body 6. Добавьте его в свои веб-страницы, чтобы сделать их интерактивными.
HTML-документа. 9. Значение id элемента <р>, содержащего текст 11Red Alert : hit
8. Количество элементов в массиве можно узнать с помощью свойства by phaser fire!11.
I I . Заключайте свой JavaScript-код в тег <___________ >, если помещае­
10. Имена переменных могут начинаться с _________ , знака $ или те его в HTML-страницу.
символа подчеркивания. 14. Если вы почти закончили, то выпейте чаю, а если, как в условии
12. Выбирайте подходящие имена для переменных и используйте стиль ___________ , конец работы еще не близок, продолжайте дальше!
для указания имен, состоящих из нескольких слов. 15. Циклы while и for используют____________выражение в качестве
_

13 . __________ — это корень дерева DOM. проверки условия.


16. Повторяйте выполнение одних и тех же блоков кода посредством 18. С ___________нельзя начинать взаимодействовать, пока страница
цикла___________ .. не загрузилась полностью.
17. В JavaScript document.____________ позволяет извлечь требуемый
элемент из объектной модели документа (DOM).
19. Сохраняйте названия сортов мороженого все вместе в одном .

110 глава 2
javascript и dom

Возьми в руку карандаш_


гпражнение
решение Выразите себя! Решение
Ранее вы познакомились с различными типа­ Взяв за основу свои текущ ие зна­
ми выражений, которые можно использовать ния о переменных, выражениях и
в JavaScript-коде. Теперь пора применить эти операторах JavaScript, посмотрите,
сможете ли вы сказать, какие из этих
знания на практике и самим оценить несколько
операторов являются допустимыми,
выражений. Приведем решение этого задания. а какие приведут к выводу ошибки.
(9/5) * tempC + 32 В приведенном ниже перечне обве­
Каким окажется результат, если значением tem pc будет ю? 5 0 ___ дите допустимые операторы.

(^var х = 1138^
"Number" + " " + "2"
(^var у = 3/8 Г)
Какова будет результирующая строка? N u w b e ir 2
var s = "3-8

level >= 5

Каким окажется результат, если значением l e v e l будет 10?


true / var п 3 - "one"

А каким окажется результат, если значением l e v e l будет ____ Технически данный оператор
является допустимым, однако
^ >= означает «больше получаемое в результате зна­
либо равно» чение нельзя использовать.
color != "pink"
"one" + 11tw o j^
Каким окажется результат, если значением c o l o r будет b lu e ? (Svar t

var Зро = t r u e ; недопусти­


^ color «не равен» pink мый!
(2 * Math.PI) * г

Каким окажется результат, если значением г будет 3? 3 - 8 . 8 4 ___

С.Приблизительно!
с Math.Pi возвращает
значение пи (оно, как вы
зна е т е, равно 3,14...)

у ; недопустимый.

Так выражаться не ст оит!

дальше ► 111
решение упражнения

СТАНЬ б р а у к р е м . Р еш ение
}(аж Д ы й u s ИриБеДенньхХ на э т о й ст р а н и ц е Фрагмент 1
J a V a ^ c r ip t—ф р а Щ е н т ° В п р е д с т а в л я е т собой о щ -

ДеЛьНый ёлок К°Да. ^аШ а заДаЧа З ак л ю ч ается var count = 0;

В т °М , Ч т °£ ы С ы Грать р»Ль браузера for (var i = 0; i < 5; i++) {


^ и оДенищь Бее ф р а г м е н т ы К°Да count = count + i ;
ДЛЯ- о т Б е т а на Вопросы о резуЛь— }
т а m ax, Ц апиШ ите сВой о т В е т alert (’’count is ” + count);
на к а ж д ы й Вопрос ц 0д с о о т в е т ­
Какой показатель общего количества бу­
ствующим ^раГМенщоМ дет отображен в диалоговом окне alert р
Фрагмент 2 го
f При каждом выполнении цикла
var tops = 5; мы добавляем значение i к п о -
с п
while (tops > 0 ) { > казат елю общего количества>
for (var spins = 0; spins < 3; spins++) {Л а значение i все время ув ел и ч и ­
вается} по эт ом у при каждом
alert("Top is spinning!”); J
выполнении цикла мы добавля­
ем к показат елю общего к о л и -
Внешний цикл while выполняется

3-5*

Сколько раз на экране появится


л
«г V /
}
п ят ь р а з, а внутренний цикл for —
т р и раза при каждом выполнении
внешнего цикла, п оэт о м у по луч а ­
&
ется 5 * Ъ, или И5!

диалоговое окно alert с сообще­ Фрагмент 3


нием "Top is spinning!"?
for (var berries = 5; berries > 0; berries-
Здесь мы начинаем с 5 и выполняем -) {
,
цикл до тех пор пока количество alert("Eating a be r r y ”);
ягод не станет равным О ведя от ­ ,
счет в убывающем порядке при каж­ Сколько ягод вы съели? $
дом заходе (а не в возрастающем).
Фрагмент 4
for (scoops = 0; scoops < 10; scoop++) {

a l e r t ("T h e r e 's more ice cream!”),

} Здесь все просто: цикл вы ­


полняется Ю р а зj поэт ом у
alert("life without ice cream i s n ’t the same"); вы съели Ю ложек!

ХО Сколько ложек мороженого вы съели?

112 глава 2
javascript и dom

Пражнение Возьмите приведенный выше код и вставьте его в цикл w h i l e внизу. Пройдитесь
решение по циклу w h i l e и напишите сообщения диалоговых окон a l e r t в той последова­
тельности, в которой они будут выводиться. Вот наше решение этого задания.

var scoops = 10;

while (scoops >= 0) { в с т а в л е н н ы й ко д


if (scoops = 3) { p Это сообщение выводится один р а з ,
л * /пт
alert("Ice л 1 ,,^
cream is running low!"); когда
K U C °значение scoops
1 равно
' 3.
,} else
n if ^ (scoops ^ ox г{
> 9) Это тоже выводится
один р а зj когда значе-
alert (--Eat faster, the ice cream is going to melt!--) ; ны£ scoops р а в т m
} else if (scoops == 2) {
alert ( "Going once!") ; %— Каждое из этиК сообщений выводится
} else if (scoops == 1) {
^ - один раз, когда значение scoops равно
с о о т в е т с т в е н н о 7-, 3- и O.
alert ("Going twice!") ;
} else if (scoops == 0) {
А это выводится всякий р а з, когда ни одно из п р о ­
alert("Gone!"); чих условий не и м е ет значения true, то есть когда
} else { значение scoops равно Я, 8, 7, (о, 5 и 4.
alert("Still lots of ice cream left, come and get it.");
}
scoops = scoops - 1; вычитаем no одной ложке
при каждом выполнении цикла.
Это сообщение выводится, когда
alert ("Life without ice cream isn't the same.") ; в„ лолнение цикла завершено.

Eat faster , the ice cream is going to melt!


I Still lots of ice cream left, come and get it
Still lots of ice cream left, come and get it
\r t\ Still lots of ice cream left, come and get it
Still lots of ice cream left, come and get it
Still lots of ice cream left, come and get it
Still lots of ice cream left, come and get it
Ice cream is running low!
Going once!
Going twice!
Gone!
Life without ice cream isn't the same.

дальше ► 113
решение упражнения

развлечения с м а гн и т а м и , реш ение

Данный код отображает известный палиндром в диалоговом окне a l e r t . Проблема заключа­


ется в том, что часть кода находилась на магнитных табличках, прикрепленных к холодильнику,
однако они упали на пол. Ваша задача заключается в том, чтобы восстановить целостность
кода и отобразить палиндром. Будьте внимательны, поскольку на полу уже лежало несколько
табличек, не имеющих отношения к данному коду, зато некоторые из табличек вам придется
использовать более одного раза! Приведем решение этого задания.
var wordl = "а";
var word2 = "nam";
Jf- h ttP ' / / b c a lh o s t
var word3 = "nal p " ;
3 man a P,an a canal panama
var word4 = "lan ac";
var word5 = "a man a p " ;

var phrase = ""; Палиндром — это предложе­

) { ( ние, которое одинаково ч и т а ­


ется как слева направо, т ак и
справа налево! Вот палиндром,
который вы должны увидеть,
если правильно р а зм е ст и т е
} все таблички на магнитах
else if (i == 1) { по м ест ам.
phrase = + word4;

J else if i --
phrase J = phrase + wordl + word3;

else if l( I i == 3
phrase = phrase + + word2 + wordl;

}
alert(phrase);

114 глава 2
javascript и dom

Movie Showtimes
Plan 9 from Outer Space
Playing « 3:00pm . 7 0 0 p m . S p e d a l (bow ing tonight и midnigtul

Forbidden Planet
Playta* « 5:0Qpm. 9:00pm.
<! doctype html>
СТАНЬ браумром. <html lang=MenM>
Решение <head>

jjaiHa ЗаДаЧа З а к л ю ч а е т ­
<title>Movies</title>
</head>
ся Б т °М , Ч т °^ ы с ы Г р а т ь
<body>
роЛь браузера. ^аМ необхо­
<hl>Movie Showtimes</hl>
димо о с у щ е с т в и т ь р азбор
<h2 id="moviel" >Plan 9 from Outer Space</h2>
ЩЩ-раЗМешКи и создать
<p>Playing at 3:0 0pm, 7:0 0pm.
на ее °сноВе сВок» собственную
<span>
объектную Модель документа
Special showing tonight at <em>midnight</em>!
ФОМ)- Поэвдому сначала про­ </span>
изведите разбор HTML’ к°щ о-
</p>
рый находится справа, а D0M
<h2 id=nmovie2M>Forbidden Planet</h2>
нарисуйте Внизу. ЦаЧаЛ©
<p>Playing at 5:00pm, 9:00pm.</p>
объектной м°дели документа
</body>
Мы уже нарисовали, а ВаМ
</html>
предстоит ее завершить.

дальше ► 115
решение упражнения

- Возьми в руку карандаш


Решение ООО My Playlist

Ниже приведена HTML-разметка веб-страницы My Playlist,


на которой отображается список песен для воспроизведе­
ния (плейлист), однако пока он пуст. Вам нужно завершить My awesome playlist
JavaScript-код, чтобы песни добавились в список. Вот наше
• Blue Suede Strings, by Elvis Pagely
решение этого задания. ♦ Great Objects on Fire, by Jerry JSON Lewis
* Code the Line, by Johnny JavaScript
<!doctype html>
<html lang="en">
<head>
<title>My Playlist</title>
г
Если вы корректно заполнит е пробелы
<meta charset=Mutf-8M> в Jav a S crip t-коде, то веб-страница после
загрузки будет выглядеть? так.
<script>
fu n c tio n addSongs() {
var songl = document. t f C t E l e w e n t S y l d (" SOnq^L ) К од, благодаря к о т о ­
р о м у будет заполнен
var s o n q Z = d o c u m e n t . q e t E l e m e n t f t c j l d (" s>ongZ
наш плейлист.
var S 0 n q 3 = d p C U l^ C n t •getElementByld (11 S0nCj3 ")

SOntj3- .innerHTML = "Blue Suede Strings, by Elvis Pagely";


SOnqZ. in n er HTML = "Great Objects on Fire, by Jerry JSON Lewis";
song3. innerH TM L = 111 Code the Line, by Johnny JavaScript";
}
Вы можете свободно под-
window, o n lo a d = addSongs ставить? сюда названия
</script> своих любимых песен!
</head>
<body>
<hl>My awesome playlist</hl>
<ul id="playlist">
Приведенный чут ь выше код зада­
<li id="songl"X/li>
ет содержимое для этих э л ем е н ­
<li id="song2"></li> тов <И> п у т е м извлечения каждого
<li id="song3"></li> элем ент а из РОМ и присваивания
свойству innerHTML значения в виде
</ ul>
названия соот вет ст вую щ ей песни.
</body>
</html>

116 глава 2
javascript и dom

^Возьми в руку карандаш


Решение Внизу вы найдете веб-страницу со списком пустых элементов, гото­
вых к тому, чтобы ваш JavaScript заполнил их температурными пока­
зателями. Мы привели большую часть кода; вам необходимо устра­
нить имеющиеся в нем пробелы, чтобы он смог задать содержимое
<! doctype html> для каждого элемента списка в виде соответствующего показателя
<html lang="en"> температуры из массива. Рассмотрим решение этого задания.
<head>
<title>Temperatures</title>
<meta charset="utf-8">
<script>
function showTentps() { Создаем новый массив для р а зм е щ е­
var tempByHour = new A rratfQ ния т ем п ера т ур ны х показателей.
tempByHour[0] = 5 9 .2 ;

tempByHour[1] = 6 0 .1 ; Комбинируем циклы и м а с ­


tempByHour[2] = 63;
сивы. О б р ат и т е внимание
на то, что мы используем
tempByHour[3] = 65;
значение i в качестве индекса
tempByHour[4] = 62;
в массиве, поэт ом у получаем
for (var i = 0; i < tempByHour.lengtW . J+ + _ ) {< доступ к каждому элем ент у
var theTenrp = t e m p B y H o u r [i] ; по мере т ого, как значение i
var id = " temp + i; увеличивается при каждом
var li = document. g e t E l e m e n t B y l d (id) ; выполнении цикла.
if (i == о ) {
li. in n e rH T M L = "The temperature at noon was + theTemp ;
} else {
li.innerHTML = "The temperature at " H I + " was " + theTemp ;
}
У Генерируем ст р о ку, к о т о ­
} рая будет использоваться,
window.onload = showTemps; для чего задействуем п е р е ­
</script> менные i и theTemp.
</head>
<body>
по о
<hl>Temperatures</hl>
<ul>
<li id="tempO"></li>
<li id="tempi"></li> Temperatures
<li id="temp2"></li> * The temperature at noon was 59.2
<li id="temp3">C/li> * The temperature at 1 was 60.1
А вот наши * The temperature at 2 was 63
<li id="temp4"></li> * The temperature at 3 was 65
</ ul>
результ ат ы ! * The temperature at 4 was 62
</body>
</html>

дальше ► 117
решение кроссворда

K M L 5 ” K F4><rBoP A’ f e ffleHue

5Л 0 г и ч Е С к

Юг

11с

13r 14г
U м N

17л

118 глава 2
3 собьипия, о б р а б о т ч и к и и Весь эггк>гп ДЖ аЗ

* -ф -

Немного взаимодействия

Человек или манекен?


решать вам.

Вам все еще не удается соприкоснуться с пользователем. Вы изучи­


ли основы JavaScript, однако могут ли ваши веб-страницы взаимодействовать
с пользователями? Когда страницы откликаются на вводимые пользователем
данные, они уже являются не простыми документами, а живыми, реагирующими
приложениями. В этой главе вы узнаете, как обрабатывать одну из форм ввода
данных пользователем (извините за каламбур) и привязывать старомодный
HTML-элемент < f o r m > к современному коду. Это может показаться необыч­
ным, однако такой подход также эффективен. Пристегните ремни, поскольку
наше путешествие по этой главе будет проходить на большой скорости: путь
от простого до интерактивного приложения мы пройдем очень быстро.
добавляем мелодию webville

Приготовьтесь к встрече с Webville Tunes


И т а к , ра не е в н р о ц е с с е ч т е н и я к н и г и в ы у зн а л и массу в с е го об о с н о в а х
Ja va S c rip t, и , н е с м о т р я н а то ч т о м ы с в а м и м н о г о го в о р и л и о с о зд а н и и
в е б -н р и л о ж е н и й , р е а л ь н ы е н р и м е р ы и х с о зд а н и я м ы ещ е н р и с т а л ь н о
н е р а ссм а тр и в а л и . П о э т о м у давайте те н е р ь н р о я в и м се р ье зн о сть (н а са­
м о м деле, н а э т о т раз без ш у т о к !) и создадим р е а л ьно е в е б -н р и л о ж е н и е .

П у с т ь э т о будет м е н е д ж е р н л е й л и с т о в . М ы д а д и м ем у ка к о е -н и б у д ь
о р и ги н а л ь н о е н а з в а н и е , н а н р и м е р ... с ка ж е м , W e b v ille Tunes.

Добавляйте новые песни в любой момент.

See ваши любимые


Blue Suede Strings, by Elvis Pagely песни будут от о­
бражаться прямо
Great Objects on Fire, by Jerry JSON Lewis л окне браузера.

I Code the Line, by Johnny JavaScript

That'll be the Data, by Buddy Bitty and the Variables

Your Random Heart, by Hank "Math" Williams

^ Приложение будет
Вот что мы будем создавать. V - полностью браузерным.
Код на стороне сервера
не потребуется.

Ш ТУ РМ
Если вам известно, для чего нужен этот код:

w in d o w .o n lo a d = i n i t ;

то что, как вам кажется, делает вот этот код?

b u tto n . o n c lic k = h a n d le B u tto n C lic k ;

120 глава 3
события и обработчики

Приступаем...
Д л я н а ча л а н е т н е о б х о д и м о с т и созд авать б о л ьш у ю , к о м п л е к с н у ю в е б -стр а н иц у.
Н а сам ом деле м ы м о ж е м н а ч а ть о ч е н ь н р о с т о . Д а в а й те со зд а д им H T M L 5 -
д о к у м е н т с ф о р м о й и э л е м е н т о м с н и с ка , где будет с о д е р ж а т ь с я н л е й л и с т :

Стандартные H T M L S -элементы head и body.


< ! d o c t y p e htm l>
<htm l lan g= " en " > Beet? JavaScript-код мы п о ­
<head> местим в файл playhst.js.

< title> W eb v ille T u n e s< /title> Мы включили таблицу стилей ,


чтобы придать красивый внеш­
<meta c h a r s e t = " u t f - 8">
ний вид нашему приложению .*
< sc r ip t s r c = " p la y lis t . js" > < /sc rip t>
< l i n k r e l = " s t y l e s h e e t " h r e f = " p l a y l i s t . c s s ">
< /h e a d > Set, 4mQ наМ Иу ЖИ0j эт0 простая форма. Вот она , с текстовым полем
<body> для ввода названий песен. Мы используем HTM LS-ат рибут placeholder , ко-
<form> торый демонстрирует пример того, что можно печатать в поле ввода.
< i n p u t t y p e = " t e x t " i d = " s o n g T e x t I n p u t " s i z e = " 4 0 " p l a c e h o l d e r = " S o n g name"> ^
< i n p u t t y p e = " b u t t o n " id = " a d d B u tto n " valu e= "A d d Song">
< /fo r m > f4 _ А вот button с id в виде
"addButton" для отправки но­
< u l i d = " p l a y l i s t ">
вых дополнений в плейлист.
Мы будем использовать список
< /u l> для размещения песен. Он пока
< /b o d y > пуст j однако скоро мы это испра­
< /h t m l> вим с помощью JavaScript-Koda...

Проведите тест-д р ай в
Н а н е ч а т а й т е н р и в е д е н н ы й вы ш е ко д , за гр у зи т е е го в своем
л ю б и м о м браузере и н о л ю б у й те с ь н а результат, н р е ж д е че м non webviiie Tunes
н е р е й д е те к сл е д ую щ е й с т р а н и ц е . Г«Т»П [+ ie http://>ocaihOSt/~Beth/HTML5/javasc еП coogie ~)
[Song ^Add Song^
Вот что вы должны увидеть.

* Не забывайтеу что использованную в этом примере таблицу стилей (и весь код) вы можете
загрузить на свой компьютеру посетив страницу kttp.//wickedlysm art.com /kfktm l5.

дальше ► 121
о событиях нажатия кнопки

Когда я наЖимаю кнопку Add Song (Добавить песню),


ничего не происходит

Ч то ж , и да, и нет. В ам к а ж е т с я , ч т о н и ч е г о н е н р о и с х о д и т , о д н а к о б раузеру с т а н о в и т ­


ся и з в е с т н о , ч т о в ы щ е л к н у л и н а к н о н к е (к р о м е т о г о , в з а в и с и м о с т и о т и с н о л ьзу е м о -
го б раузера в ы т а к ж е у в и д и те , к а к к н о н к а « о то ж м е тс я » назад но сл е ее н а ж а т и я ).

Н а са м ом деле в о н р о с за кл ю ч а е тс я в т о м , к а к за с т а в и ть к н о н к у делать ч т о -т о , к о гд а
в ы щ е л ка е те н а н е й . Т о ч н е е , в о н р о с с о с т о и т в т о м , к а к будет н р о и с х о д и т ь в ы зо в н е ­
о б х о д и м о го J a v a S c rip t-кода, к о гд а в ы н а ж и м а е те к н о н к у ?

Здесь нам потребуются две вещи:

^ JavaS cript-код, который будет оцениваться,


когда пользователь щелкнет на кнопке Add
Song (Добавить песню). Данный код (как
только мы его напишем) обеспечит добав­
ление новой песни в плейлист.

Способ «прицепить» данный код таким об­


разом, чтобы при нажатии кнопки JavaScript
знал, что необходимо добавить песню
в плейлист.

Когда пользователь щелкает на кнс


(или, к примеру, нажимает ее пальцег
сенсорном экране какого-либо уст|
ства), мы хотим узнать об этом.
Поэтому нас интересует событие, кото­
рое инициируется, когда «пользователь
только что щелкнул на кнопке».

122 глава 3
события и обработчики

ЭЙ, кнопка,
ты меня интересуешь...
Не могла ли бы ты дать
мне знать, если кто-нибудь
щелкнет на тебе?

Добавить песню

Ваша кнопка

Обработка событий
Далее в ы у зн а е те , ч т о в б раузере н р и о т о б р а ж е н и и веб-стра-
н и ц ы н р о и с х о д и т м н о ж е с т в о д е й с т в и й : п о л ь зо в а те л ь щ е л ка ­
е т н а к н о н к а х , н о с е т и м о гу т н о с т у н а т ь з а н р о ш е н н ы е в а ш и м
к о д о м д о п о л н и т е л ь н ы е д а н н ы е , з н а ч е н и я в р е м е н и та й м е р о в
м о гу т и с т е к а т ь (до э т о го м ы еще д о й д е м ). В се э т и в е щ и н р и в о -
д я т к и н и ц и и р о в а н и ю с о б ы т и й , с в и д е те л ь с тв у ю щ и х о т о м , ч т о
к н о н к а б ы ла н а ж а т а , ста л и д о с т у н н ы д о п о л н и т е л ь н ы е д а н н ы е ,
в р е м я и с т е к л о и т. д. (е сть ещ е м н о г о р а з н ы х с о б ы т и й ).

В с я к и й раз, к о гд а и н и ц и и р у е т с я с о б ы т и е , ваш ем у к о д у нр ед о -
ста в л яе тся в о з м о ж н о с т ь обработать е го ; то есть вам н е о б х о ­
д и м о п р е д у с м о тр е ть ко д , к о т о р ы й будет в ы зы в а т ь с я н р и и н и ­
Ваш код ц и и р о в а н и и о п р е д е л е н н о го с о б ы т и я . В ам н е н у ж н о с и ю ж е
м и н у т у о б е с н е ч и в а ть о б р а б о т к у к а к и х -л и б о с о б ы т и й , о д н а ко
э то н о т р е б у е т с я сделать, е сли в ы х о т и т е , ч т о б ы н р и и х и н и ц и ­
и р о в а н и и ч т о -т о н р о и с х о д и л о : н а н р и м е р , к о гд а и н и ц и и р у е т с я
с о б ы т и е н а ж а т и я к н о н к и , вам м о ж е т п о т р е б о в а т ь с я , ч т о б ы за
э т и м н о сл е д о в а л о д о б а в л е н и е н о в о й н е с н и в п л е й л и с т; ко гд а
н о с т у н а ю т д о п о л н и т е л ь н ы е д а н н ы е , в ы м о ж е т е за х о т е ть о б р а ­
б о та ть и х и о т о б р а з и т ь н а с в о е й с т р а н и ц е ; ко гд а за п у с ка е тся
т а й м е р , вам м о ж е т п о н а д о б и т ь с я с о о б щ и т ь п о л ь з о в а те л ю , ч т о
е го б р о н ь н а б и л е т ы в н е р в о м р я д у с к о р о и с т е ч е т, и т. д.

Т а к и м о б р а зо м , м ы зн а е м , ч т о н а м н е о б х о д и м о о б е с н е ч и т ь об­
ра б о тку со б ы тия , и н и ц и и р у е м о го н р и н а ж а ти и к н о н к и , н о это­
му н о с м о т р и м , к а к э то м о ж н о сделать.

дальше ► 123
код для обработчика кнопки

Составляем план...
Д а в а й те н е м н о го н р и т о р м о з и м , н р е ж д е ч е м угл у б и м с я в м и р о б р а б о т ч и к о в и с о б ы т и й . Н а ш а ц ель
се й ч а с — сделать т а к , ч т о б ы но сл е щ е л ч ка н а к н о н к е A d d S o n g (Д о б а в и т ь н е с н ю ) н р о и з о ш л о д о ­
бавлени е н е с н и в н л е й л и с т н а с т р а н и ц е . П о д о й д е м к р е ш е н и ю э т о й за д а чи н а о с н о в е с л е д у ю щ и х
э та н о в :
1 . Задание об р а б о тч и к а для о б р а б о тк и с о б ы т и й c lic k 6 о тн о ш е н и и кнопки A d d S on g ( Д о б а в и т ь п е с н ю ).

2 . Написание об р а б о тч и к а для извлечения названия песни, введ енного п ол ь з ов ател ем , после чего п о с л е д у е т ...

3 . Создание нов о го эл е м ен та для размещ ения новой песни и . . .

4 . Д обавл ение н ов ого эл е м ен та в D 0 M с т р а н и ц ы .

Н е б е с н о к о й т е с ь , е сли э т и э т а н ы н е со все м я с н ы для вас, н о с к о л ь к у н о х о д у дела м ы все вам о б ъ яс­


н и м . С е й ч а с о т вас тр е б у е тс я н р о с т о н р о ч у в с т в о в а ть и х , следуя за н а м и , н о к а м ы будем за н и м а ть с я
н а н и с а н и е м н е о б х о д и м о го о б р а б о т ч и к а . И т а к , о т к р о й т е н о в ы й ф айл p la y lis t.js , где будет р а с п о л а ­
га т ь с я весь ваш J a v a S c rip t-код .

Получение доступа к кнопке Add Song (Добавить песню)


Ч т о б ы « н о н р о с и ть » к н о н к у дать н а м зн а ть , к о гд а будет и н и ц и и р о в а н о с о б ы т и е , сви д е те л ь ств ую щ е е
о т о м , ч т о н о л ь зо в а те л ь щ е л кн у л н а н е й , сна ча ла н е о б х о д и м о н о л у ч и т ь д о с т у н к э т о й к н о н к е . К сча­
с ть ю , м ы создали д а н н у ю к н о н к у с и с н о л ь з о в а н и е м H T M L -р а з м е тки , и э то озна ча е т, ч т о ... к а к в ы у ж е
д о га д а л и сь, о н а н р е д с та в л е н а в о б ъ е к т н о й м о д е л и д о ку м е н т а ( D O M ) , а в ы у ж е зн а е те , к а к и з в л е ка ть
э л е м е н т ы оттуда. Е сл и в ы ещ е раз в згл я н е те н а H T M L -разм етку, т о за м е т и те , ч т о м ы н р и с в о и л и i d
к н о н к и з н а ч е н и е a d d B u tto n . Т а к и м о б р а зо м , м ы в о с п о л ь зу е м с я g e t E l e m e n t B y l d для и з в л е ч е н и я
ссы л ки на кн о н ку:

: v a r b u t t o n = d o c u m e n t . g e t E l e m e n t B y l d ( " a d d B u tto n " ) ;

Т е н е р ь н а м н у ж н о н р о с т о задать для к н о н к и ко д , к о т о р ы й будет в ы зы в а т ь с я н р и с о б ы т и и c l i c k .


Д л я э т о го м ы созд а д им ф у н к ц и ю с и м е н е м h a n d l e B u t t o n C l i c k , к о т о р а я за й м е тс я о б р а б о т к о й дан­
н о г о с о б ы т и я . П о д р о б н е е о ф у н к ц и я х м ы н о г о в о р и м н е м н о го н о з ж е , а н о к а н е о б х о д и м а я н а м ф у н к­
ц и я будет в ы гл я д е ть в о т та к:

ф ункция носит имя


h a n d le B u tto n C lick ; об о с о б е н - — фу н к ц и я п о з в о л я е т у п а к о в а т ь
ност ях синт аксиса мы п о го - >v код в р а м к и о т д е л ь н о г о блока.
в о р и м ч у т ь позже. X 1 Вы м о ж е т е п р и с в о и т ь е м у
) имя и повт орно использоват ь
f u n c t i o n h a n d l e B u t t o n C l i c k () { \ э т о т бл о к кода в е з д е > где в а м
a пl e 4_/ пт, 4_о_
r t ( " B u tto n was c l-Ii ■c k1 e dл !и"х) ; г\ X п о т рг е б уие т с я .

] К\ В есь к о д, к о т о р ы й д о л -
При в ы зове данной ф у н к ц и и жен в ы п о л н я т ь с я п р и
будет выводиться диалого- вы зове ф у н к ц и и , м ы з а -
вое окно a lert. к льо ча е м в скобки.

124 глава 3
1. Задание обработчика для обработки событий click
2. Написание обработчика для извлечения названия песни
3. Создание нового элемента для размещения новой песни
Задание обработчика событий click для кнопки 4 . Добавление нового элемента в D0M страницы

И т а к , т е н е р ь у нас е сть к н о н к а , а т а к ж е ф у н к ц и я h a n d l e B u t t o n C l i c k , к о т о р а я будет в ы сту-


н а т ь о б р а б о т ч и к о м , т а к ч т о д а в а й те с о е д и н и м и х вм е сте . Д л я э т о го м ы в о с п о л ьзу е м с я с в о й ­
с тв о м b u t t o n н о д и м е н е м one l i c k . С в о й с т в о o n c l i c k м ы зад адим сл е д ую щ и м о б р а зо м :

v a r b u t t o n = d o c u m e n t . g e t E l e m e n t B y l d ( " a d d B u tto n " ) ;


b u t t o n .o n c l ic k = h a n d leB u tto n C lic k ; /
Л
Имея под рукой b u tto n , после вызова getElementByld мы задаем
для свойства onclick функции?, которая будет вызываться при
наступлении события click.

К а к в ы н о м н и т е , м ы делали н е ч т о н о д о б н о е , к о гд а и с н о л ь з о в а л и с в о й с т в о w in d o w .o n lo a d
для в ы зо в а ф у н к ц и и н о с л е о к о н ч а н и я з а гр у з к и о к н а . О д н а к о в д а н н о м случае м ы в ы зы в а е м
ф у н к ц и ю но сл е н а ж а т и я к н о н к и . Т е н е р ь с о е д и н и м все:

К а к и в предыдущей главе, здесь мы используем ф унк -


цино m itj которая не будет вызываться и выполняться
w in d o w .o n lo a d = i n i t ; £ meX n0PJ пОКа с т РаниЧа полностью не загрузится.
f u n c t i o n i n i t () {
v a r b u t t o n = d o c u m e n t . g e t E l e m e n t B y l d ( " a d d B u tto n " ) ;
b u t t o n .o n c l ic k = h a n d leB u tto n C lic k ;
К. После окончания загрузки ст р а ­
ницы мы извлекаем button и за-
f u n c t i o n h a n d l e B u t t o n C l i c k () {
даем его обработчика onclick.
a l e r t ( " B u tto n was c l i c k e d ! 1 Ь
Обработчик событий click будет
выводить диалоговое окно alert
в случае щелчка на кнопке.

Проведение т е с т а .
Н а н е ч а т а й те н р и в е д е н н ы й в ы ш е ко д (в своем ф айле p l a y l i s t . j s ) , з а гр у зи те с тр а н иц у, а затем но -
щ е л ка й т е н а к н о н к е с т о л ь к о р аз, с к о л ь к о з а х о т и т е . П о с л е к а ж д о го щ е л ч ка в ы будете н а б л ю д а ть
н о я в л е н и е д и а л о го в о го о к н а a l e r t .

З а к о н ч и в т е с т и р о в а н и е с в о е го н о в о г о
о б р а бо тчика с о б ы ти й c l i c k в о тн о ш е н и и
к н о н к и , о т к и н ь т е с ь н а с н и н к у стула и и зу ­ h Mp . y / f o c a l h o s t
ч и т е к о д , нро д ум а в т о , к а к о н раб о та е т. Button wa5 clicked!

К о г д а в ы н о й м е т е , ч т о все э то у ж е у вас
в го л о в е , н е р е в е р н и т е стр а н и ц у , и м ы с
в а м и н р о й д е м с я н о д е та л я м , ч т о б ы за-
к р е н и т ь м а те р и а л .

дальше ► 125
как работает кнопка add song

Более пристальный Взгляд на происшедшее...


На нескольких носледних страницах мы нознакомили вас с м ассой
новых аснектов, ноэтому давайте ещ е раз нройдем ся но коду, чтобы
убедиться в том, что вы все четко усвоили. Итак, нристуним:

Первое, что мы сделали, — это добавили кнопку в свою


HTML-срорму. Затем нам потребовалось средство перехвата
событий click в отношении этой кнопки, чтобы в результате
был выполнен кое-какой код. Для этого мы создали обработ­
чика и присвоили его свойству onclick нашего button.
Задаем обработчика
событий click в ф унк­
function init() { ции in it (то есть
var button = document.getElementByld ("addButton") выполнение будет
button.onclick = handleButtonClick; запускаться после
} завершения загрузки
страницы).
Объект button об­
ладает свойством
onclick, для которого
мы задаем функцию
handleButtonClick.

Когда пользователь щелкает на кнопке ,


инициируется событие click и происхо­
дит вызов функции handleButtonClick.

function handleButtonClick() {
alert("Button was clicked! ') ;
}

Мы также написали простой обработчик, который выводит


диалоговое окно a l e r t с сообщением о том, что кнопка была
нажата. Чуть позже мы напишем настоящий код для обработ­
чик а, а этот отлично подходит для тестирования. I

г 'и Обработчик
в вашем коде

126 глава 3
события и обработчики

Итак, код написан, страница загружается


и отображается в окне браузера, обработ­
чик задан. Теперь все зависит от поль­
зователя...

Наконец, пользователь щелкает на на­


шей кнопке, в результате чего она акти-
визируется, замечает, что у нее имеется
обработчик, и вызывает его...

_/ Очнись, / Вижу, у меня Ч


Г пользователь щелк- \ f есть обработчик на \
N. нул на тебе. ) 1 этот случай, нужно дать
ему знать. >
О
_____ П — 0 ----------- '

Г Добавить песню
о

f u n c t i o n h a n d l e B u t t o n C l i c k () {
a l e r t ( " B u tton was c l i c k e d ! " )
}

Меня попросили
сообщить вам, что кноп­
ка была нажата... Я знаю,
что для диалогового окна
http://localhost
ale rt это не слишком впечат­
Button was clicked!
ляюще, но, как бы там ни было,
я просто делаю свою
( Q* )
работу.

дальше ► 127
извлечение названия песни из dom 1. Задание о б р а б о т ч и к а для о б р а б о т к и с о б ы т и й c lick
2. Написание обработчика для извлечения названия песни
3. Создание нового элемента для размещения новой песни
извлечение названия песни 4 . Добавление нового элемента в D0M страницы

М ы готовы н е р е й т и к о в т о р о м у э та н у р е ш е н и я н а ш е й за д а ч и — и з в л е ч е н и ю н а з в а н и я н е с н и ,
в в е д е н н о го п о л ьзо в а те л е м . Сделав э т о , м ы с м о ж е м задум аться над те м , к а к н а ш н л е й л и с т будет
о т о б р а ж а т ь с я в браузере.

О д н а к о к а к м ы и з в л е ч е м н а з в а н и е н е с н и ? Э то н е ч т о т а к о е , ч т о ввел п о л ь з о в а те л ь , ведь так?


А х да, все, ч т о п р о и с х о д и т н а в е б -с тр а н и ц е , о тр а ж а е т с я и в о б ъ е к т н о й м о д е л и д о ку м е н та (D O M ),
н о э т о м у те кс т , в в е д е н н ы й п о л ьзо в а те л е м , т о ж е д о л ж е н б ы т ь там .

Д л я и з в л е ч е н и я т е к с т а и з т е к с т о в о го э л е м е н та ввода ф о р м ы н а м сна ча ла н о т р е б у е т с я и з в л е ч ь
э т о т э л е м е н т и з D O M , и в ы у ж е зн а е те , к а к о й и н с т р у м е н т для э т о го н у ж е н — g e t E l e m e n t B y l d .
Сделав э то , м ы см о ж е м в о с п о л ь зо в а ть с я с в о й с т в о м v a l u e т е к с т о в о го э л е м е нта ввода для п о л у ч е ­
н и я д о стун а к тексту, вве д е н н о м у в но л е ф о р м ы по л ьзо ва те л е м , и в о т к а к это все будет вы гл яд е ть:

Вот элем ент j к о т о ­


рый м ы х о т и м извлечь
до к у м е н т а
из DOM. Д л я э т о ­
го м ы и с п о л ь з у е м
его id со значен и ем
".S o n g T e x tln p u t". ul id="playlis+"

\
input id^'songTextlnput” nput id="addButton" j
value="Blue Suede Strings, by Elvis Pagely"

З а т е м м ы и с п о л ь з у е м свойст во value
э л е м е н т а ввода для извлечения т е к с т а ,
С пом ощ ью мет ода набранного п о л ь з о в а т е л е м в п оле вчооа.
g e tE le m e n tB y l d м ы сможем
получит ь доступ к элем ент у
ввода s o n g T e x tln p u t в ф орм е.

^Возьми в руку карандаш


Доработайте ф ункцию h a n d l e B u t t o n C l i c k , приведенную ниже, чтобы извлечь на
звание песни, набранное пользователем в элементе ввода формы. П роверить пра
вильность своих ответов вы сможете, посмотрев реш ение д ан н ого задания на с. 130.

f u n c t i o n h a n d l e B u t t o n C l i c k () {
v a r t e x t l n p u t = d o c u m e n t . g e t E l e m e n t B y l d ("
v a r songName = . v a lu e;
alert(" A d d in g " +

128 глава 3
события и обработчики

Возьми в руку карандаш

А вдруг вам потребуется провести проверку, чтобы убедиться в том, что пользо­
ватель действительно ввел текст до того, как щелкнул на кнопке? Как это можно
будет сделать? (Решение данного задания вы также сможете отыскать на с. 130.)

Часш°

ЧаДаВаеМые
Вопросы

Каким будет значение свойства value текстового элемента Ка ки е ещ е типы с о б ы ти й м ож но о б р а б а ты в а ть


ввода, если пользователь ничего не ввел? Будет ли оно null? на JavaScript помимо click?
Или кнопка Add Song (Добавить песню) не станет вызывать
обработчик, если пользователь ничего не ввел? 0 : Существует масса прочих событий, связанных с манипу­
ляциями мышью, которые можно обрабатывать. Например, вы
0 : Кнопка Add Song (Добавить песню) не настолько умна. Если можете отслеживать и обрабатывать события, инициируемые при
вы хотите определять, ввел ли что-нибудь пользователь, для этого нажатии кнопки мыши, при наведении указателя мыши на элемент
вам потребуется соответствующий код. Чтобы узнать, является и убирании его прочь с элемента, при перетаскивании элемента с
ли текстовое поле ввода пустым (то есть пользователь ничего в помощью мыши, при нажатии и удержании кнопки мыши (они от­
нем не напечатал), можете проверить, не равно ли его значение личаются от событий click). Кроме того, существует множество
строке, в которой ничего нет, также называемой пустой строкой и иных типов событий, о которых мы уже упоминали (например, со­
помечаемой как,,м(пара двойных кавычек, между которыми ничего бытия, инициируемые, когда становятся доступны дополнительные
не стоит). Мы понимаем, почему вы решили, что значение может данные, события, связанные с таймерами и окном браузера, и т. д.).
быть равно null, поскольку ранее отмечали, что это значение В процессе чтения книги вы увидите еще довольно много других
переменной, под которым подразумевается «значения нет», однако типов событий, которые можно обрабатывать; если вы знаете,
с точки зрения текстового поля ввода оно будет содержать не ничто, как обрабатывать события одного типа, то вы с большой долей
а строку, в которой ничего нет. Представьте себе!;-). вероятности сможете обработать события любых других типов!

Я думал, что "value" текстового элемента ввода — это


атрибут. Но вы называете его свойством. Почему?
В Что делает JavaScript, пока ждет инициирования событий?

0 : Если вы не запрограммировали свой JavaScript на выполнение


0 : Вы правы, value — это атрибут текстового элемента ввода. каких-либо действий в это время, он будет бездельничать, пока
Вы можете инициализировать значение текстового элемента ввода что-нибудь не произойдет (пользователь начнет взаимодействовать
с использованием атрибута value. Однако в случае с JavaScript с интерфейсом, поступят данные из Интернета, истечет значение
для доступа к значению, введенному пользователем, вам потре­ времени таймера и т. д.). И это хорошо, поскольку вычислительная
буется использовать свойство value элемента ввода, которое мощь вашего компьютера сможет быть направлена на другие вещи,
извлекается из объектной модели документа (DOM). например на то, чтобы сделать ваш браузер более отзывчивым.
Позже мы расскажем, как создавать задачи, выполняемые в фо­
новом режиме, чтобы ваш браузер одновременно выполнял код
задачи и реагировал на события.

дальше ► 129
решение упражнения

Возьми в руку карандаш


Решение Доработайте функцию h a n d l e B u t t o n C l i c k , приведенную
ниже, чтобы извлечь название песни, набранное пользовате­
лем в элементе ввода формы. Вот наше решение этого задания.

Сначала на м необходимо извлечь ссылку на т е к -


ст овы й э л е м е н т ввода в ф о р м е. Мы пр исвои ли
id эт о го э л е м е н т а значение ".s o n g T e x tln p u t",
п о э т о м у мож ем и с п о ль з о ва т ь его в сочет ании
с ж э с g e tE le m e n tB y l d для извлечения ссылки.

f u n c t i o n h a n d l e B u t t o n C l i c k () { J
var t e x t I n p u t = docum ent. g e tE le m e n tB y ld (" so n g T ex tIn p u t"
v a r songName = t e x t I n p u t . v a l u e ;
a l e r t ( "Adding " + son gN am e);
Свойство value текстового
} элемента ввода содержит
все, что набирается в т е к -
стовом поле и представляет
Ь у д е т выводиться диалоговое окно собой строку. Здесь мы при -
alert, в к о т о р о м о т о б р а зи т с я сваиваем введенный текст
"Adding" и название песни. переменной songName.

Возьми в руку карандаш


Решение БОНУС

А вдруг вам потребуется провести проверку, чтобы убедиться в том, что


пользователь действительно ввел текст до того, как щелкнул на кнопке?
Как это можно будет сделать? Решение таково:

f u n c t i o n h a n d l e B u t t o n C l i c k () {
v a r t e x t l n p u t = docum ent. g e tE le m e n tB y ld (" so n g T e x tln p u t" );
v a r songName = t e x t l n p u t . v a l u e ; M ы мож ем и с п о ль з о ва т ь о п е р а т о р
if (songName == "") { ^ — if и ср а в н и т ь с т р о к у so n g N a m e
с п у с т о й с т р о к о й , чтобы у б е ­
a l e r t ( " P lea se e n t e r a song"),
дит ься, ч т о п о л ь з о в а т е л ь д е й ­
} else { с т в и т е л ь н о ч т о - т о напечат ал.
a l e r t ( "Adding " + songName); Если п о л ь з о в а т е л ь ничего не н а п е ­
ч а т а л , т о мы выведем диалоговое
окно a le rt и п о п р о с и м его ввест и
название песни.

130 глава 3
1. Задание о б р а б о т ч и к а для о б р а б о т к и с о б ы т и й c lick
2 . Нап и сан ие о б р а б о т ч и к а для и звлечения назВания песни
3. Создание нового элемента для размещения новой песни
Как добавить песню на страницу? 4-А»б»в».н«...вого«««м.»™вdom^«„цы
М ы с в а м и у ж е м н о г о ч е го сделали, и все р а б о та е т! В ы м о ж е т е в в е с ти назва­
н и е н е с н и в ф орму, щ е л к н у т ь н а к н о н к е A d d S o n g (Д о б а в и т ь н е с н ю ) и и з в л е ч ь
т о , ч т о в в о д и л и в ф орму, — все в рамках вашего кода . Т е н е р ь м ы о т о б р а з и м п л е й ­
л и с т н а са м о й с т р а н и ц е . В о т к а к э то будет в ы гл я д е ть.

ООО W eb ville T u n e s

[ А | ► | [ + | 0 h ttp ://lo calh o st/->B e th /H e ad -F irst-H T M <5 ] (С^т Google j

Song name Г A d d Song^)

Blue Suede Strings, by Elvis Pagely При нажатии кнопки


Add Song (Добавить
песню) ваш JavaScript
добавляет соответ­
ствующую песню
в список на странице.

Нам потребуется сделать следующее

Вы могли заметить, что мм уже добави­


© ли пустой список в HTML-разметку (пу­ Это список
стой элемент < u i > ) , когда в первый раз body в объектной
вводили данные. В результате объектная модели доку­
модель документа (DOM) сейчас будет мента. Сейчас
ul id= "p la y lis t"
выглядеть так. он пуст.

© Каждый раз, когда вводится название но­


вой песни, нам нужно добавлять новый
элемент в неупорядоченный список. Для При вводе на­
этого мы создадим новый элемент <и>, звания песни
мы создаем
в котором будет размещаться название
новый эле­
новой песни. Затем мы возьмем новый
мент списка
элемент <и> и добавим его в < u i> в объ­ (элемент <И>)
ектной модели документа. В результа­ и добавляем его
те этого, когда браузер сделает свои в список <ul>.
дела, вы увидите, что страница подвер­
глась обновлению, словно данный эле­
мент <и> был там всегда. И конечно же,
все это мы сделаем в коде.

дальше ► 131
создание нового элемента

пражненке п По

Здесь приведен плейлист, для которого вам необхо­


димо нарисовать объектную модель документа в том
виде, который он приобретет после добавления всех Blue Suede Strings, by Elvis Pagely
этих песен. Обратите внимание на порядок, в котором
песни были добавлены на страницу, и разместите Great Objects on Fire, by Jerry JSON Lewis

соответствующие элементы на своих местах в DOM. 1Code the Line, by Johnny JavaScript
Один из них мы уже расположили в нужном месте,
That'll be the Data, by Buddy Bitly and the Variables
вам остается лишь сделать то же самое в отношении
остальных элементов. Посмотрите решение данного Your Random Heart, by Hank "Math" Williams
задания в конце главы, прежде чем двинетесь дальше.

Blue Suede Strings,


by Elvis Pagely

Д о р и с у й т е зд е сь о с т а л ь н у ю
ч а с т ь РОМ д л я п л е й л и с т а ,
п р и в е д е н н о г о в в е р ху.
Придется ли вам строить какие-либо предположения насчет порядка,
в котором элементы < i i > добавляются в родительский элемент?

132 глава 3
события и обработчики

Как создать новый элемент


— Нам лучше заняться
В ы у ж е в и д е л и , к а к м о ж н о н о л у ч и т ь д о с т у н к существующим созданием этих элементов,
элементам н о с р е д с т в о м о б ъ е к т н о й м о д е л и д о ку м е н та . О д н а ко Бетти. Они снова обновляют
D O M та кж е м о ж н о и сн о л ьзо в а ть для со зд а ния н о в ы х элем ентов D ОМ.
(с н о с л е д у ю щ и м их добавлением в D O M , о ч е м м ы н о г о в о р и м
со все м с к о р о ).
Д а в а й т е н р е д с т а в и м , ч т о н а м н у ж н о с о зд а ть э л е м е н т < l i > .
В о т к а к м ы э то сделаем:

Д л я создания новых э л е м е н т о в и с п о л ь з уе т с я d o c u m e n t
c re a te E le m en t. В о звр а щ а е т с я ссылка на новый э л е м е н т .

var l i =
\
d o c u m e n t. c r e a t e E le m e n t ( " l i " ) ;

Передаем
Здесь м ы п р и с в а ­
c r e a te E le m e n t в виде
и ва ем новый э л е ­
с т р о к и т о , какой э л е ­
м е н т пер е м е н н о й И.
м е н т х о т и м создать.

С п о м о щ ь ю c r e a te E le m e n t создается совершенно
| li j новый э л е м е н т . С ледует о т м е т и т ь , ч т о он
Л пока не вс т а в л я е т с я в о б ъ е к т н у ю м о д е ль д о ­
ку м е н т а . На данный м о м е н т он п р е д с т а в л я е т
содой ли ш ь э л е м е н т , находящийся в свободном
п л а в а н и и , к о т о р о м у нужно п р и с т а н и щ е в РОМ.

И т а к , т е н е р ь у на с и м е е т с я э л е м е н т < l i > , в к о т о р о м н и ч е г о
н е т. В ы у ж е з н а е т е с н о с о б д о б а в и т ь т е к с т о в о е с о д е р ж и м о е
в эл е м е н т:
li.in n erH T M L = songN am e;

Наша п е р е м е н - ^ з а д а ш со д е р ^
ная I'- жимое в виде названия
песни для э л е м е н т а <h>.

^ Blue Suede Strings,


by Elvis Pagely

Наш новый о б ъ е кт
э л е м е н т а li, готовы
р и н у т ь с я в бой. О д н а ­
ко он еще не явля е т с я
ч а с т ь ю РОМ!

дальше ► 133
добавление нового элемента 1. Задание о б р а б о т ч и к а для о б р а б о т к и с о б ы т и й c lick
2 . Нап и сан ие о б р а б о т ч и к а для и звлечения назв ан и я песни
3 . С о здание нового э л е м е н т а для р а з м е щ е н и я новой песни

Добавление элемента В DOM 4 . Добавление нового элемента в D0M страницы

Ч т о б ы д о б а в и ть н о в ы й э л е м е н т в о б ъ е к т н у ю модель д о ку м е н та , вам
н е о б х о д и м о зн а ть , куда е го н о м е щ а ть . Ч т о ж , н а м э то у ж е и з в е с т н о :
м ы со б и р а е м ся н о м е с т и т ь э л е м е н т < l i > в э л е м е н т < u l> . Н о к а к э то
сделать? Д а в а й те еще ра з взгл я н е м н а D O M . П о м н и т е , к а к ра не е м ы
о т м е ч а л и , ч т о о н а с р о д н и дереву? М о ж е т е т а к ж е с ч и т а т ь ее че м -то
вр о д е родословного дерева.

d o c u m e n t я вля е т с я н еким ре-


подобием « м а т е р и » всего с е ­ '" Л

к
м ейного рода и р а с п о л а г а е т с я б&нкоМ» (У V ...... р 0Эителелл
б да н но м п о ко л е ни и
на с а м о м верху дерева. р
document
У h t m l и м е ю т с я два
дочерних э л е м е н т а —
с html
i hea d и body. Р о дит е ле м
~ Г ~
body явля е т с я h tm l.
head | body j * '

с title script form ul id="playlist"


h
А вот наш ul. Роди­
| input | | input ~ | телем ul я в л я е м с я
body, а у ul пока н е т
дочерних элем ент ов...
Т а к и м о б р а зо м , ч т о б ы д о б а в и т ь н а ш э л е м е н т < l i > , н е о б х о д и м о ...мы х о т и м сде­
сделать е го д о ч е р н и м н о о т н о ш е н и ю к < u l> . Д л я э т о го н а м с н а ч а ­ л а т ь наш новый
ла н у ж н о о т ы с к а т ь э л е м е н т < u l> в де р е в е (м ы н р и с в о и л и е го i d э л е м е н т <(/>
з н а ч е н и е "p la y lis t", ч т о б ы е го н р о щ е б ы л о н а й т и ) . З а те м , ч т о б ы
н р о и з о ш л о д о б а в л е н и е э л е м е н т а < l i > , м ы н р е д л а га е м э л е м е н т у
IT ) дочерним по о т ­
нош ению к <ul>.
< u l> д о б а в и т ь н о в ы й д о ч е р н и й элем ент. Все э т о будет в ы гл я д е ть
Blue Suede Strings,
сл е д ую щ и м об р а зо м :
by Elvis Pagely
И с п о л ь з у е м g e tE le m e n tB y l d для извлечения
ссылки на э л е м е н т <ul> с id -"playlist1'.
При каждом вызове

v a r u l =
2
d o c u m e n t . g e t E l e m e n t B y l d ( " p l a y l i s t 11) ;
appendC hild новый
э л е м е н т <Ц> б удет
добавлят ься в э л е ­
u l .a p p e n d C h i l d ( li) ;
м е н т <ul> после
Здесь мы п р е д ла га е м э л е м е н т у <ul> добавить <h> в качест ве любых других э л е ­
дочернего э л е м е н т а . К ак т о л ь к о э т о будет сделано, в РОМ <(/> м е н т о в <li>j ко т оры е
с т а н е т дочерним э л е м е н т о м <ul>, и браузер обновит с т р а н и ц у , уже т а м б уд у т р а с ­
чтобы в ней о т р а зи л с я новый <h>. полага т ься.

134 глава 3
события и обработчики

Соединяем все воедино...


Давайте соединим весь код и добавим его в функцию h a n d l e B u t t o n C l i c k . Наберите нриведенный ниже
код, если вы еще этого не сделали, чтобы затем можно было нровести тестирование.

f u n c t i o n h a n d l e B u t t o n C l i c k () {

v a r t e x t l n p u t = d o c u m e n t . g e t E l e m e n t B y l d ( " s o n g T e x t l n p u t " );
Сначала м ы создаем новый э л е м е н т <h>,
v a r songName = t e x t l n p u t . v a l u e ; ___ g к о т о р о м б удет р а з м е щ а т ь с я н а з в а -
tС ние новой п е с ни .
var l i = docum ent. c r ea teE le m e n t (" l i " );
З а т е м задаем содержимое в виде
li.in n erH T M L = songName; ^ названия песни для данного эл е м е н т а .
<ul> с id "playlist" я вля е т с я р о д и -
v a r u l = document . g e t E l e m e n t B y l d ( " p l a y l i s t " ) ; (г~т ельскиМ э л е м е н т о м no о т н о ш е н и ю
к н а ш е м у новом у <И>. П о эт ом у он
u l . a p p e n d C h ild ( l i ) ; -- ------------^ след у ю щ и й в очереди на извлечение.

Л Д обавляем объект II в ul с и сп о ль-


О б рат ит е вним ание , чт о мы предлага~ 30^анием appendChild.
сал р о д и т е л ь с к о м ц э л е м е н т у ul добавить
в себя Н в ка чест ве дочернего эл е м е н т а .

...и проводим тест-драйв


____ I______ -
u N d = " p la y list'^ L
Протестируйте Webville Tunes, добавляя в нлейлист
несни. Вот наши результаты.

Так б удет вы глядет ь о б ъект ная м о ­


О О О W eb v ille T u n es
дель д о к у м е н т а после добавления всех
[ < | | | + |Q h ttp ://lo c a lh o s t/-'B e th /H e a d -F irs t-H T M L 5 ; C j (O? Google
новых э л е м е н т о в <Н>.
Song name (Add Song^i

Blue Suede Strings, by Elvis Pagely Т е п е р ь , когда мы вводим название


песни и наж имаем кнопку A d d Song
Great Objects on Fire, by Jerry JSON Lewis
( Д о б а в и т ь песню ), с о о т в е т с т в у ю ­
I Code the Line, by Johnny JavaScript щая песня добавляется в РОМ, б л а го ­
даря ч ем у м ы видим , ч т о с т р а н и ц а
That'll be the Data, by Buddy Bitly and the Variables
п р е т е р п е в а е т и зм енения и в о т о -
Your Random Heart, by Hank "Math" Williams браж аемом на ней списке по я вля е т с я
новая песня.

дальше ► 135
обзор приложения playlist

Обзор того, что мы только что сделали


В э т о й главе мы с вами много чего сделали (иричем за короткий нромежуток
времени!). Иснользуя^уаБспр):, мы создали менеджер нлейлистов, который
нозволяет ввести название несни, щелкнуть на кнопке и добавить данную
несню в снисок на странице
Первое, что мы сделали, — это задали обработчик
для обработки событий c l i c k в отношении кноп­
ки Add Song (Добавить песню). Мы создали функ­
с Add Song
_J

цию h a n d l e B u t t o n C l i c k и задали ее для свой­


ства o n c l i c k кнопки Add Song (Добавить песню).
Когда п о л ь з о в а т е л ь щелкает на кнопке Add Song (Добавить
песню ), пр о и с х о д и т вызов нашего обработчика handleButtonClick.
ф Затем М Ы написали КОД ДЛЯ h a n d l e B u t t o n C l i c k ,
чтобы извлекать название песни из текстово­
го поля ввода. Мы воспользовались свойством
i n p u t . v a l u e для извлечения текстовых данных и j
# \*
даже позаботились о проведении проверки, чтобы
убедиться, что пользователь ввел название песни.
Если он этого не сделал, то мы выводим диалого­
вое окно a l e r t с соответствующим сообщением.

3 ha n d le B u tto n C lic k м ы извл е ка е м


input id=''songTextInput" input id=''addButton"
введенное п о л ь з о в а т е л е м название value="Blue Suede Strings by Elvis Pagely''
песни, и с п о ль зуя свойст во input.vatue
для извлечения т е к с т о в ы х данных
из об ъ е кт н о й м о дели д окум ент а.
Чтобы добавить песню в плейлист, далее мы
создали элемент < l i > , используя d o c u m e n t .
c r e a t e E l e m e n t , и задали содержимое в виде
названия песни для этого элемента с помощью
innerHTM L. М и С03дали новый э л е м е н т Blue Suede S trin g s ,
<li> и задали для него содерж и- -А. У v' s а9е У
м о е в виде названия песни.
Наконец, мы внедрили новый элемент < i i > в объ­
ектную модель документа, добавив его в качестве
дочернего элемента по отношению к родительско­ body
му < u l > . Мы сделали это С ПОМОЩЬЮ a p p e n d C h i l d , Д обавление
дав элементу < u l > команду «добавить < l i > в ка­ нового дочер­
честве дочернего элемента», в результате чего он него э л е м е н т а |^ u M d = ^ p la y li^ rJ |
был внедрен в объектную модель документа. При в DOM п р и в о ­
добавлении элемента в DOM браузер обновляет д и т к обновле­
страницу, которую видит пользователь, и в плей­ нию ст раницы.
листе появляется название новой песни.

136 глава 3
события и обработчики

ТТостойте-ка, я понимаю, что мы взаимодей­


ствуем с DOM и все такое, но как данный код можно
назвать реальным веб-приложением? Если я закрою
окно браузера, то все мои песни пропадут. Разве не
должны элементы моего плейлиста сохраняться,
если это действительно приложение?

Мы с вами согласны, плейлист должен сохраняться;


в к о н ц е к о н ц о в , к а к о й см ы сл д о б а в л я ть все э т и п е с н и
в п л е й л и с т, если о н и не будут с о х р а н е н ы ? К р о м е т о г о ,
сущ е ствуе т масса д р у г и х ф у н к ц и й , к о т о р ы е в ы т а к ж е
м о ж е те за х о те ть в н е д р и ть . Н а п р и м е р , вам м о ж е т п о н а ­
д о б и т ь с я д о б а в и ть а у д и о и н т е р ф е й с с и с п о л ь зо в а н и е м
A P I-и н те р ф е й с а a u d i o / v i d e o , ч т о б ы м о ж н о б ы ло п р о ­
сл у ш и в а ть п е с н и , д е л и т ь с я и м и со с в о и м и д р у з ь я м и
п о с р е д с т в о м в е б -с л у ж б (в р о д е F a c e b o o k и T w itt e r ) ,
и с к а т ь в л о к а л ь н о й с е ти л ю д е й , к о т о р ы м н р а в я т с я те
ж е и с п о л н и т е л и , ч т о и вам (и с п о л ь зу я A P I-и н те р ф е й с
G e o lo c a tio n ). К т о м у ж е м ы у в е р е н ы , ч т о у вас м о гу т
в о з н и к н у т ь и д р у ги е п о ж е л а н и я в э т о м пла не .

В о зв р а щ а я с ь к п л е й л и с т у ... М ы х о т е л и б ы с т р о п р о ­
д е м о н с т р и р о в а т ь вам п р и м е р с о з д а н и я н е б о л ь ш о го
и н те р а кт и в н о го п р и л о ж е н и я , и п лейл ист о тл и чн о п о ­
до ш е л в д а н н о м случае. К р о м е т о г о , с о х р а н е н и е н е с е н
тр е б уе т A P I-и н те р ф е й с а W eb Storage и з в е р с и и H T M L 5 ,
до р а с с м о т р е н и я к о т о р о г о — еще н е с к о л ь к о глав.

С д р у го й с т о р о н ы , м ы д е й с тв и т е л ь н о н е х о т и м , ч т о б ы
здесь оставалась ка ка я -то н е д о с ка за н н о с ть ...

Переверните страницу

дальше ► 137
J o rD o B o

К y ilo r D j> eg j i eH U Io

Мы приготовили для вас


кое-какой код, так что вам
не придется делать это
самим.

М ы за р а н е е п р и г о т о в и л и для вас ко д , п о з в о л я ­
ю щ и й с о х р а н я ть п л е й л и с ты . Вам н у ж н о н р о с т о
н а п е ч а т а ть е го , а т а к ж е в н е с т и н а р у н е б о л ь ш и х
и з м е н е н и й в уж е и м е ю щ и й с я ко д , ч т о б ы в и т о ге
получился со хр а н е н н ы й пл ейл ист H T M L 5 .

О бо всех о со б е н н о стях со хр а н е н и я д ан ны х
л о ка л ь н о в браузере м ы п о г о в о р и м в главе, но -
с в я щ е н н о й A P I-и н те р ф е й с у W e b S torage, а н о к а
ч то вы научитесь со хр а нять н л ейлисты .

Е с т е с т в е н н о , н и к о г д а н е л и ш н и м б уд е т п р о ­
с м о тр е т ь п р и г о т о в л е н н ы й н а м и ко д . Вас м о ж е т
у д и в и т ь , н а с к о л ь к о м н о г о е в ы у ж е зн а е те , не
г о в о р я у ж е о то м , н а с ко л ь ко м н о го е в ы см о ж е те
п о н я т ь , д а ж е е сли ещ е н е зн а е те э т о го .

\Lm

Приготовленный код
не будет работать
J ДЫ НС | в некоторых браузе-
о о ц о р о Ж Н з» 1. рах, если вы загру­
Приготовленный
ь код не будет ра­ жаете свои страни­
цы из file://, а не с сервера (например,
б у д ь т е ботать в Internet localhost://) или онлайн-сервера.
оС Ш ороЖ Н ы Explorer 6 и 7.
В следующих главах мы поговорим об этой
Данные версии ситуации более подробно (она довольно
браузера Internet Explorer не поддержи­ часто возникает в случае с новыми функ­
вают localStorage. Поэтому если вы циями HTML5). А пока, если вы не хотите
используете Internet Explorer, поза- запускать выполнение сервера или копиро­
ботьтесь о том, чтобы его версия вать файлы на онлайн-сервер, используйте
была 8 или выше. браузер Safari или Chrome.

138 глава 3
события и обработчики

Как ({обабить приготовленный код... j^ o rfro B o

Ч у т ь н и ж е н р и в е д е н н р и г о т о в л е н н ы й ко д , к о т о р ы й н у ж н о д о б а в и ть К JjH oriip>0gjX0H ulo


в н р и л о ж е н и е W e b v ille Tunes, ч т о б ы в ы м о гл и с о х р а н и ть с ф о р м и р о в а н ­
н ы й в а м и за м е ч а те л ь н ы й пл е й л и с т. В се, ч т о вам н у ж н о сделать, — э то
созд а ть н о в ы й ф айл с и м е н е м p l a y l i s t _ s t o r e . j s , н е р е н е с т и в н е го
н р и в е д е н н ы й в н и з у ко д , а за те м в н е с т и н а р у и з м е н е н и й в у ж е и м е ю ­
щ и й с я у вас к о д (н а сл е д ую щ е й с т р а н и ц е ).

fu n c tio n sa v e(ite m ) {
v a r p l a y l i s t A r r a y = g e t S t o r e A r r a y ( " p l a y l i s t " );
p la y lis tA r r a y .p u s h (ite m );
l o c a l S t o r a g e . s e t I t e m ( " p l a y l i s t ", J S O N . s t r i n g i f y ( p l a y l i s t A r r a y )
}

f u n c t i o n l o a d P l a y l i s t () {
var p la y lis t A r r a y = g e tS a v ed S o n g s();
v a r u l = d o c u m e n t . g e t E l e m e n t B y l d ( " p l a y l i s t ");
i f ( p l a y l i s t A r r a y != n u l l ) {
f o r (var i = 0; i < p l a y l i s t A r r a y . l e n g t h ; i+ + )
v a r l i = d o c u m e n t . c r e a t e E l e m e n t ("l i " ) ;
li.in n e rH T M L = p l a y l i s t A r r a y [ i ] ;
u l . a p p e n d C h ild (li);
Перенесите Beet? этот код
} ® файл playlist_store.js
}
}

f u n c t i o n g e t S a v e d S o n g s () {
return g e t S t o r e A r r a y (" p l a y l i s t " ) ;

fu n c tio n g etS toreA rray(k ey) {


var p la y lis tA r r a y = lo c a lS to r a g e . g e tlte m (k e y );
i f ( p l a y l i s t A r r a y == n u l l I I p l a y l i s t A r r a y == ") {
p l a y l i s t A r r a y = new A rr a y ( ) ;
}
else {
p l a y l i s t A r r a y = JSON. p a r s e ( p l a y l i s t A r r a y ) ;
}
return p la y lis tA r r a y ;

дальше ► 139
сохранение плейлиста

интегрирование приготовленного кода j^ o ip o B o

к употребл ение
Н ам необ ход им о в не сти нару неб о л ьш их и зм е н е н и й , ч т о б ы и н т е гр и ­
р о в а т ь к о д для с о х р а н е н и я н л е й л и с та . С на ча л а м ы д о б а в и м с с ы л ку
н а p l a y l i s t _ s t o r e . j s в э л е м е н т <head> в p l a y l i s t . h t m l :
Д об авьт е э т у с т р о к у , р а з -
< scr ip t s r c = " p la y lis t_ s to r e . j s " x / s c r i p t > / __ — ме с ти в ее прямо над ссылкой
„ П П у
< s c n p t s гс= " p l a y l i s t . j s " > < / s c r i p t >
^ на playlist.is.
л Она за груж а ет
приготовленный код.

Т е н е р ь н у ж н о д о б а в и ть две с т р о к и в у ж е и м е ю щ и й с я у вас ко д
в p l a y l i s t . j s , к о т о р ы е будут з а гр у ж а т ь и с о х р а н я т ь н л е й л и с т:

f u n c t i o n i n i t () {
v a r b u t t o n = d o c u m e n t . g e t E l e m e n t B y l d ( "addButton"
b u t t o n .o n c l ic k = h a n d leB u tto n C lic k ;
Д а н н а я с т р о к а загр уж а ет сохраненные
l o a d P l a y l i s t (); ^ __________
песни из localStorage, когда вы за груж ает е
} свою с т р а н и ц у , благодаря чем у они о т о ­
бразят ся на экране в п л е й л и с т е .
f u n c t i o n h a n d l e B u t t o n C l i c k () {
v a r t e x t l n p u t = d o c u m e n t . g e t E l e m e n t B y l d ( " s o n g T e x t l n p u t " );
v a r songName = t e x t l n p u t . v a l u e ;
var l i = docum ent. cr e a te E le m e n t (" l i " );
l i . innerHTML = songName;
var u l = docum ent. g e tE le m e n tB y ld (" l i s t " );
u l . a p p e n d C h i l d (l i ) А э т а ст р о к а сохр аняет каж­
save(son gN am e); дую новую п е с н ю , к о т о р у ю Мы добавили
вы добавляете в п л е й л и с т . все э т и п е с ­
ни, закры ли
окно б раузера,
зат ем сно­
ва о т к р ы л и
Тест-драйв сохраненного плейлиста его, з а г р у з и ­
° MfrbvUteTunes______ ли с т р а н и ц у ,
И т а к , п е р е з а гр у з и т е с т р а н и ц у и в в е д и те назва­ I * I I I M tpv/'lni ,|| 1ю'4/-КечhH«4ri Hr-.( HIMI Ч С
и перед нам и
н и я н е с к о л ь к и х н е се н . З а к р о й т е о к н о браузера. Song n a m e
( Add Sang-) предстал со­
С н о в а о т к р о й т е е го и о н я т ь з а гр у з и т е с т р а н и ­ Blue Suede Strings, by Elvis Pagely храненный
цу. П о с л е э т о го в ы д о л ж н ы у в и д е ть п л е й л и с т плейлист
Great Objecte on Fire, by Jarry JSON Lewis
со в се м и с в о и м и с о х р а н е н н ы м и н е с н я м и . с песнями.
I Code the Line, by Johnny JavaScript

З а м надоел в а Л л е й л и с т , и бы р е ш и ­ Tfiatll be the Data, b y B u d d y Bitly an d the V ariab les

ли у д а л и т ь его ? Тогда вам п р и д е т с я Your Random Heart, by Hank "Math” Williams

з а г л я н у т ь в гла ву , п освящ ен ную A P I -


и н т е р ф е й с у W eb Storage!

140 глава 3
события и обработчики

Классно! Мы действительно начали де­


лать так, чтобы код и веб-страница взаимо­
действовали друг с другом. Однако меня
заинтересовали функции, объекты и вещи
вроде element.appendChildQ. Нужно ли мне
знать еще что-то о них?

Подходящее время.

М ы с тр е м и л и с ь п р о д е м о н с т р и р о в а т ь вам н о д р о б ­
н ы й п р и м е р т о г о , к а к H T M L -р а зм е тка и J a v a S c rip t
в с о ч е т а н и и д р у г с д р у го м п о з в о л я ю т с о зд а в а ть
и н т е р а к т и в н ы е в е б -п р и л о ж е н и я . Е сли вдум аться,
м ы с ва м и у ж е м н о го е делали:

1) в ста в л я л и к о д на с тр а н и ц у ;

2) п о з н а к о м и л и с ь с с о б ы т и я м и c lic k , и н и ц и и р у е ­
м ы м и п р и щ е л ч ке н а к н о п к е , и н а н и с а л и к о д для
п е р е х в а та и о б р а б о т к и д а н н ы х с о б ы т и й ;

3) и з в л е ка л и и н ф о р м а ц и ю и з о б ъ е к т н о й м о д е л и
д о кум е н та ;

4 ) созд авали и д о б а в л я л и н о в ы е э л е м е н т ы в D O M .

Н е п л о х о ! А те н е р ь , к о гд а у вас с л о ж и л о с ь н е к о т о ­
р о е и н т у и т и в н о е нре д ста вле н ие о то м , к а к действу­
ет весь э т о т м е ха н и зм , давайте сделаем н е б о л ь ш о й
к р ю к н о а в е ню Ja va S crip t и н о с м о тр и м , к а к и м е н н о
р а б о т а ю т ф у н к ц и и и о б ъ е кты .

Н е т, э то н е будет за у р я д н а я н р о гу л к а , н о с к о л ь к у
м ы д а ж е за гл я н е м н о д к р ы ш к и л ю к о в н а д о р о ге
и ра зб е р е м ся в то м , к а к ф у н к ц и о н и р у е т В ебвилль.

З а и н те р е с о в а л и с ь ? Т огда п р и с о е д и н я й т е с ь к н а м
в главе 4...

дальше ► 141
обзор обработчиков событитй и dom

КЛЮЧЕВЫЕ
— МОМЕНТЫ

■ В браузере постоянно происходит масса со­ а затем добавить в качестве дочернего эле­
бытий. Если вы хотите обеспечить реакцию мента по отношению к другому элементу.
на эти события, то вам потребуется обраба­
Используйте d o c u m e n t . c r e a t e E l e m e n t
тывать их с помощью обработчиков событий.
для создания новых элементов. Передайте
■ Событие c l i c k инициируется при нажатии имя тега (например, " l i " ) в вызов функ­
кнопки на странице. ции, чтобы указать, какой элемент вы хотите
создать.
■ Для обработки событий c l i c k необходимо
зарегистрировать функцию, которая и займет­ Для добавления элемента в качестве дочер­
ся их обработкой. Для этого нужно сначала него по отношению к родительскому элементу
написать функцию, а затем присвоить ее имя в DOM необходимо извлечь ссылку на роди­
свойству КНОПКИ o n c l i c k . тельский элемент и вызвать в отношении него
ap pend C h ild , передав при этом дочерний
■ Если обработчик событий c l i c k зарегистри­
элемент, который требуется добавить.
рован, то данная функция будет вызываться,
когда пользователь щелкнет на кнопке с по­ При добавлении множественных дочерних
мощью мыши. элементов в родительский элемент с исполь­
зованием a p p e n d C h ild КЭЖДЫЙ НОВЫЙ ДО-
■ Для реагирования на события c l i c k не­
черний элемент будет добавляться после
обходимо написать соответствующий код
всех прочих уже имеющихся там дочерних
в функции обработчика. Можно выводить
элементов, в результате чего они окажутся
сообщения для пользователя в диалоговых
расположены позади или под дочерними
окнах a l e r t , обновлять страницу, а также
элементами, которые уже присутствовали на
выполнять другие действия.
странице (при условии, что вы не станете вно­
■ Для извлечения данных, введенных пользова­ сить изменения в макет посредством CSS).
телем в текстовое поле формы, необходимо
Вы можете использовать API-интерфейс Web
использовать свойство v a l u e поля ввода.
Storage ( l o c a l S t o r a g e ) ДЛЯ Сохранения
■ Если пользователь ничего не ввел в текстовое данных в браузере пользователя.
поле формы, значением данного поля будет
Мы применяли localStorage для сохранения
пустая строка ("").
плейлиста с песнями, используя при этом
■ Вы можете проводить сравнение переменной заранее приготовленный код. Подробнее
с пустой строкой при помощи оператора i f о l o c a l S t o r a g e вы узнаете в главе 9.
и ==.
В следующей главе мы еще больше расска­
■ Для добавления нового элемента в объектную жем о DOM и JavaScript-возможностях, таких
модель документа его сначала нужно создать, как функции и объекты.

142 глава 3
события и обработчики

Ц Щ 5 - К Г 0С СВ0Г Д

Д а й т е своем у м о з гу н е к о т о р о е в р е м я , ч т о б ы о н у с в о и л а с н е к т ы в за и м о ­
д е й с т в и я H T M L с J a v a S c rip t. П о р а з м ы с л и т е над те м , к а к о н и р а б о т а ю т
с о о б щ а . А н о к а в ы б удете д е л а ть э т о , р а з га д а й т е н р и в е д е н н ы й н и ж е
к р о с с в о р д для з а к р е н л е н и я м а те р и а л а . В се и с н о л ь з о в а н н ы е в н е м слова
в з я т ы и з д а н н о й гл авы .

По горизонтали По вертикали
2. Метод для создания новых элементов, внедряемых 1. Исполнитель, имя которого мы использовали в примере
в объектную модель документа (DOM). с песнями.
3. Метод для добавления новых элементов в DOM. 5. Код, который занимается обработкой событий_________ .
4. «Мать» дерева объектной модели документа. 6. В случае с кнопкой click — э т о ____________ ..
7. Объектная модель документа является чем-то вроде 7. Новый элемент добавляется в ка ч е с тв е ____________
родословного____________ . элемента.
8. Мы использовали его в заранее приготовленном коде, 10. Что мы будем рассматривать в следующей главе?
чтобы стало возможным сохранение плейлиста с пес­ Функции и ____________ .
нями.
9. В случае, если пользователь ничего не введет, значением
по умолчанию элемента ввода формы будет____________
строка.
11. Оно происходит, когда пользователь щелкает на кнопке.

дальше ► 143
решение упражнения

гр ш е н и е
решение ПОП

Здесь приведен плейлист, для которого вам необхо­


димо нарисовать объектную модель документа в том
виде, который он приобретет после добавления всех Blue Suede Strings, byElvis Pagely
этих песен. Обратите внимание на порядок, в котором
Great Objects on Fire, byJerry JSON Lewis
песни были добавлены на страницу, и разместите
соответствующие элементы на своих местах в DOM. I Code the Line, byJohnny JavaScript
Наше решение выглядит так. That'll be the Data, by Buddy Bitlyand the Variables

Your Random Heart, by Hank "Math" Williams


| document

С html

| head | body |
А вот остальная
часть POM

title | ul id= “playlist” ^

Blue Suede Strings, Your Random H e a rt, by


by Elvis Pagely Hank “Math" Williams

Great O bjects That'll be the Data, by


on Fire, by J e rry Buddy Bitly and the
J S O N Lewis Variables
I Code th e Line, by
Johnny JavaScript

Пришлось ли вам строить какие-либо предположения Д а , поскольку он влияет на п о ­


насчет порядка, в котором элементы < i i > добавляются рядок отображения песен
в родительский элемент? на странице; appendChild всегда
добавляет новый элемент после
дочернего элементаj который
уже т ам был до него.

144 глава 3
события и обработчики

Ц Щ § - к Г °с с Б о Г д . ^ ш е н и е

дальше ► 145
4 ^JJhkUuu и ойьетсщы jaVaScript

Серьезный JavaScript+

М ожете л и вы уже назвать себя создателем сценариев? Вполне


возможно, поскольку вы уже многое знаете о JavaScript, однако кто захочет
быть простым писателем сценариев, когда можно быть программистом? Пора
проявить серьезность и поднять планку, — настало время познакомиться
с функциями и объектами. Они являются ключом к написанию более эффек­
тивного, лучше организованного и легкого в сопровождении кода. Они также
активно используются наряду сАР1-интерфейсами HTML5 JavaScript, поэтому
чем лучше вы будете в них разбираться, тем быстрее сможете освоиться с тем
или иным новым API-интерфейсом и начать его использовать. Пристегнитесь,
поскольку эта глава потребует вашего всецелого внимания...
оценка своих сил

Расширяем ваш словарный запас


В ы у ж е м н о го е ум еете делать с н о м о щ ь ю Ja v a S c rip t. Д а в а й те в згл я н е м н а т о ,
ч т о вам у ж е н о силам :

Извлечение элемента из объект


ной модели документа (РОМ)

<script>
var guessInput = document.getElementByld(Mguess M);
С
var guess = guessInput.value;
Извлечение значения т е к­
var answer = null;
стового поля ввода формы.

Создание нового массива,


var answers = [ "red",
заполненного строками.
"green" ,
"blue"]; И спользование И звлечение т акого
Г библиот ек ф ункций. свойства м ассива,
V к а к len gth.
var index = Math.floor (Math, random() * answers.length);

^ ч Принятие решений на основе


if (guess = answers [index]) { результатов проверки условий.
answer = "You're right! I was thinking of " + answers[index];
} else { ^
answer = "Sorry, I was thinking of " + answers[index]; Использование
элементов
} массива.
alert(answer);
</script>

Использование браузерных
функций (например , alert).

О д нако н о ка м н о ги е ваш и зн а н и я явл яю тся неф орм альны м и. В ы , ко н е ч н о ,


зн а е те , к а к и з в л е ка т ь э л е м е н т ы и з о б ъ е к т н о й м о д е л и д о к у м е н т а ( D O M ), п р и ­
сва и ва ть н о в ы е з н а ч е н и я , н о е сли м ы н о н р о с и м вас о б ъ я с н и т ь , ч т о т а к о е
d o c u m e n t . g e t E l e m e n t B y ld в т е х н и ч е с к о м п л а н е , в е р о я т н о , у вас в о з н и к н у т
с эти м н е ко т о р ы е труд ности. Н о не с то и т б е сно ко иться , но ско л ьку к ко н ц у
гл а в ы в ы с м о ж е те без труда сделать э то .

А ч т о б ы вам э то д е й с т в и т е л ь н о удалось, м ы н е с та н е м н а ч и н а т ь с гл у б о к о го
ана л и за g e t E l e m e n t B y ld , а за й м е м ся ко е -ч е м более интересным: р а с ш и р и м ваш
с л о в а р н ы й занас в о б л а с ти J a v a S c rip t и н а у ч и м с я делать н о в ы е ве щ и .

148 глава 4
функции и объекты javascript

Как добавить свои собственные функции


Ранее мы с вами иснользовали встроенны е функции, нанример a l e r t или даж е Math, random, но вдруг
у вас возникнет необходим ость добавить свою собственную функцию? Донустим, мы захотели нанисать
код вроде следующего:
var guessInput = document.getElementByld("guess");
var guess = guess Input, value; *4^ ^ guess поль3о ват еля
т очно т а к же, как и на п р е д ы д у -
var answer = checkGuess (guess) ; щей странице...
al / a n e w p r\ • A\

^ --
ЖеА| з а м е н и т ь на и з я и ш ,, ^ д, основного кода , м ы м о -
смож ем вы зы ват ь и M m ^ J ^ deTa^m Cke° kQuess‘ ко^ о р у н >
*мо же самое.
Создание функции checkGuess
Q Для создания функции необходимо воспользоваться ключевым словом
function, после которого следует указать ИМЯ, например checkGuess.

Своей функции вы можете передавать


function checkGuess(guess) { ноль и более параметров. Используй­
var answers = [ "red" ,
те параметры для передачи значений
функции. Здесь нам требуется один
"green" ,
параметр: guess пользователя.
"blue"];

var index = Math, floor (Math, random () * answers.length);

if (guess == answers[index]) {
answer = "You're right! I was thinking of " + answers[index];
} else {
answer = "Sorry, I was thinking of " + answers[index];

}
return answer; ' *)
Задайте тело своей функции, которое
Опционально можно воз­ следует заключить в фигурные скобки.
вращать значение в качестве Тело содержит весь код, который обе­
результата вызова функции. спечивает выполнение работы функции.
Здесь мы возвращаем строку Здесь в теле мы повторно используем
с сообщением. код с предыдущей страницы.

дальше ► 149
как работают функции

Как работает функция


Т а к к а к ж е все э то р аб отает? Ч т о п р о и с х о д и т , к о гд а м ы действительно
вызываем ф у п кц и ю ? Д а в а й те в згл я п е м в о б щ и х ч е р т а х .

Итак, сначала нужно создать ф ункцию . function bark(dogName f dogWeight) {


if (dogWeight <= 10) {
Д о п усти м , м ы то л ько ч т о паписал и повую
ф у п к ц и ю b a r k , у к о т о р о й и м е е т с я два па р а м е ­ return dogName + " says Yip";
тр а : dogN am e и d o g W e i g h t , а т а к ж е весьм а за- } else {
п и м а т е л ь п ы й ф р а гм е п т ко д а , в о з в р а щ а ю щ и й return dogName + " says Woof";
к л и ч к у с о б а к и и т о , ч т о о п а лает, в за в и с и м о ­
}
с т и о т т о г о , к а к о й о п а и м е е т вес.

В о т н а ш а удобная
ф у н к ц и я bark.

Имя нашей Здесь мы переда­


Теперь давайте вызовем функцию ! функции ем два аргумента:
В ы у ж е зп а е те , к а к в ы зы в а т ь ф у п к ц и ю : п у ж п о кличку и вес.
п р о с т о в в е с ти ее и м я и п е р е д а ть е й все н е ­
о б х о д и м ы е а р гу м е п т ы . В д а п п о м случае п а м
bark("Fido", 50)
п о т р е б у е т с я п е р е д а ть два а р гу м е п та : с т р о к у
с к л и ч к о й с о б а к и и вес с о б а к и в вид е ц е л о го
чи сл а .

Д а в а й те в ы п о л п и м в ы зо в и п о с м о т р и м , к а к все
э то р а б о та е т:

При вы зо ве b a r k а р г у м е н т ы
function bark(dogName , dogWeight)
присваиваю т ся им енам п а ­
р а м е т р о в в ф у н к ц и и bark. if (dogWeight <= 10) {
return dogName + says Yip";
else {
return dogName + says Woof";
И каждый раз , когда
параметры встреча­
ются в функцииj будут
использоваться пере­
данные нами значения.

150 глава 4
функции и объекты javascript

А теперь давайте позволим телу ф унк­


ции сделать свою работу.
П осле то го ка к м ы п р и с в о и л и зпа чепие ка ж ­ function bark(dogName, dogWeight) {
д о го а р гу м е п та с о о тв е т с тв у ю щ е м у п а р а м е тр у if (dogWeight <= 10) {
в ф у п к ц и и (п а п р и м е р , "Fido" для dogN am e и
return dogName + " says Yip";
целое ч и с л о 50 для d o g W e i g h t ) , м ы г о т о в ы
п е р е х о д и т ь к о ц е п к е в се х о п е р а т о р о в в теле } else {
ф упкц ии . return dogName + " says Woof";

О п е р а то р ы о ц е пи в а ю тся сверху в п и з, к а к и }

л ю б о й д р у г о й к о д , к о т о р ы й в ы п и ш е т е . Раз-
п и ц а з а кл ю ч а е тс я в т о м , ч т о м ы будем делать
э то в среде, где и м е п а п а р а м е тр о в d ogN am e и Здесь мы оцениваем весь код
d o g W e i g h t п р и с в а и в а ю т с я а р гу м е п та м , п ере- в теле функции.
даппы м в ф упкц ию .

Помните, что функции необязательно должны


О пционально у нас могут иметься возвращать значения. Однако в данном случае
операторы return в теле ф ункции... функция bark возвращает значение.
А когда строка
... где м ы будем в о зв р а щ а ть з п а ч е п и е коду,
возвращается,
с о в е р ш и в ш е м у в ы зо в . Д а в а й те п о с м о т р и м ,
она присваива­
к а к э то р а б о та е т: Строка "Fido says Woof" ется переменной
возвращается вызывающе­ sound, которая
м у коду (то есть коду, вы­ затем переда­
К а к «кЗ ко « “„Л и ам '
звавшему функцию bark). ется alert, в р е ­
„ д „ не ровен
зультате чего
на экран выво­
дится диалоговое

function bark(dogName, dogWeight) {


"Fido says W o o f
ED окно с соот­
ветствующим
сообщением.
^ if (dogWeight <= 10) { У
var sound = bark("Fido " , 50);
( return dogName + " says Yip";
alert(sound);
} else {
V c return dogName + 11 says Woof" ;
h ttp ://lo c a lh o st
}
Fido

дальше ► 151
важность функций и объектов

Я неустанно твержу вам, что все


A P I-интерфейсы HTM L5 битком набиты
функциями, объектами и прочими продви­
нутыми JavaScript-возможностями...

Если бы у нас была лишняя минутка поговорить...


В ы дум али, ч т о в главе 4 будете а к т и в п о п о з п а в а т ь п о в о е
в H T M L 5 ? К о п е ч п о ж е , т а к и будет. О д п а к о п р е ж д е вам о б я ­
за те л ь н о п у ж п о р а зо б р а ть с я в т о м , ч т о и м е п п о я в л я е тс я
A P I-и п т е р ф е й с о в J a v a S c rip t в H T M L 5 , ч е м м ы и за й ­
м е м ся в д а п п о й главе.

Т а к ч т о ж е я в л я е тс я э т о й о с п о в о й ? С ч и т а й т е , ч т о A P I-
и п т е р ф е й с ы J a v a S c rip t в H T M L 5 с о с т о я т и з о б ъ е кт о в , м е­
т о д о в (т а к ж е п а зы в а е м ы х функциями) и с в о й с т в . Ч т о б ы
п о -п а с то я щ е м у овлад еть A P I-и п т е р ф е й с а м и J a v a S c rip t, вам
п е о б х о д и м о х о р о ш о р а зб и р а т ь с я в э т и х вещ ах. Е с те с тв е п -
п о , в ы м о ж е т е п о п ы т а т ь с я о б о й т и с ь и без з п а п и й о п и х , од­
п а к о в т а к о м случае п р и и с п о л ь з о в а п и и А Р 1 -и п те р ф е й с о в
вам п р и д е т с я п о с т о я п п о с т р о и т ь д о га д к и , ч т о п е п о з в о л и т
вам п о л п о с т ь ю за д е й с тв о в а ть и х п о т е п ц и а л (п е го в о р я уж е
о т о м , ч т о в ы будете с о в е р ш а ть м ассу о ш и б о к и п и с а т ь пе-
к а ч е с т в е п п ы й к о д ).

М ы р е ш и л и о б р а т и т ь ваш е в п и м а п и е п а д а п п ы е а с п е к т ы ,
ч т о б ы в ы зп а л и , ч т о вас о ж и д а е т в п е р е д и . С ам ое замеча-
те л ь п о е за к л ю ч а е тс я в т о м , ч т о к к о п ц у гл а в ы в ы будете
р а зб и р а т ь с я в о б ъ е кта х , ф у п к ц и я х , м е то д а х и массе п р о ч и х
с в я з а п п ы х с п и м и в е щ е й л уч ш е , ч е м п р и м е р п о 98 % л ю д е й ,
за н и м а ю щ и х с я п а п и с а п и е м с ц е п а р и е в . И э то п е ш у тка .

152 глава 4
функции и объекты javascript

« р у н к ц и ю
Интервью недели:
Вещи, о которых вы не знали

Head First: Д о б р о п о ж а л о в а ть , Ф у п к ц и я ! Н а д е ю сь, о п и исп о л ь зую т и х п о с то я п п о : a l e r t , docum ent.


с е го д п я В ы п ове д а е те п а м м п о го е о себе. g e tE le m e n tB y ld , M ath. random. О п и п р о с т о п е о п р е ­
д е л я ю т свои собственные ф у п к ц и и .
Function: Рада б ы т ь здесь.
Head First: Ч т о ж , в е р п о , в случае с a l e r t все п о п я т -
Head First: М ы за м е т и л и , ч т о в п а с то я щ е е в р е м я
п о , п о в о т д р у ги е две совсем п е п о х о ж и па ф у п кц и и .
м п о ги е п о в и ч к и в J a v a S c rip t п е с к л о п п ы с л и ш к о м
ч а с т о и с п о л ь з о в а т ь Вас. О п и п р о с т о п и ш у т с в о й Function: Э то ф у п к ц и и , в и д и т е л и ... п о с т о й т е -к а ,
ко д , с т р о к а за с т р о к о й , д в и га я с ь с в е р х у в п и з . П о ­ м и п у т о ч ку ...
ч е м у и м с то и л о б ы уделять В ам б о льш е в п и м а п и я ?
...М п е т о л ь к о ч т о с к а з а л и , ч т о ч и т а т е л и ещ е п е
Function: Д а , п е с к л о п п ы , и э то п р и с к о р б п о , п о ­ п о з п а к о м и л и с ь с э т и м и т и п а м и ф у п к ц и й , о д п а ко
с к о л ь ку я пе су в себе б о л ьш и е в о з м о ж п о с т и . Д у м а й ­ о п и сдел аю т э то ч е р е з п е с к о л ь к о с т р а п и ц . Т а к и л и
те о б о м п е т а к: я — т о , ч т о п о з в о л я е т вам п а п и с а т ь и п а ч е , след ует о т м е т и т ь , ч т о ф у п к ц и и и с п о л ь з у ­
к о д о д и п раз, а за те м п о в т о р п о и с п о л ь з о в а т ь е го . ю т с я повсю ду.

Head First: П р о с т и т е , ч т о с п р а ш и в а ю , п о е сли В ы Head First: И т а к , ф у п к ц и я в о зв р а щ а е т з п а ч е п и е ,


п р о с т о даете и м в о з м о ж п о с т ь делать о д п и и те ж е п равил ьпо? В связи с э ти м х о ч у с п р о с и ть : а ч т о ,
в е щ и с п о в а и спо ва ... э то ведь п е м п о г о с к у ч п о , п е е сли у м е п я п е т з п а ч е п и я , к о т о р о е я х о ч у верпуть?
т а к ли?
Function: М п о г и е ф у п к ц и и в о з в р а щ а ю т зп а ч е п и я ,
Function: Н е т-п е т, ф у п к ц и и я в л я ю т с я п а р а м е т р и ­ о д п а к о ф у п к ц и я во все п е о б я за те л ь п о д о л ж п а п о ­
з о в а н н ы м и . Д р у г и м и сл о в а м и , к а ж д ы й р а з, к о гд а с ту п а ть та к. Е сть п ем ало ф у п к ц и й , к о т о р ы е п р о с т о
в ы и с п о л ь зуе те ф у п к ц и ю , в ы м о ж е те п ередавать ей де л а ю т ч т о -то , п а п р и м е р о б п о в л я ю т о б ъ е к тн у ю м о­
а р гу м е п т ы , б л а го д а р я ч е м у ста п е те п о л у ч а т ь пазад дель д о ку м е п т а (D O M ) , п о с л е ч е го п е в о зв р а щ а ю т
резул ьта ты , к о т о р ы е будут о тл и ч а т ь с я д р у г о т д р уга п и к а к о г о з п а ч е п и я , и все п р е к р а с п о .
в з а в и с и м о с т и о т т о г о , ч т о в ы е й пе р е д а л и .
Head First: То есть в т а к и х ф у п к ц и я х о т с у т с т в у ю т
Head First: А п е л ь зя л и п р и в е с т и п р и м е р ? о пе р а то р ы return?

Function: Д о п у с т и м , в а м п е о б х о д и м о с о о б щ а т ь Function: Д а , и м е п п о та к.
пользователям сто и м о сть то ва р о в, ко то р ы е о п и
п о м е с ти л и в св о ю э л е к т р о п н у ю к о р з и н у в и п т е р п е т -
Head First: Ч т о ж , а к а к п а с ч е т п р и с в а и в а н и я и м е п
с в о и м ф у п кц и я м , а то м п е д о в о д ил о сь слы ш а ть, ч т о
м а га з и п е , п о э т о м у в ы р е ш и л и п а п и с а т ь ф у п к ц и ю
э то делать п е о б я за те л ь п о , е сли п е х о ч е т с я .
com puteShoppingC a r t T o t a l . Сделав э то , в ы с м о ж е ­
те п е р е д а в а ть ф у п к ц и и р а з л и ч п ы е э л е к т р о п п ы е Function : Д а в а й те п е будем и з л и ш п е п у га ть ауди то ­
к о р з и п ы , п р и н а д л е ж а щ и е р а з п ы м п о л ь зо в а те л я м , р и ю . Д а в а й те в е р п е м с я к э т о й тем е, ко гд а ч и т а т е л и
и к а ж д ы й ра з п о л у ч а т ь с о о тв е т с тв у ю щ е е з п а ч е п и е у з п а ю т о б о м п е п е м п о г о больш е?
сто и м о сти товаров в ко п к р е т п о й ко р зи п е .
Head First: О б е щ а е те м п е д ать э к с к л ю з и в п о е и п -
...К с т а т и , в о з в р а щ а я с ь к В а ш е м у з а м е ч а п и ю па-
те р в ь ю ?
счет то го , ч то п о в и ч к и пе о чепь часто использу­
ю т ф у п к ц и и ; п а с а м о м деле э то п е т а к , п о с к о л ь к у Function: М ы э то ещ е обсудим ...

дальше ► 153
параметры и аргументы

Не уверена, что понимаю разницу


между параметром и аргументом:
это случайно не одно и то же?

Нет, это разные понятия.


П р и о п р е д е л е н и и ф у н к ц и и в ы м о ж е т е определишь
ее с и с п о л ь з о в а н и е м о д н о го и л и более параметров.

Здесь мы определяем три


параметра: degrees, mode
и duration.

j
func t i o n coo k ( d e g r e e s , mode, duration) {
// здесь будет валя код

П р и в ы зо в е ф у н к ц и и в ы вызываете ее с и с п о л ь зо в а ­
н и е м аргументов:

\ т?
cook(425.0, "bake", 45);

Это аргументы. Здесь имеются три


аргумента: число с плавающей точкой
строковое значение и целое число.

cook(350.0, "broil", 10);

Т а к и м о б р а зо м , с в о и п а р а м е т р ы в ы будете о п р е д е л я ть
т о л ь к о о д и п р аз, а в ы зы в а т ь с в о и ф у п к ц и и ста п е те с и с ­
п о л ь з о в а н и е м м а ссы р а з п ы х а р гу м е н то в .
3 ас удивит, насколько много людей путается в том, где исполь­
зуются параметры, а где аргументы. 3 некоторых книгах даже
встречается неверное толкование, поэтому если вы где-то увидите,
^ что утверждается обратное, то будете знать, где правда...

Функцию определяют с использованием параметров,


а вызывают с использованием аргументов.
154 глава 4
функции и объекты javascript

Днапк>Мия «^нкДии

Т е п е р ь , ко гд а в ы зп а е те , к а к о п р е д е л я ть п в ы зы в а т ь ф у п к ц и и , давай те
уб е д и м ся , ч т о в ы х о р о ш о р а зб и р а е те с ь в с и п т а к с и с е . В о т к а к в ы гл я д я т
с о с та в п ы е ч а с т и а п а т о м и и ф у п к ц и и :
г Даже если у вашей ф унк-
Затем идут з а - ции нет параметров, вам
После ключевого слова ключенные в круглые по-прежнему необходимо
Вначале всегда function следует имя скобки и разделенные указать открывающую
должно идти ключе­ вашей функции. запятой параметры, и закрывающую скобки,
вое слово function. которых может быть
ноль и более.

к Тело функции заклю ­


чается в две фигурные
var bonus = level * score * .1; скобки и содержит
набор операторов
return score + b o n u s ; (точно так же, как
привычные для вас
операторы).

Функция может вклю ­ Оператор re tu rn включает


чать оператор с ключе­ выражение, которое возвра­
Это закрыва­
вым словом return, однако щается в качестве резуль­
ющая скобка
это вовсе не обязательно. тата вызова функции.
тела функции.

Часш°
зад аваем ы е .........
B o T L j= > o tb l

Почему перед именами параметров ] ) • Я передаю переменную своей функ­ Смогу ли я изм енять значен и я
не ставится var? Параметр — это же но­ ции; если я изменю значение соответ­ в функции?
вая переменная, ведь так? ствующего параметра в моей функции,
то приведет ли это также к изменению
0 : Вы сможете изменять только значения
0 : Да, так и есть. Функция сделает за вас моей исходной переменной?
глобальных переменных (они определяются
всю работу по созданию экземпляра пере­
вне функций) или переменных, которые вы
менной, поэтому вам не нужно указывать 0 : Нет. Когда вы передаете примитивное явно определили в своей функции. Вскоре
ключевое слово v a r перед именами своих значение, оно копируется в параметр. Мы
мы чуть подробнее затронем эту тему.
параметров. называем это «передача по значению».
Таким образом, если вы измените значение
^ 3 * Каковы правила присваивания имен параметра в теле своей функции, то это Котсутствует
- - оператор
— , *return?
™ . -
функциям? никак не повлияет на оригинальное значе­
ние вашего аргумента. Исключением здесь
0 : Они аналогичны правилам присваива­ является передача массива или объекта, но 0 : Функция без оператора r e t u r n воз­
ния имен переменным. об этом мы поговорим чуть позже. вращает значение u n d e f in e d .

дальше ► 155
упражнение

^озьлли в руку карандаш_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


Воспользуйтесь своими знаниями о функциях и передаче аргументов параметрам для оцен­
ки приведенного ниже кода. Сделав это, напишите внизу, какое значение будет иметь каждая
из переменных. Проверьте свои ответы, посмотрев решение этого задания в конце главы,
прежде чем двинетесь дальше.

function dogsAge(age) {
return age * 7;
}

var myDogsAge = dogsAge (4) ;

function rectangleArea(width, height) {


var area = width * height;
return area;
}

var rectArea = rectangleArea(3, 4);

function addUp(numArray) {
var total = 0;
for (var i = 0; i < numArray.length; i++) {
total += numArray[i];
}
return total;
}

var theTotal = addUp([1, 5, 3, 9]);

function getAvatar(points) {
var avatar;
Напишите
здесь, какое
if (points < 100) {
значение б у ­
avatar = "Mouse"; дет и м ет ь
} else if (points > 100 && points < 1000) { каждая из
avatar = "Cat";
} else {
avatar = "Ape";
С
myDogsAge = .............
}
rectArea = .............
return avatar;
} theTotal = .............
var myAvatar = getAvatar(335); myAvatar = .............

156 глава 4
функции и объекты javascript

Налл нужно поговорить о некото­


рых особенностях использова­
ния переменных...

Локальные и глобальные переменные


НуЖно знать разницу меЖду ними

В ы у ж е зп а е те , ч т о м о ж е т е о б ъ я в л я ть п е р е м е п п ы е с и с п о л ь зо в а ­
н и е м к л ю ч е в о го слова v a r и и м е п и где у го д п о в св о е м J a v a S c rip t-
Еслииеремеииая
ко д е :

var avatar;
Это гл о б а л ь н ы е п е р е м е н н ы е j
\ С ~ они п о в с е м е с т н о д о с т у п н ы
объявлена
var levelThreshold = 1000; в в а ш е м J a v a S c r i p t -коде.
внефункции,
В ам т а к ж е и з в е с т п о , ч т о п е р е м е п п ы е
м о ж п о о б ъ я в л я ть и в п у т р и ф у п к ц и и : тооиаявляется
function getScore(points)
var score; ^
{
Переменные points>
score и i объявляются ГЛОБАЛЬНОЙ.
внутри функции.

for (var i = 0; i < levelThreshold; i++) {


Еслиже
}
//code here
Мы называем их локальны­
ми переменными, потому
иеремеииая
return score;
что они доступны только
локально в самой функции.
объявленавнутри
Даже если мы используем levelThreshold внутри
функцииj она будет глобальной переменной, п о ­
функции, тооиа—
скольку объявлена вне функции.
ЛОКАЛЬНАЯ
О д п а к о к а к о е все э то и м е е т зп а ч е п и е ? П е р е м е п п ы е есть п е р е ­
м е п п ы е , п е т а к ли? Ч т о ж , о т т о г о , гд ^ в ы о б ъ яв л яе те с в о и п е р е ­
м е п п ы е , за в и с и т, насколько о п и будут видимы для о с т а л ь п о й ч а с т и
ва ш е го код а. А п о п и м а п и е т о г о , к а к р а б о т а ю т две э т и р а зп о в и д -
п о с т и п е р е м е п п ы х , в п о с л е д с т в и и п о м о ж е т вам п и с а т ь более л е г­
к и й в с о п р о в о ж д е п и и к о д (п е г о в о р я у ж е о т о м , ч т о э то п о м о ж е т
вам р а з о б р а ть с я в ко д е , п а п и с а п п о м д р у ги м и л ю д ь м и ).

дальше ► 157
локальная и глобальная область видимости

Понятие области видимости локальных и глобальных переменных


От т о г о , где вы определяете своп перемеппые, будет зависеть их область видимости', то есть
там, где перемеппые определепы и пе определепы, опи соответствеппо будут видимы и пе-
видимы для вашего кода. Давайте взгляпем па пример, где присутствуют перемеппые как с
локальпой, так и с глобальпой областью видимости. Помпите, что перемеппые, которые вы
определяете впе фупкции, будут обладать глобальпой областью видимости, а перемеппые,
определяемые впутри фупкции, —локальпой областью видимости.
Э т и ч е т ы р е п ер ем енны е обла даю т г л о ­
бальной о б ла с т ь ю в и д и м о с т и , т о ест ь
они определены и видимы во всем п р и в е ­
var avatar = "generic"; денном ниже коде.
var skill = 1.0; С ледует о т м е т и т ь , ч т о если вы у к а ­
var pointsPerLevel = 1000; жете ссылки на д о п олни т ель ны е с ц е ­
var userPoints = 2008; нарии в своей с т р а н и ц е , т о они тоже
с м о г у т у в и д е т ь глобальные перем енны е!

function getAvatar(points) { Переменная level здесь я вля ет с я л о к а л ь -


var level = points / pointsPerLevel;\ 4 - ной и видимой т о ль к о для кода в н у т р и
ф ун кц и и g e tA v a ta r. Это о з н а ч а е т , чт о
т о ль к о данная ф у нкци я см ож ет п о л у ­
if (level = o) ( \ \ ч и т ь д о с т у п к пер ем е н н о й level.
return "Teddy bear"; \
Не будем забы ват ь о п а р а м е т р е p o in ts ,
} else if (level == 1) {
к о т оры й также обладает лок а ль
return "Cat"; \ ной о б ла с т ь ю ви д и м о с т и в ф у нкции
} else if (level > =2 ) { g e tA v a ta r.
return "Gorilla"; О б р а т и т е в н и м а н и е , чт о в случае
с g e t A v a t a r также и с п о л ь з у е т с я г л о ­
бальная пер ем е н н а я p o in ts ? e rL e v e i

8 u p d a te P o in ts у нас и м е е т с я л о к а л ь ­
function updatePoints(bonus , newPoints) ная п ер е м е н н а я L Д а н н а я п ер е м е н н а я
for (var i = 0; i < bonus; i++) { видима для всего кода в updatePoints.
newPoints += skill * bonus; bonus и n e w P o in ts также я в л я ­
} ю т с я л о к а ль н ы м и по о т н о ш е ­
return newPoints + userPoints; нию к u p d a te P o in ts , в т о вр е м я как
userPoints я вля е т с я глобальной п е р е ­
менной.

userPoints = updatePoints(2, 100) А здесь в коде м ы мож ем и с п о л ь з о в а т ь


т о л ь к о глобальные п е р е м е н н ы е , пр и
avatar = getAvatar(2112);
э т о м у нас н е т д о с т у п а к к а к и м - л и б о
п е р е м е н н ы м в н у т р и ф у н к ц и й , поскольк у
они невидимы в глобальной области.

158 глава 4
функции и объекты javascript

Готов поклясться,
что переменная была прямо
у меня за спиной, но когда
я обернулся, она уже исчезла.

Недолгая Жизнь переменных


Е сли вы — и е р е м е и и а я , т о вам п р и х о д и т с я пе-
л е гк о и ваш а ж и з п ь м о ж е т о ка за т ь с я к о р о т к о й .
Т а к и будет, е сли в ы , к о п е ч п о , п е я в л я е те сь гл о ­
б а л ь п о й п е р е м е п п о й , х о т я д а ж е в случае с п и м и
п р о д о л ж и т е л ь н о с т ь ж и з п и о гр а п и ч е п а . Н о ч т о
о п р е д е л я е т д л и т е л ь н о с т ь с у щ е с тв о в а н и я п е р е ­
м е п п о й ? Д е л о о б с т о и т сл е д у ю щ и м о б р а зо м :

Глобальные переменные существуют столько


же, сколько и соответствующая веб-страница.
Ж и з п ь гл о б а л ь п о й п е р е м е п п о й п а ч и п а е т с я ,
ко гд а ее J a v a S c rip t з а гр у ж а е тс я в стр а п и ц у . О д ­
п а к о ж и з п ь в а ш е й гл о б а л ь п о й п е р е м е п п о й за­
к о н ч и т с я , к а к т о л ь к о п о л ь зо в а те л ь п о к и п е т
ве б -стра п иц у. Д а ж е е сли о п п е р е з а гр у з и т ту ж е
сам ую стр а п и ц у , все в а ш и гл о б а л ь п ы е п е р е м е п ­
п ы е будут у п и ч т о ж е п ы , а за те м в о с с о зд а п ы в за­
по во за гр у ж е п п о й страпиц е.

Локальные переменные обычно исчезают по за­


вершении работы функции. Л о к а л ь п ы е п е р е ­ Мы сказали «обычно», поскольку
м е п п ы е со зд а ю тс я п р и п е р в о м в ы зо в е в а ш е й
существуют особые способы сохра­
ф у п к ц и и и ж и в у т до т е х п о р , п о к а э та ф у п к ц и я
нить жизнь локальным переменным
п е з а к о п ч и т с в о ю р а б о ту (в о з в р а т и в п р и э т о м
на более длительный срок, однако мы
з п а ч е п и е и л и ж е п е т ). С ледует о т м е т и т ь , ч т о
не станем беспокоиться о них сейчас.
в ы м о ж е т е в зя ть з п а ч е п и я с в о и х л о к а л ь п ы х пе-
р е м е п п ы х и в о з в р а т и т ь и х и з ф у п к ц и и до т о г о ,
к а к э ти пе р е м е ппы е предстапут перед ц и ф р о ­
в ы м т в о р ц о м п а т о м свете.

Т а к ч т о ж е , п о л у ч а е тс я , «сбеж ать» о т с т р а п и ц ы
п и к а к Н Е Л Ь З Я ? Е сл и в ы — л о ка л ь п а я п е р е м е п -
п а я, т о ваш а ж и з п ь п р о л е т а е т б ы с т р о . Н о если
Присоединяйтесь к нам в главе,
вам п о в е зл о р о д и т ь с я гл о б а л ь п о й п е р е м е п п о й ,
т о в ы будете зд р а в с тв о в а ть , п о к а п о л ь зо в а те л ь посвященной A P I -инт ерф ейсу Web
п е п е р е з а гр у з и т с т р а п и ц у в б раузере. Storage, где мы помож ем ваш им
_ данным избежать «уж асаю щ их»
О д п а к о в с е -та ки должен с у щ е ств о в а ть с п о с о б
для н и х последствий перезагрузки
«сбежать» о т с т р а п и ц ы ! М ы м о ж е м е го п а й т и !
веб-странии,ы!
К а к в ы считаете?

дальше ► 159
переменные в тени

Интересно, что
будет, если я присвою
локальной переменной то же
имя, которое имеет уже суще­
ствующая глобальная пере­
ев V менная?

Помещаем «в тень» глобальную переменную.


В о т ч т о м ы и м е е м в виду. Д о п у с т и м , у вас е сть гл обал ь­
н а я п е р е м е н н а я b e a n C o u n t e r и в ы о б ъ яв л яе те ф у п к ­
ц и ю , к а к п о к а з а н о далее:

var beanCounter = 1 0 ;
Здесь у нас
имеются
function getNumberOf Items (ordertype) { и глобальная
var beanCounter = 0; Чг и локальная
if (ordertype == "order”) { переменные!
/ / сделать что-то с помощью beanCounter...
}
return beanCounter;
}

К о гд а в ы сделаете э т о , л ю б ы е с с ы л к и п а b e a n C o u n t e r
в н у т р и ф у н к ц и и будут в е с т и к л о к а л ь п о й п е р е м е п п о й ,
а не к гл о б а л ь н о й . Т а к и м о б р а зо м , м ы го в о р и м , ч т о гл о ­
бальная п е р е м е н н а я будет п а х о д и т ь с я «в те п и » л о ка л ь ­
н о й п е р е м е н н о й (д р у ги м и сл о в а м и , м ы п е с м о ж е м ее
ув и д е ть , п о с к о л ь к у па м п о м е ш а е т э то сделать л о ка л ь п а я
п е р е м е п п а я ).

б е д у е т от метит ь , что ло -
кальная и глобальная переменные
не влияют друг на друга: если и з ­
менить одну из них , то это никак
не скажется на другой. Они явля­
ются независимыми переменными.

160 глава 4
функции и объекты javascript
Част°

ЧаДаВаеМые
В опросы

создаете глобальную переменную. Следует отметить, что мы не


При отслеживании области видимости всех этих локаль­ рекомендуем прибегать к такой практике кодирования; не только
ных и глобальных перемеренных можно запутаться, так почему потому, что она потенциально способна сделать ваш код неудобо­
же не использовать только глобальные переменные? Я именно читаемым, но и потому, что, как считают некоторые люди, данное
так всегда и поступаю. поведение может однажды измениться в реализациях JavaScript
(что, возможно, приведет к нарушению вашего кода).
0 : Если вы пишете код, который является сложным или будет
нуждаться в длительном сопровождении, то нужно внимательно Нужно ли мне определять функцию, прежде чем исполь­
следить за тем, как вы распоряжаетесь своими переменными. Если зовать ее, и может ли объявление функции появиться где
вы слишком рьяно будете создавать глобальные переменные, угодно в моем сценарии?
вам станет сложно уследить за тем, где они используются (и где
вы вносите изменения в значения своих переменных), что может
0 : Объявления функций могут появляться где угодно в вашем
привести к написанию некачественного кода. Все это окажется
сценарии. Если захотите, вы можете объявить функцию ниже, там,
даже еще более важным, если вы будете писать код совместно с
где будете использовать ее. Это можно делать, поскольку когда вы
коллегами или станете использовать сторонние библиотеки (даже
загружаете свою страницу в первый раз, браузер производит разбор
если они окажутся грамотно написанными, то все равно должны
всего JavaScript, имеющегося на странице (или располагающегося
быть структурированы во избежание проблем).
во внешнем файле), и видит объявление функции до того, как
Таким образом, глобальные переменные следует использовать там, начнет выполнение кода. Вы также можете размещать объявления
где это имеет смысл, но при этом необходимо проявлять умерен­ глобальных переменных в любой части своего сценария, однако
ность, и всякий раз, когда предоставляется возможность, делать мы рекомендуем объявлять все свои глобальные переменные
свои переменные локальными. По мере увеличения опыта работы в верхней части файлов, чтобы их легче было отыскать.
с JavaScript вы будете узнавать дополнительные методики структу­
При использовании более одного внешнего JavaScript-файла
рирования кода, чтобы он оказался более легким в сопровождении.
следует учитывать, что при наличии двух функций с одинаковым
именем в разных файлах будет использоваться та, которую браузер
К — ............. ................................... увидит последней.
однако я загружаю еще и дополнительные JavaScript-файлы.
Эти файлы будут видеть отдельны е наборы глобальных
Кажется, что все жалуются на чрезмерное использование
переменных?
глобальных переменных в JavaScript. Почему так происходит?
Язык JavaScript был не слишком удачно спроектирован, или же
0 : Поскольку существует только одна глобальная область види­ люди не знают, что делают, или причина в чем-то еще? И как
мости, каждый файл, который вы загружаете, будет видеть один нам быть в данной ситуации?
и тот же набор переменных (и генерировать глобальные перемен­
ные в одном и том же пространстве). Вот почему так важно быть
0 : Глобальные переменные часто с излишком используются
внимательным при использовании переменных — это позволит
в JavaScript. Отчасти причина этого заключается в том, что язык
избежать конфликтов (кроме того, необходимо стараться снизить
JavaScript позволяет легко освоиться и начать писать код, и это
количество или вообще убрать глобальные переменные, если это
хорошо, поскольку JavaScript не навязывает вам массу всяких
представляется возможным).
структур и прочей нагрузки. Недостатки начнут проявляться при
написании серьезного кода, который будет претерпевать измене­
^ 3 * Мне доводилось видеть код, в котором не используется ния и нуждаться в сопровождении в течение длительного времени
ключевое слово var при присваивании значения имени новой (что в большой степени характеризует все веб-страницы). Следует
переменной. Как такое возможно? отметить, что JavaScript является мощным языком и включает
различные возможности, например объекты, которые вы можете
0 : Да, так можно поступать; когда вы присваиваете значение использовать для организации своего кода модульным образом.
имени переменной, которая ранее не была объявлена, она будет На эту тему написано много книг, а «попробовать на вкус» объекты
рассматриваться как новая глобальная переменная. Поэтому вы сможете во второй части этой главы (до нее осталось всего
будьте осторожны, если делаете это внутри функции, в которой несколько страниц).

дальше ► 161
функции как значения

Функции еще являются и значениями


И т а к , м ы с ва м и и с п о л ь зо в а л и п е р е м е п п ы е для р а зм е щ е п и я ч и с л о в ы х и л о г и ч е с к и х
з п а ч е п и й , с т р о к , м а сси в о в и в с е го п р о ч е г о , п о у п о м я п у л и л и м ы о т о м , ч т о в ы т а к ж е
м о ж е т е п р и с в а и в а т ь ф у п к ц и ю п е р е м е п п о й ? В з гл я п и т е п а с л е д у ю щ и й п р и м е р :

Определим простую функцию, которая


function addOne(num) 1 ^ прибавляет 1 к своему аргументу.
return num + 1;
Теперь сделаем кое-что новенькое. Мы воспользу-
}
емся именем функции addOne и присвоим addOne
Г новой переменной plusOne.
var plusOne = addOne;
Обратите внимание , что мы не вызываем
функцию посредством addOneQ, а просто
указываем имя функции.
var result = plusOne(l);

ч
После выполнения
plusOne присваивается функции , поэтому
мы сможем вызывать ее с использованием
Целочисленного аргумента в виде г
данного вызова result
будет равен 2.

Ч т о ж е , р а п е е м ы п е т о л ь к о за б ы л и у п о м я п у т ь об э т о й п е б о л ы н о й де та л и , к а с а ю щ е й ­
ся ф у п к ц и й , п о т а к ж е п е со все м б ы л и ч е с т п ы , к о гд а р а с с ка зы в а л и вам об а п а т о м и и
ф у п к ц и и , — о ка зы в а е тс я , вам даж е п е п у ж п о п р и с в а и в а т ь и м я с в о е й ф у п к ц и и . Все
в е р п о : ваш а ф у п к ц и я м о ж е т б ы ть анонимной. Ч т о ж е все э то з п а ч и т и за ч е м вам м о ­
ж е т п о т р е б о в а т ь с я п о с т у п и т ь так? Д а в а й те сп а ча л а п о с м о т р и м , к а к созд ать ф у п к ц и ю
без и м е п и :

Здесь мы создаем функцию , не указывая при этом


function (num) { ^ имени... Хм... Но как же мы тогда сможем сделать
что-нибудь при помощи нее?
return num + 1;
Давайте сделаем это снова и на этот
r ~ раз присвоим ее переменной.

var f = f u n c t io n (n u m ) {
r e t u r n num + 1 ; А затем мы сможем
•» ^ использовать нашу
* L переменную_ для
. - вызова
п .-.~

v a r r e s u lt = f (1);
функции
a le r t(r e s u lt); ^

После выполнения данного


вызова result будет равен 2.

162 глава 4
функции и объекты javascript

М 9 *Г 9 ? 9 Й
Ш ТУРМ Все это должно быть
для вас немного более
Взгляните на данный код: как вы думаете, что он делает? понятным, учит ы ­
вая то, что мы сейчас
var element = document.getElementByld ("button" ) ; с вами рассмотрели...
element.onclick = function () {
alert("clicked!"); к Не беспокойтесь, если вы так и не с м о -
} жете на ZOO % во всем здесь разобраться,
поскольку мы еще дойдем до этого...

Что моЖно сделать посредством функций как значений?


Т а к в ч е м ж е здесь в а ж п о с ть ? В ч е м польза? В а ж п о с т ь з а к л ю ч а е тс я п е с т о л ь к о в т о м , ч т о м ы м о ж е м п р и ­
сва и ва ть ф у п к ц и ю п е р е м е п п о й , с к о л ь к о в т о м , ч т о э то п а ш с п о с о б п о ка з а т ь вам, ч т о ф у п к ц и я действи­
тельно является значением. А в ы у ж е зп а е те , ч т о м о ж е т е с о х р а п я т ь з п а ч е п и я в п е р е м е п п ы х и л и м а сси ва х,
пер е д а ва ть и х в ка ч е с т в е а р гу м е п т о в ф у п к ц и я м и л и , к а к м ы в с к о р е у в и д и м , п р и с в а и в а т ь и х с в о й с т в а м
о б ъ е кт о в . О д п а к о в м е с то т о г о , ч т о б ы р а с с ка зы в а т ь ва м о п о л е з п о с т и а п о п и м п ы х ф у п к ц и й , п р о с т о
в згл я п е м п а о д и п и з м п о ж е с т в а л ю б о п ы т п ы х с п о с о б о в и с п о л ь з о в а н и я ф у п к ц и й к а к з п а ч е п и й :

Вот простая функция init


function init() {
Здесь мы присваиваем определенную нами
alert("you rule!") \load.
функцию обработчику событии onl,
}
window.onload = init; Посмотрите-ка, мы уже исполь­
зовали функции как значения!

Л и б о м ы м о ж е м п о с т у п и т ь ещ е и п т е р е с п е е :
ству window.onload.
Не беспокойтесь, если
window.onload = function() {
window.onload кажется
alert("you rule!"); вам несколько непонятным,
} ^ Красота! Разве это поскольку позже мы под-
не проще и удобнее < Q Q н ш поговорим,
для чтения?

К а к в ы уж е п а ч а л и п о п и м а т ь , ф у п к ц и и п о з в о л я ю т делать к о е -ч т о п о л е зп о е п о м и м о п р о с т о й « у п а ко в ки »
ко д а для п о в т о р п о г о и с п о л ь з о в а п и я . Ч т о б ы л у ч ш е р а з о б р а ть с я в т о м , к а к п о л п о с т ь ю за д е й с тв о в а ть все
п р е и м у щ е с тв а ф у п к ц и й , д а в а й те в згл я п е м п а о б ъ е к т ы и п о с м о т р и м , к а к о п и в п и с ы в а ю т с я в J a v a S crip t,
п о с л е ч е го о б ъ е д и п и м и х в е д и п ы й м е х а п и зм .

дальше ► 163
зажигательная речь

Эй, авторы! Еще раз привет!


Я девушка, которая купила вашу кни­
гу о программировании на HTM L5,
помните меня? Какое все это имеет
отношение к HTML5?

Мы полагали, что уже ответили на этот


вопрос... н о если вам к а ж е т с я , будто м ы
п о д о б р а л и вас и у ж е п о л д о р о г и п р о в е з л и
о к о л ь н ы м и п у т я м и п о го р о д у с в к л ю ч е н н ы м
с ч е т ч и к о м (в то в р е м я к а к м о гл и бы п о п р я ­
м о й о т в е з т и в ц е н т р го р о д а ), ч т о ж , то гд а
в с п о м н и т е о то м , ч т о в следующей главе м ы со­
б и р а е м с я н а ч а ть и з у ч е н и е A P I-и н т е р ф е й с о в ,
р а б о т а ю щ и х с H T M L 5 . А ч т о б ы сделать э то ,
вам п о т р е б у е т с я действительно хорошо разби­
раться, в ф у н к ц и я х , о б ъ е к т а х и п р о ч и х свя-
з а п п ы х с н и м и а с п е кта х .

Так ч то п о те р п и те — ф а кти ч е с ки , вы уж е
п р о ш л и п о л о в и н у п у т и ! И не за б ы в а й те , ч т о
в д а п н о й главе в ы п р е в р а т и т е с ь и з п и с а те л я
с ц е п а р и е в в п р о гр а м м и с т а , и з H T M L /C S S -
п а е з д н и к а в т о г о , к т о с п о с о б е н создавать
с е р ь е зн ы е п р и л о ж е н и я .

L А мы уже упоминали о т о м ,
что все это также может
позволить вам заработать
намного больше денег?

164 глава 4
функции и объекты javascript

Благодаря объектам N
будущие перспективы выглядят
настолько яркими, что нам действи­
тельно НЕ ОБОЙТИСЬ без солнцеза­
щитных очков...

Kmo-mo сказал «объекты»?!


О , э то н а ш а л ю б и м а я те м а ! О б ъ е к т ы н е р е н е с у т в а ш и н а в ы к и
в J a v a S c rip t-н р о гр а м м и р о в а н и и н а с л е д у ю щ и й у р о в е н ь — о н и вы -
с т у н а ю т к л ю ч о м к у н р а в л е н и ю с л о ж н ы м к о д о м , к н о н и м а н и ю об ъ ­
е к т н о й м о д е л и д о ку м е н т а (D O M ) , к о р га н и з а ц и и в а ш и х д а н н ы х и
да ж е я в л я ю т с я о с н о в н ы м с н о с о б о м « у н а ко в ки » A P I-и н т е р ф е й с о в
J a v a S c rip t в H T M L 5 (д а н н ы й с н и с о к м о ж н о н р о д о л ж а т ь !). С у ч е ­
т о м э т о го вам н о ка з а л о с ь , ч т о о б ъ е к т ы — с л о ж н а я тем а, н е т а к ли?
Х а ! М ы с в а м и н р о с т о б р о с и м с я сл о м я го л о в у в н е р е д и не за м е д л и ­
те л ь н о н е р е й д е м к и х и с н о л ь з о в а н и ю .

Раскроем вам секрет JavaScript-объектов: о н и н р е д с т а в л я ю т с о б о й все­


го л и ш ь к о л л е к ц и и с в о й с т в . Д а в а й те в ка ч е с т в е н р и м е р а в о зьм е м ,
с ка ж е м , собаку. С о б а ка обладает р я д о м с в о й с т в :

У большинства собак есть


клички (пате), как , например ,
идо (Fido) в данном случае.

£ -------- Каждая собака имеет


определенный вес (weight).

У всех собак есть набор люби­


мых занятий , например гулять
(walks) и приносить обратно
брошенный мячик (fetching balls). И относится к определен­
ной породе. В данном случае
К -
у фидо (Fido) смешанная
(mixed) порода (breed).
Собака (dog)

дальше ► 165
объекты и свойства

Размышления о свойствах...
Е с те с тв е н н о , н а ш не с F id o , е сли б ы м о г го в о р и т ь , сразу ж е о т м е т и л б ы , ч т о у н е го
и м е е т с я н а м н о го б о льш е с в о й с т в , ч е м м ы н е р е ч и с л и л и в ы ш е , о д н а ко в д а н н о м
н р и м е р е и м е н н о и х м ы и о т р а з и м в н р о г р а м м н о м ко д е . Д а в а й те в згл я н е м н а э т и
с в о й с т в а с т о ч к и з р е н и я т и н о в д а н н ы х Ja v a S c rip t:

Набор свойств Строки, представля­


ющие кличку и породу
нашей собаки.
name: "Fido"

К а к вы догадались, у нас weight: 40 <; 3 качестве значения


будет объект, пред­ веса у нас будет
ставляющий собаку. целое число.
breed: "M ixed"

loves: ["walks”, "fetching balls”]

8 массиве строк мы собираем значения


свойства loves объекта dog, при этом
значений может быть ноль и больше;
здесь у нас два значения, которые олице­
творяют любимые занятия Fido.
Как создать объект на JavaScript?
И т а к , у нас е сть о б ъ е к т с р я д о м с в о й с т в . А к а к о н со зд а е тся
с и с п о л ь з о в а н и е м JavaS cript? В о т к а к :
Обратите внимание,
Начинаться объект должен
Мы присвоим наш объ- ^ отКрывающейся фигурной скоб- что каждое свойство
ект переменной fido. ^ после которой следуют все отделяется запятой.
свойства, находящиеся внутри. НЕ точкой с запятой!

var fido = { Нам объект обладает четырьмя свой­


ствами : name, weight, breed и loves.
паше: 11Fido11,
weight: 40,
Обратите внимание, что значение
breed: "Mixed11, weight является числом ( 40 ), а зна­
чения breed и пате — строками.
loves: ["walks11 "fetching balls"]

И конечно же, у нас имеется массив для р а з ­


мещения значений свойства loves объекта dog.

166 глава 4
функции и объекты javascript

моЖно сделать с объектами


Обращение к свойствам объекта с помощью «точечной» нотации:

h ------------ И с п о л ь з у й т е т о ч ку (.)
if (fido.weight > 25)
alert ("WOOF") ;
И спользуйт е объект н а ­
I
ряду с т очко й и и м е н е м £ id o .w e ig h t ^
} else { свойст ва для п о л у ч е ­ ... а в о т и м я
ния д о с т у п а к значению В о т объект.. свойства.
alert ("yip") ;
эт ого свойства.
}

На э т о т р а з з а к л ю ­
Обращение к свойствам с использованием строки
ч и т е и м я свойст ва
и скобочной нотации: в квадрат ны е скобки.

var breed = fido ["breed" ] , И спользуйт е объ­


f id o [ " w e ig h t" ]
if (breed == "mixed")
alert("Best in show");
{ е к т наряду с и м е н е м
с в о й с т в а , за к л ю ч е н н ы м С t
В о т о б ъ е к т ............. а в о т и м я
в кавы чкиj и к в а д р а т ­
ные скобки для п о л у ­ свойст ва в к а ­
чения дос т у п а к з н а ч е ­ вычках.
нию эт ого свойства. Мы с ч и т а е м , чт о
Изменение значения свойства: т очечная нот а ц и я
более у д о б о ч и т а е м а ,
Mw и зм ен я ем значение свойст ва
чем скобочная.
fido.weight = 27; ^ w e ig h t об ъ е кт а fido...
fido.breed = "Chawalla/Great Dane mix"; ■■■ Значение его свойст ва breed...
fido. loves, push ("chewing bones") ; <£__ ••• и добавляем новый э л е м е н т в его
А м ассив loves.
^ push п р о с т о добавляет новый
э л е м е н т в конец массива.
^ — « П ер ечи сли т ь» означает п р о й -
ТТеречиспение всех свойств объекта: т и с ь по в с е м с в о й с т в а м о б ъ е к т а

Д л я перечи слени я свойст в мы и с п о л ь з у е м ц икл for in


var prop;
^ --------------------------------- При каждом вы полнении цикла
for (prop in fido) { ^
п е р е м е н н а я p rop п о л у ч а е т с т р о ­
alert ("Fido has a " + prop + property "); ковое значение следую щ его по
if (prop == "name") { очереди им ени свойства.
alert("This is " + fido[prop]);
Мы и с п о л ь з у е м скобочную н о т а ц и ю
^ О б р а т и т е в н и м а н и е '. п о р я д о к с в о й с т в для по луч ения д о с т у п а к значению
} п р о и з в о л ь н ы й , т а к ч т о не с т о и т с о о т в е т с т в у ю щ е г о свойства.
р а с с ч и т ы в а т ь на к а к у ю - т о о п р е д е ­
ленную последоват ельност ь.

дальше ► 167
что могут объекты

Q Действия в отношении массива объекта:


4 Здесь мы п р и с ва ива ем значение м ассива
var likes = fido.loves; loves о б ъ е кт а fido п е р ем енно й likes.
var likesString = "Fido likes";

for (var i = 0; i < likes.ltr^th; ± + + ) ^ 4 М О Ж е М вы п о л н и т ь цикл в о т -


ношении массива likes и создат ь
^ likesString += •• - + likes [i] ; ^ gcey л ю 6иМШ з а н я т и и fido.

alert (likesString); ^ т л к ж е мо>кем вы вест и диалоговое


окно a le rt с с о о т в е т с т в у ю щ е й ст рокой.

Передача объекта функции:


--■----------V. М ы м о ж е м п е р е д а т ь объ-
function bark (dog) { е к т функции т о ч н о т а к
же, как в случае с людои
if (dog.weight > 25) {
другой перем енной.
alert ("WOOF") ;
} else { 3 ф у нкци и м ы мож ем
alert("yip") п о л у ч и т ь д о с т у п к с во й ­
с т в а м о б ъект а как обычно,
}
и с п о л ь з уя j конечно ж е , им я
} п а р а м е т р а для объекта.

b a r k ( f i d o ) T >N^ Мы п ередаем fido в качест ве


а р г у м е н т а ф у нкции b a r k , к о ­
т о р а я ожидает о б ъ е к т dog.

Оператор «точка» (.)

Оператор «точка» (.) обеспечивает доступ к свойствам объ­


екта. В целом код получается более удобочитаемым, чем при
использовании скобочной нотации (["строка"]):

• fido . w e i g h t ЭТО вес fido.


• f i d o . b r e e d ЭТО порода fido.
• f i d o . паше ЭТО КЛИЧКЭ fido.
• f i d o . l o v e s это массив, содержащий значения, олицетво­
ряющие любимые занятия fido.

168 глава 4
функции и объекты javascript

А можно ли добавлять свой­


ства в объекты после того,
как они уже были определены?

Да, вы сможете добавлять и удалять свойства


в любой момент.
Ч т о б ы д о б а в и ть с в о й с т в о в о б ъ е кт, н у ж н о н р о с т о н р и -
с в о и т ь н о в о м у с в о й с т в у зн а ч е н и е , к а к н о к а з а н о далее:
f i d o . age = 5 ;

по сл е ч е го у fid o п о я в и т с я н о в о е с в о й с т в о : аде.

А ч т о б ы удал ить с в о й с т в о , н у ж н о в о с п о л ь з о в а ть с я к л ю ­
ч е в ы м сл о в о м delete:
d e le te f i d o . a g e ;

П р и уд а л е н и и с в о й с т в а в ы удаляете н е н р о с т о е го зн а ч е ­
н и е , а само э то с в о й с т в о . Ф а к т и ч е с к и , если в ы з а х о т и т е
в о с п о л ь з о в а ть с я f i d o . аде но сл е т о г о , к а к уд а л ил и е го ,
то о н о будет о ц е н е н о к а к u n d e fin e d .

В ы р а ж е н и е d e le t e в о зв р а щ а е т t r u e , е сли с в о й с т в о
б ы л о у с н е ш н о удалено (л и б о е сли в ы удаляете с в о й с т в о ,
к о т о р о е н е сущ ествует, л и б о если т о , ч т о в ы н ы т а е те с ь
уда л ить, н е я в л я е тс я с в о й с т в о м о б ъ е кта ).

дальше ► 169
объекты как аргументы

Поговорим о передаче объектов функциям


М ы с в а м и у ж е н е м н о го о б суж д а л и т о , к а к а р гу м е н т ы н е р е д а ю тс я ф у н к ­
ц и я м , — о н и н е р е д а ю тс я по значению , т а к ч т о е сли м ы не р е д а д и м ц елое
ч и с л о , с о о т в е т с т в у ю щ и й н а р а м е т р ф у н к ц и и н о л у ч и т копию д а н н о го
ц е л о ч и с л е н н о го значения для и с п о л ь з о в а н и я в ф у н к ц и и . А н а л о г и ч н ы е
н р а в и л а д е й с т в у ю т и в случае с о б ъ е кта м и , однако н а м н у ж н о более н р и -
ста л ь н о в згл я н у ть н а то , ч т о будет с о д е р ж а т ь с я в н е р е м е н н о й , к о гд а о н а
н р и с в а и в а е т с я объ екту, ч т о б ы в ы с м о гл и н о н я т ь , ч т о все э то о зн а ча е т.

К о гд а о б ъ е к т н р и с в а и в а е т с я н е р е м е н н о й , о н а будет с о д е р ж а т ь н е сам
э т о т о б ъ е кт, а ссылку н а н е го . С ч и т а й т е с с ы л ку у ка за те л е м н а о б ъ е кт.

fid o name: "Fido"

weight: 40

Когда объект присваивается breed: "M ixed"


переменной, она наделяется
ссылкой на этот объект. loves: ["walks", "fetching balls"]
Переменная не будет «содер­
ж а т ь » сам объект.

Т а к и м о б р а зо м , н р и в ы зо в е ф у н к ц и и и пе р ед а че е й о б ъ е кта в ы будете
н ер е д а ва ть с с ы л ку н а о б ъ е к т — не сам о б ъ е кт, а т о л ь к о ука за те л ь на не го ,
К о н и я с с ы л к и п е р е д а е тс я в н а р а м е т р , п р и э т о м у ка зы в а т ь о н а будет на
о р и г и н а л ь н ы й о б ъ е кт.

Если вы вызовем функцию


bark и передадим ей fido
в качестве аргумента ,
то получим копию ссылки
на объект dog. ?
f u n c t i o n b a r k (d o g ) {
... code here ...
}

Т а к ч т о ж е все э то о значает? П р и и з м е н е н и и с в о й с т в а о б ъ е кта в ы и з м е ­


н я е те д а н н о е с в о й с т в о в о р и г и н а л ь н о м о б ъ е кте , а н е в к о н и и , н о э т о м у
у в и д и т е все в н е с е н н ы е в а м и и з м е н е н и я в о б ъ е к т в н у т р и и в н е в а ш е й
ф у н к ц и и . Д а в а й те р а с с м о т р и м н р и м е р , где в случае с dog и с н о л ь з у е тс я
ф у н к ц и я l o s e W e i g h t .. .

170 глава 4
функции и объекты javascript

СаЖаем Fido на guemy...


Д а в а й те в згл я н е м н а т о , ч т о н р о и с х о д и т , к о гд а м ы нер е д а е м
сД еной с
f i d o ф у н к ц и и l o s e W e ig h t и и з м е н я е м с в о й с т в о d o g . w e i g h t .

Мы определили объект f i d o и передаем его


функции lo s e W e ig h t .

fido — это ссылка на объект, то есть


соответствующий объект не рас­
полагается в_ переменной fidoj однако name: "Fido"
эта переменная на него указывает.
weight: 48

— breed: "Mixed"

У loves: ["walks", "fetching balls"]


fido.weight = 48;

loseWeight(fido) При передаче fido


функции мы передаем
ссылку на объект.

( 2 \ Параметр d o g функции l o s e W e ig h t получает ко-


пию ссылки на f i d o . Таким образом, любые из­
менения в свойствах параметра будут отражаться
на переданном объекте.

Когда мы передаем fido функции


Ссылка dog
loseWeight, параметру dog п р и ­ это копия
сваивается копия ссылки, а не копия ссылки fido
объекта. Так что fido и dog будут
указывать на один и тот же объект.

function loseWeight(dog) {
dog.weight = dog.weight 10; e Такимобразом , при вычитании
НО фунтов* из dog.weight мы
изменяем значение fido.weight.

alert(fido.паше + " now weighs " + fido.weight);

10 ф у н то в ® 4,5 4 кг.

дальше ► 171
приложение webville cinema

ПРИЛОЖЕНИЕ WEBVILLE CINEMA ДЛЯ ПОКАЗА АФИШИ КИНОТЕАТРА

Здесь речь пойдет о приложении Webville Cinema и API-


интерфейсах JavaScript; вам нужно будет создать объекты
m ovie. Всего вам потребуются два таких объекта, каждый
ИЗ КОТОРЫХ будет ВКЛЮЧаТЬ название ( t i t l e ) , Жанр (genre)

и рейтинг фильма ( r a t i n g ) (выставляемый по шкале от


1 до 5 звездочек), а также время киносеансов (show tim es).
Вот образцы данных, которые вы сможете использовать
для заполнения своих объектов.

Название фильма: Plan 9 from Outer Space.


Время киносеансов: 3:00pm, 7:00pm and 11:00pm.

Жанр: Cult Classic.

Рейтинг в звездочках: 2.

Название фильма: Forbidden Planet.

Время киносеансов: 5:00pm и 9:00pm.

Жанр: Classic Sci-fi.

Рейтинг в звездочках: 5.

Г Р еш е н и е к д а н н о м у з а д а н и ю V - 8*' моЖете св°* °дН0 ^ Ц Т в а м


н а х о д и т с я на с л е д у ю щ е й с т р а - ЭГ “ Р
н и ц е , о д н а к о не з а г л я д ы в а й т е 6 о льШ е н Р а в я т с я
т у д а , п о к а не с д е л а е т е все
с а м и . С е рь езн о. Mt?/ не ш у т и м .

Код для создания ваших


об ъект ов н а п и ш и т е здесь.
■ж

172 глава 4
функции и объекты javascript

ПРИЛОЖЕНИЕ WEBYILLE CINEMA ДЛЯ ПОКАЗА АФИШИ КИНОТЕАТРА---------


РЕШЕНИЕ
Ну как у вас прошло создание объектов movie?

А вот наше решение к данному заданию:

m o v i e l обладает ч е т ы р ь м я с в о й с т в а м и :
M bi создали два
о б ъ е кт а с и м е ­ title , g e n r e , ra tin g и show tim es.
нам и moviel-
и m o vieZ для var moviel = { Значения title и g e n r e явля-
двух ф и льм ов. title: "Plan 9 from Outer Space"
ю т е я строками.

genre: "Cult Classic", Значение rating —


rating: 5, э т о число.
showtim.es: ["3:00pm", "7:00рт", "11:0 Орт"]
};
^ A s k o w tim e s п ред с т а вля е м , собой м ас с и в, содержа­
щ и й значения вр ем ени сеансов ф и л ь м а в виде ст рок.

свои -
у m o v i e z тоже и м е ю т с я ч е т ы р е
var тоvie2 = { ства: title, g e n re , rating и sho w tim es.

title: "Forbidden Planet",


genre: "Classic Sci-fi", He с л е д у е т з а б ы в а т ь ,
rating: 5, ч т о свойст ва необходимо
р а з д е л я т ь за п я т ы м и .
showtimes: ["5:00pm", "9:00pm"]
};

Мы использовали т е ж е самые
им ена с в о й с т в , как и в случае
с m o v i e l , но значения с во йст в
на э т о т раз б уд у т уже другие.

дальше ► 173
внедрение следующего сеанса

Наш следующий сеанс состоится в...


Итак, мы с вами уже немного отведали на вкус, что значит смешивать объек­
ты и функции. Давайте нойдем еще дальше и нанишем код, который станет
выводить сообщение о времени следующего сеанса фильма. Наша функция
будет нринимать movie в качестве аргумента и возвращать строку, содержа­
щую значение времени следующего сеанса фильма, отталкиваясь нри этом
от значения текущего времени. Л Л
М ы и звл е ка е м значение т е к у щ е го в р е м е н и с п о м о щ ь ю
В о т наила новая ф у н к ц и я , п р и ­
J a v a S c r i p t - о б ъ е к т а Date. Не б еспокойт есь о д е т а -
н и м а ю щ а я о б ъ е к т movie.
лях - п р о с т о з н а й т е , ч т о он в о з в р а щ а е т зн а ч е н и е
т е к у щ е г о врем ени в м и л л и с е к у н д а х .
Теп ер ь мы з а д е й с т в у е м м ассив s k o w t i m e s о б ъ -
function getNextShowing(movie)
var now = new Date().getTime();
{
j е к т а m o v ie и со ве р ш а е м и т е р а ц и и по нему.
I В случае с каждым з н а ч е н и -
▼ ем s k o w tim e s мы и звл е ка е м
for (var i = 0; i < movie.showtimes .length; i++) { Л n
^ ^ значение т е к у щ е го врем ени
var showtime = ge tTimeFromSt ring (movie.show times [i]) ; g миллисекундах, а зат ем
if ((showtime - now) > 0) { пр оводим сравнение.
return "Next showing of " + movie.title + " is " + movie.show times [i] ;

|^_ Если вр е м я еще не н а с т у п и л о , т о э т о значение в р е м е ­


}
ни следую щ его сеанса , п о э т о м у оно и возвращ ает ся.
return null;
Если сеансов больше не о с т а ­
е т с я , м ы во звр ащ а ем null.
j^oijloBo

к уно^е^леншо
function getTimeFromString( time String) {
var theTime = new D a t e ();
В о т п р и го т о вл е н н ы й
var time = timeString.match(/(\d+)(?:: (\d\d))?\s*(p?) /);
нам и кодj ко т о р ы й п р о ­
theTime.setHours( parselnt(time[1]) + (time[3] ? 12 : 0) )
ст о б е р е т с т р о к у ф о р ­
theTime.setMinutes( parseInt(time[2]) II 0 ) ; м а т а , например l a m
return theTime.getTime() ; или Ърт> и п р е о б р а з у е т
} ее в значение вр ем ени
в м и ллисекунда х.
He беспокойт есь насчет данного кода; в нем и с п о л ь з у ю т с я
р е гу ля р н ы е выражения , о ко т о р ы х вы у з н а е т е по ходу и з у ч е ­
ния Ja vaS cript. А пока п р о с т о в зг л я н и т е на них!

var nextShowing = getNext Showing (moviel) ; Г Х Здесь МЫ вызываем ф у н к ц и ю g e t N e x tS h o w in g


alert (nextshowing) ; и и с п о л ь з у е м с т р о к у , к о т о р у ю она возвраща-
next Showing = getNext Showing (movie2) ; отображения в диалоговом окне alert.
alert(nextshowing); )
И де ла ем т о же сам ое в случае с movieZ.

174 глава 4
функции и объекты javascript

К а к р а б о т а е т «объединение в д е п о чку » _________________________________

В ы о б р а т и л и в н и м а н и е н а д а н н у ю с т р о к у в н р е д ы д у щ е м коде?

movie.showtimes.length

Э та с т р о к а н е н о х о ж а н и н а ч т о и з т о г о , ч т о н а м д о в о д и л о с ь в и д е ть р а н ь ш е .
О н а нр е д с та в л я е т с о б о й с о к р а щ е н н ы й в а р и а н т с е р и и ш а го в , к о т о р ы е н а м п о ­
тр е б о в а л о с ь б ы в ы н о л н и т ь , ч т о б ы и з в л е ч ь д л и н у м а сси в а s h o w tim e s и з об ъ ­
е к т а m o v ie . В м е сто нее н а м н р и ш л о с ь б ы н а н и с а т ь следую щ ее:

— Сначала мы извлекаем
ллассив showtim es.
var showtimes Array = movie.showtimes; ^
var len = show timesArray, length; ^ ____ Затем МЫ используем его
для доступа к свойству length.
О д н а к о м ы м о ж е м делать все э то за о д и н н о д х о д н у т е м о б ъ е д и н е ­
н и я в ы р а ж е н и й в ц е н о ч к у . Д а в а й те н о с м о т р и м , к а к э то р а б о та е т:

movie.showtimes.length
А ^ t ^
ЧЭОценива - ...который и м е - ...который
ется как ет свойство имеет свой -
объект showtimes , что яв - ство с им е -
movie... ляется массивом... нем length.

Tecm-драйб
Н а н е ч а т а й т е к о д с н р е д ы д у щ е й с т р а н и ц ы и н р о в е д и т е е го те ст-д р а й в . В ы у в и д и те , ч т о ф у н к ц и я
g e tN e x tS h o w in g н р и н и м а е т о б ъ е к т m o v ie и в о зв р а щ а е т с т р о к у со з н а ч е н и е м с л е д ую щ е го сеанса
с о о т в е т с т в у ю щ е го ф ильм а. В ы т а к ж е м о ж е т е с в о б о д н о созд авать с о б с т в е н н ы е н о в ы е о б ъ е к т ы
и н р о в о д и т ь те ст-д р а й в с и х уч а с ти е м . М ы т а к и н о с т у н и л и , н р и э т о м м е с тн о е в р е м я б ы л о 12:30.

var banzaiMovie = {
h« PV/focalhost
title: "Buckaroo Banzai",
Next showing of Buckaroo в а л а ! is j
■00pm
genre: "Cult classic",
rating: 5,
showtimes: ["1:0 0pm" , "5:0 0pm" , "7:0 0pm" ]

'jV
С
Примечание: качество нашего кода явля
J ется не совсем т а к и м , как у « производ -
var next Showing = getNextShowing (banzaiMovie) ; ственного кода»; если вы выполните его
alert (nextshowing); после наступления времени последнего
киносеанса , то получите значение null.
Повторите попытку на следующий день>.\&

дальше ► 175
объекты и методы

Объекты такЖе м огут обладать поведением...


В ы ж е н е дум али, ч т о о б ъ е к т ы го д я т с я т о л ь к о для с о х р а н е н и я ч и с е л ,
с т р о к и м ассивов? О б ъ е к т ы а к т и в н ы — о н и м о гу т делать о п р е д е л е н н ы е
в е щ и . С о б а ки , к н р и м е р у , н е с и д я т н а м е сте : о н и л а ю т, б е га ю т, и г р а ю т
Когда объект
в м я ч , и н а ш о б ъ е к т d o g т о ж е д о л ж е н в е с т и себя н о д о б н ы м о б р а зо м !
П р и н и м а я во в н и м а н и е все и з у ч е н н о е в э т о й главе, в ы н о л н о с т ь ю г о т о в ы включает
к тому, ч т о б ы с н а б д и ть с в о и о б ъ е к т ы н о в е д е н и е м . В о т к а к э то делается:

var fido = { в себя


паше: "Fido11,
weight: 40, функцию,
breed: "Mixed11,
loves: ["walks", "fetching balls"] мы говорим,
bark: function() {
alert("Woof woof!") Мы м о ж е м добавить что даииый
} функцию напрямую в наш

}; i К
объект, как показано здесь. объект
Вместо того чтобы гово- Обратите внимание , что
ритъ, что это «функция “ с™ л»зуем анонимную включает
в объекте » , мы просто гово- и присваиваем ее
рым , ч т о это метод. М ежду
ними нет никакой разницы,
^ о и с ^ в у bark объекта,
в себя метод.
однако функции в объектах
все называют методами.

Д л я в ы зо в а м ето д а в о т н о ш е н и и о б ъ е кта следует у ка за ть и м я д а н н о го


о б ъ е кт а н а р я д у с и м е н е м м е то д а , и с н о л ь з у я т о ч е ч н у ю н о т а ц и ю , а т а к ж е
все н е о б х о д и м ы е а р гу м е н т ы .

f i d o .b a r k () ;
Мы говорим объекту сделать
чт о-т о, вызывая его методы.
3 данном случае мы вызываем
метод bark объекта fido.

176 глава 4
функции и объекты javascript

Возвращаемся к приложению Webville Cinema...


Т е н е р ь, к о гд а в а ш и з н а н и я об о б ъ е кт а х р а с ш и р и л и с ь , м ы м о ж е м в е р ­
н у т ь с я и у с о в е р ш е н с тв о в а ть к о д н а ш е го н р и л о ж е н и я W e b v ille C in e m a .
М ы у ж е н а н и с а л и ф у н к ц и ю g e t N e x t Showing, н р и н и м а ю щ у ю m ovie в к а ­
ч е ств е а р гу м е н та , о д н а к о вза м е н м о гл и б ы сделать э ту ф у н к ц и ю ч а с т ь ю
о б ъ е кта m ovie, н р е в р а т и в ее в м е то д . Д а в а й те т а к и н о с т у н и м :

var moviel = {
title: "Plan 9 from Outer Space",
M ы взяли наш код и пом ест и­
genre: "Cult Classic",
ли его в метод объекта m o v ie l
rating: 5, с использованием имени свойст\
showtimes: ["3:0 0pm" , "7:0 0pm" , "11:0 0pm" ] getNextShowing.

getNext Showing: function (movie) {


var now = new Date () .getTime () ;

for (var i = 0; i < movie.showtimes.length; i++) {


var showtime = getTimeFromString (movie.showtimes [i]) ;
if ((showtime - now) > 0 ) {
return "Next showing of " + movie.title + " is " + movie.showtimes[i];
}
}
return null;
}

Но мы знаем, что моЖем быть не совсем правы...


Н а сам ом деле м ы н е м о ж е м н р о с т о в б р о с и т ь ф у н к ц и ю в д а н н ы й о б ъ е кт, н о с ко л ь ку
g e t N e x t S h o w in g н р и н и м а е т m ovie в ка ч е с т в е а р гу м е н та . П р и э т о м н а м х о ч е т с я вы -
зы в а т ь g e t N e x t S h o w in g сл е д ую щ и м о б р а зо м : ^ ^ т р е Ш а т ь с я к а к ц е - л и 6о а р г у -
^ м е н т ы , п оско льк у б у д е м вполне ясно, вр ем я
var nextshowing = moviel.getNextShowing () ; следую щ его сеанса какого ф и л ь м а МЫ ХотиМ
и звл е ч ь j т о е с т ь т о г о , ко т о р ы й п р е д с т а в л е н
объект ом m o v ie l.
И т а к , к а к и е ж е и е н р а в л е н и я н а м н е о б х о д и м о вне сти ? Н у ж н о уд а л ить н а р а м е т р m ovie
и з о н р е д е л е н и я м е то д а g e t N e x t S h o w in g , о д н а ко то гд а н а м н р и д е т с я ч т о -т о делать со
все м и с с ы л ка м и н а m o v ie , s h o w tim e s в ко д е , н о с к о л ь к у к а к т о л ь к о м ы удалим н а р а ­
м е тр , m o v ie н е р е с т а н е т с у щ е с тв о в а ть к а к н е р е м е н н а я . Ч т о ж , д а ва й те н о с м о т р и м ...

дальше ► 177
переработка функции как метода

Давайте уберем параметр movie...


М ы н о з в о л и м себе уда л ить н а р а м е т р movie и все с с ы л к и н а н е го .
В резул ьтате у нас н о л у ч и т с я с л е д у ю щ и й ко д :

Внизу мы выделили изменения


var moviel = { n
серым цветом...
title: "Plan 9 from Outer Space", _ n
v See это выглядит вполне сносно, однако
genre: --Cult Classic--, ^ ^ иео$кодиМО пр о д ум а т ь как
rating: 5, метод getNextShowing будет использо
showtimes :["3:00pm", "7:00pm", "11:00pm"], 8amt> свойство skowtimeS--
£
getNextShowing: function () { - HaM пРи$ЫЧны либо локальные
var now = new n . .. . m. ..
Date().getTime(); переменные (но
N showtimes
r к hum
не относится), лиоо глобальные
переменные (к которым showtimes
for (var i = 0 ; i < showtimes.length; i++) { тоже не относится). Хм...
var showtime = getTimeFromString (showtimes [i]) ;
if ((showtime - now) > 0 ) {
return "Next showing of " + title + " is " + showtimes[i];

} } 1
А вот и еще одно
return null; свойство - title.
}
};

U что теперь?
И т а к , в о т в ч е м з а кл ю ч а е тс я го л о в о л о м к а : у нас и м е ю т с я с с ы л к и н а с в о й с т в а showtimes и title. О б ы ч ­
н о в ф у н к ц и и м ы ссы лаем ся н а л о к а л ь н у ю н е р е м е н н у ю , н а гл о б а л ьн у ю н е р е м е н н у ю и л и н а н а р а м е т р
ф у н к ц и и , о д н а ко showtimes и title я в л я ю т с я с в о й с т в а м и о б ъ е кта moviel. В н р о ч е м , м о ж е т все и ср а б о ­
тает... ведь Ja v a S c rip t, к а ж е т с я , д о с т а т о ч н о у м е н для т о г о , ч т о б ы с а м о с то я те л ь н о во всем р а зо б р а ться?

Н е т. Н е сраб отает. М о ж е т е н р о в е с т и те с т-д р а й в , и J a v a S c rip t с о о б щ и т вам, ч т о н е р е м е н н ы е showtimes


и title и м е ю т з н а ч е н и е undefined. К а к т а к о е в о зм о ж н о ?

Д е л о в о т в че м : э т и н е р е м е н н ы е я в л я ю т с я с в о й с т в а м и о б ъ е кта , о д н а ко м ы н е с ка за л и J a v a S c rip t, к а к о г о
и м е н н о о б ъ е кта . В ы м о ж е т е н о д ум а ть: «Ведь о ч е в и д н о ж е , ч т о м ы и м е е м в ви д у Д А Н Н Ы Й о б ъ е кт, в о т
э то т, к о т о р ы й н а х о д и т с я н р я м о здесь! Ч т о т у т м о ж е т б ы т ь н е н о н я т н о го ? » . И , да, м ы п о д р а зум е ваем
св о й с т в а и м е н н о э т о го о б ъ е кта . В J a v a S c rip t п р и с у т с т в у е т к л ю ч е в о е сл о во this, к о т о р о е н о з в о л я е т т о ч ­
н о дать н о н я т ь , ч т о в ы и м е е те в в и д у данный конкретный объект.

Н а сам о м деле с и т у а ц и я н е м н о го более с л о ж н а я , ч е м о н а к а ж е т с я здесь, и об э т о м м ы н о г о в о р и м со всем


с к о р о , а н о к а за й м е м ся д о б а в л е н и е м к л ю ч е в о го слова this, ч т о б ы н а ш к о д р а б о та л к а к надо.

178 глава 4
функции и объекты javascript

Добавление ключевого слова this


Д а в а й те д о б а в и м t h i s в ка ж д о е м е с то , где м ы у ка зы в а е м с в о й с т в о , и те м са м ы м
д а д им н о н я т ь J a v a S c rip t, ч т о и м е е м в ви д у с в о й с т в о данного к о н к р е т н о г о о б ъ е кта :

var moviel = {
title: "Plan 9 from Outer Space",
genre: "Cult Classic",
rating: 5,
showtimes: ["3:00pm", "7:00pm", "11:00pm11], 3dect> МЫ д о бавили к л ю ч е в о е слово
th is п е р е д каж ды м с в о й с т в о м ,
обо зна чив т е м с а м ы м , ч т о и м е е м
getNextShowing: function() {
w T 6 6 иду с с ы л к у на о б ъ е к т m o v i e l .
var now = new Date().getTime();

for (var i = 0; i < this.showtimes.length; i++) {


var showtime = getTimeFromString(this.showtimes[i]);
if ((showtime - now) > 0 ) {
return "Next showing of " + this.title + " is " + this.showtimes[i];
}
}
return null;

Tecm-gpau6 с участием this


Н а б е р и т е н о к а з а н н ы й в ы ш е к о д , а т а к ж е добавьте ф у н к ц и ю g e t N e x t S h o w in g
в с в о й о б ъ е кт m o v i e 2 (н р о с т о с к о н и р у й т е и вставьте ее). З а те м в н е с и т е п р и в е д е н ­
н ы е в н и з у и з м е н е н и я в с в о е й н р е д ы д у щ и й т е с т о в ы й ко д . И н р о в е д и т е те ст-д р а й в !
В о т ч т о н о л у ч и л о с ь у нас: г

httP'/Zfocalhost
Next showing of Plan 9 from Outer Space is 3:00pm

var nextShowing = moviel.getNextShowing () ;


alert(nextShowing); *■ ж )
nextShowing = movie2 .getNextShowing () ;
alert(nextShowing);

V О б р а т и т е в н и м а н и е , ч т о т е п е р ь м ы в ы з ы в а е м 3 etNe^ ho^ 3
В О Т Н О Ш Е Н И И о б ъ е к т а . Т а к более п о н я т н о , н е п р а в д а ли.

дальше ► 179
повт орное использование кода и м ет оды

Похоже, что мы
дублируем один и тот же
код всеми этими копированиями
и вставками /метода getNextShowing.
Разве нет более оптимального
пути?

Верно подмечено.
У вас отличная интуиция, если вы догада­
лись, что код дублируется, когда мы копиру­
ем g e tN e x tS h o w in g в более чем одип объект
m o vie. Одна из целей объектпо-ориептиро-
ванного програм м ирования заклю чается в
максимизации повторпого использования
кода — здесь мы не используем повторпо
код, а ф актически создаем каждый объект
как уникальный, а наши объекты movie по
соглашению (и из-за копировапия и встав­
ки!) в итоге долж ны получаться одинако­
выми. Такой подход пе только является
излиш ней тратой ресурсов, по и мож ет соз­
давать благодатную почву для ошибок.
Существует лучш ий способ сделать это, ис­
пользуя конструктор. Ч то такое копструк-
тор? Это специальпая фупкция, которую
мы с вами папиш ем и которая сможет
создавать объекты и делать их все одина­
ковыми. М ожете считать ее своего рода
пеболы ной ф абрикой, которая припим ает
зпачепия свойств, которы е вы хотите за­
дать в своем объекте, и возвращ ает повы й
объект со всеми пужпыми вам свойствами
и методами.
Д авайте создадим копструктор...

180 глава 4
ф ункции и объект ы ja v a s c rip t

Как создать конструктор


Д авайте создадим копструктор объектов d o g . Мы уже зпаем, как долж пы вы­
глядеть паш и объекты d o g : опи будут иметь свойства nam e, b r e e d и w e i g h t ,
а также вклю чать метод b a r k . Таким образом, пашему копструктору п отре­
буется п рип ять зп ачеп ия свойств в качестве парам етров и возвратить пам
объект d o g , вклю чаю щ ий метод b a r k . Вот пеобходимы й пам код:

ф у н к ц и я - к о н с т р у к т о р во м н о г о м
Параметры конст рукт ора п р и н и ­
схожа с обычной ф у н к ц и е й . О д н а к о м а ю т значения свойств, которыми
по с о г л а ш е н и ю ее и м я должно н а ­ должен обладать наш объект.
ч и н а т ь с я с п р о п и с н о й буквы.

fu n c tio n
Л D o g (п а ш е , b r e e d , w e ig h t) {
Здесь мы инициализируем
свойства объекта значениями,
t h i s , nam e = пате; ~ переданными к о н ст р ук т о р у.
t h is , b re e d = b re e d ;

Имена свойств Мы можем вклю чит ь м ет од


th is . w e ig h t = w e ig h t;
и имена п а р а ­ bark в конст руируемы й объект
м е т р о в необяза­ th is .b a r k = f u n c t i o n () { п у т е м инициализации свойства
тельно должны bark значением функции точно
i f ( th is .w e ig h t > 25) { м а к жел как делали раньше.
быть одинако­
выми, однако a l e r t ( t h i s .п а ш е + " says W o o f! " )

зачастую они } e ls e { Нам необходимо использовать


оказываются this.weight и this.name в методе
a l e r t ( t h i s . nam e + says Y ip ! ")
таковыми — для ссылки на свойства в объек­
о п я т ь -т а к и , } те т ак же, как и раньше.
по соглашению.
);
)
О бра т ит е внимание, насколько данный синтаксис
отличается о т синтаксиса объект а. Это операторы,
поэт ом у каждый из них должен заканчиваться точкой
с запят ой (как это обычно бывает в функции).

П ройдем ся по коду еще раз, чтобы убедиться в том, что вы во всем разобра­
лись. D og —это фупкция-копструктор, припимаю щ ая пабор аргумептов, ко­
торы е являю тся пачальпы ми зпачепиям и пеобходимых пам свойств: nam e,
b r e e d и w e i g h t . Получив эти зпачепия, копструктор п рисваивает свойства,
используя клю чевое слово t h i s . O n также определяет паш метод b a r k .
И каков же результат всего этого? К опструктор D og возвращ ает повы й объ­
ект. Д авайте посмотрим, как ф актически использовать копструктор.

дальш е ► 181
использование конст рукт ора

Вам не нужно бес­


покоиться о создании всех
этих объектов, поскольку мы
сделаем это за вас.

Воспользуемся нашим конструктором


Теперь, когда мы п остроили нашу «фабрику», можно
пачипать использовать ее для создания объектов d o g .
Вам потребуется вызы вать функцию-конструктор осо­
бым образом —нутем разм ещ епия ключевого слова new
перед вызовом. Вот ряд примеров:

Д ля создания объекта dog мы


используем ключевое слово new
А за т е м вызываем его подобно
в сочетании с конст руктором. любой другой функции.

var fido = new Dog("Fido", "Mixed", 38);

va r tin y = new D o g ( " T in y " , " C h a w a lla " , 8 );


Мы создаем т ри разных
va r C liffo r d = new D og ( " C lif f o r d " , " B l o o d h o u n d 11, 6 5 );
объекта dog п у т е м п е р е ­
дачи разных аргум ент ов
для конфигурирования каж­
Получив объект ы, мы м о ­
f i d o . b a r k () ; дого из этих объектов.
жем вызывать их методы
tin y .b a r k ( ) ; bark для возврата с о о т ­
вет ст вую щ и х значений.
c liffo r d .b a r k () ;

Д авайте еще раз разберемся, что здесь происходит: мы соз­


даем три разпы х объекта d o g , каждый из которы х будет об­
ладать своими свойствами, для чего используем клю чевое
слово new в сочетапии с рапее создаппым копструктором http://localhost
D og. К опструктор возвращ ает объект d o g , скопфигуриро- ijf Fido says Woof!

ваппы й в соответствии с передаппы м и пами аргументами.


Д алее мы вызы ваем метод b a r k в отпош епии каждого ht(p://laca1ho$t
объекта d o g . О братите впимапие, что мы используем Tiny s*ys V i» r
одип и тот же метод b a r k в случае со всеми объектами
d o g , а при каждом вы зове b a r k клю чевое слово t h i s бу-
дет указывать па объект d o g , в отпош епии которого был http://!ocalh ost
соверш еп вызов. Таким образом, если мы вы зовем ме­ Clifford says Woof!

тод b a r k в отпош епии fido, то в методе b a r k клю чевое


слово t h i s будет указывать па объект f i d o . Давайте
более пристальпо взгляпем па то, как все это работает.

182 глава 4
ф ункции и объект ы ja v a s c rip t

Как на самом деле работает this?


В сякий раз, когда мы помещ аем клю чевое слово t h i s в код метода, опо будет
иптерпретироваться как ссылка па объект, в отпош епии которого был вызвап
даппы й метод. Таким образом, если мы вызовем f i d o . b a r k , то t h i s будет
указывать па f i d o . Л ибо, если мы вы зовем его в отпош епии объекта t i n y ,
то t h i s будет указывать па t i n y в вы зове метода. Но откуда t h i s зпает, какой
объект опо представляет? Д авайте посмотрим.

Допустим, у нас имеется объект dog, присвоенный fid o :

fid o = new D o g ( " F id o " , " M ix e d " , 3 8 );

V xname; "Fido" Вот экземпляр нашего нового


^ _ breed: "Mixed" ^ ___ _
объекта dog с нужными значе­
— weight: 38
ниями свойств.
bark: functionQ { ... }

(2 ^ Теперь мы вызываем b a r k о в отношении fid o : При каждом вызове метода в о т но ш е­


нии объекта JavaScript делает т а к >
f i d o . b a r k () th is чтобы ключевое слово this указывало
Г name: "Fido"
на сам э т о т объект. Таким образом,
здесь this указывает на fido.
breed: "Mixed”

— weight: 38 Так что когда мы ссылаемся


bark: functionQ { ... } на this.п а т е , мы знаем, что
имя объекта будет "Fido11.

Вы можете вызывать bark


в отношении любого объ­
( 3\ Таким образом, t h i s всегда будет указывать на объект, екта dogj a this при эт ом
в отношении которого был вызван метод, независимо будет присваиваться ко н-
от того, как много объектов dog мы создадим: . к рет н о м у dog до выполне-
^ ния вашего основного кода.
f i d o . b a r k () t i n y . b a r k () c l i f f o r d . b a r k ()

th is th is th is

name: "Fido" name: "Tiny" name: "C lifford"


breed: "Mixed" breed: "Chawalla" breed: "Bloodhound"

— weight: 38 - weight: 8 — weight: 65

bark: functionQ { ... } bark: functionQ { ... } bark: functionQ { ... }

дальш е ► 183
конструктор movie

184 глава 4
ф ункции и объект ы ja v a s c rip t

Часш°
ЧаДаБаеМые
В опросы

В чем заключается истинная разница между функцией Q l Да, в теле объекта this всегда будет указывать на сам
и методом? В конце концов, если они являются одним и тем объект. Нов некоторых особых ситуациях это может быть не так;
же, почему называются по-разному? например, все окажется несколько сложнее, когда объекты будут
находиться внутри объектов, и если вы решите предпринять дан­
Q i По соглашению, если объект включает функцию, мы называем ное действие, то вам придется принимать во внимание семантику,
ее методом. Функция и метод работают одинаково, за исключени­ поскольку таково общее правило.
ем того, что вызов метода объекта осуществляется с применением
оператора «точка», при этом метод может использовать this для Мне доводилось слышать о том, что при объектно-ориен-
доступа к объекту, в отношении которого был вызван. Считайте тированном программировании у меня могут иметься классы
функцию отдельным блоком кода, который можно вызывать, а ме­ объектов, которые способны наследовать свойства и методы
тод — поведением, привязанным к определенному объекту. друг от друга по цепочке. Например, у меня мог бы быть класс
mammals, от которого наследуют свойства и методы dog и cat.
Если я с помощью конструктора создам объекты, вклю­ Возможно ли это на JavaScript?
чающие метод, то в случае со всеми этими объектами будет
совместно использоваться один и тот же код данного метода? Q i Да, возможно. В случае с JavaScript используется так назы­
ваемое прототипное наследование, которое представляет
Q i Да, все верно, причем в этом заключается одно из преиму­ собой даже более мощную модель, чем модели, основанные строго
ществ объектно-ориентированного программирования: вы можете на классах. Рассмотрение прототипного наследования немного
создать код для класса объектов (например, для всех своих объ­ выходит за рамки данной книги, хотя, может, нам и стоило бы
ектов dog) в одном месте, и он будет совместно использоваться в написать больше о нем в сфере JavaScript.
случае со всеми объектами dog. Чтобы сделать его специфичным
для каждого из объектов dog, необходимо обратиться к их свой­
ствам, для доступа к которым вам потребуется использовать this. тор, не так ли?

Могу ли я задавать для this значения по своему выбору, 0 : Да, абсолютно верно! Date — это встроенный JavaScript-
и если да, не приведет ли это к тем или иным отрицательным конструктор. Когда вы указываете new Date () в коде, то полу­
последствиям? чаете в свое распоряжение объект Date с набором полезных
методов, которые можно использовать для работы с датами.
0 : Нет, вы не сможете задать для this какие-либо значения.
Помните, что this — это ключевое слово, а не переменная! Оно В чем разница между объектами, которые мы пишем сами
выглядит и ведет себя отчасти как переменная, но не является ею. и которые создаем с помощью конструктора?

Есть ли у this значение вне метода объекта? 0 : Основное различие заключается в том, как вы их создаете.
& Объекты, которые вы пишете сами, используя фигурные скобки
0 : Нет, если вы не вызываете метод объекта, то this будет и разделенные запятыми свойства, называются литералами
undefined. объектов. Вы символ за символом вносите их в свой код! Если
вам потребуется еще один такой объект, то придется самим напи­
сать его и позаботиться о том, чтобы он располагал аналогичными
Насколько я понимаю, когда я вызываю метод в отно­
свойствами. Объекты, генерируемые конструктором, создаются с
шении объекта, этот объект задается как значение this на все
использованием new и функции-конструктора, возвращающей объ­
время, пока будет идти оценка метода. Так ли это?
ект. Вы можете использовать функцию-конструктор для создания
множества объектов с одинаковыми свойствами, но с разными
значениями свойств, если пожелаете.

дальш е ► 185
реш ение упражнения

развлечения с м а гн и т а м и , ^ е^ ен и е

Таблички с рабочим кодом функции-конструктора Movie были прикреплены к холодильнику,


однако некоторые из них упали на пол. Можете ли вы восстановить целостность данного кода?
Будьте внимательны, поскольку на полу уже лежало несколько лишних табличек, которые могут
сбить вас с толку. Приведем реш ение данного задания.

Это к о н ст р ук т о р , в качестве
имени которого мы используем
Movie.
r a tin g , s h o w t im e s ) {

Мы передаем значения свойств,


которые к о т и м сконфигурировать:
titlej gen re> rating и showtimes...
r a tin g
и инициализируем эти свойства.
t h i s . s h o w t im e s =
Д ля ссылки на свойства в объекте
t h is .g e tN e x tS h o w in g = f u n c t i o n () { мы используем ключевое слово this.

va r now = n e w D a t e ( ) . g e t T i m e ()

fo r (v a r i = 0; i < t h i s . s h o w t im e s

va r s h o w t im e = g e tT im e F r o m S tr in g ( th is . [i]) ;
i f ( ( s h o w tim e - now) > 0 ) {

re tu rn "N e x t s h o w in g o f " + th is .t it le is " + t h i s . s h o w t im e s [i]

He забудьте п ост авит ь


в конце данного опера ­
-O - тора точку с запятой!

186 глава 4
ф ункции и объект ы ja v a s c rip t

Сразу Же проведем тест-драйв нашего конструктора


Теперь, когда у пас есть копструктор M ovie, п ора запяться создаппем объектов
m ovie! Н апечатав код фупкции-копструктора M ovie, добавьте приведеппы е пиж е
строки и проведите тест-драйв даппого копструктора. Мы полагаем, вы согласи-
тесь с тем, что это намного более легкий способ создапия объектов. Сначала мы создаем объект
movie для фильма Вискагоо
va r b a n z a iM o v ie = n e w M o v ie ( " B u c k a r o o B a n z a i" , Banzai (один из наших Любимых
" C u lt C la s s ic " , представителей жанра культ о-
пбрат ит е внимание, зна- ' вой классики), а также передаем
иенше массива для showtimes ' значения для параметров.
М О Ж Н О п о м е с т и т ь прямо ["1:00pm", "5:00pm", "7:00pm", "11:00рт"]);

в вызов функции.
var plan9Movie = new Movie ("Plan 9 from Outer Space",

" C u lt C la s s ic " , д йлее следуем plan , from


2 , Outer Space...
["3:00pm" , "7:00pm", "11:00pm"]) ;

•••и, конечно же,


var forbiddenPlanetMovie = new Movie ("Forbidden Planet", ^ Forbidden Planet
"Classic Sci-fi",

5,
["5:00pm", "9:00pm"]);

Создав все необходимые объекты, мы мо~


a l e r t ( b a n z a iM o v ie . g e tN e x tS h o w in g ( ) ) ; Л - ------^ Жем вызывать м ет од getNextShow ing и
выводить для пользователя в диалоговых
alert (plan9Movie.getNextShowing () ) ;
окнах alert сообщения о времени следую -
a l e r t ( f o r b id d e n P la n e t M o v ie . g e tN e x tS h o w in g () ) ; щего сеанса соот вет ст вую щ его фильма.

http://iocalliost
Next Showing o f Forbidden Planet is 5:0flpm

http://Jocalhost
Next showing o f Plan 9 from Outer Space is 3:00pm

h ttp ://lo c a lh o s t

Next showing Of Buckaroo Banzai is n o o p m

дальш е ► 187
тур по объектам

Поздравляем! Вы справились с изуче­


нием функций и объектов! Теперь, когда
вы все знаете о них, и прежде, чем мы завершим
эту главу, потратим немного времени и взгля­
нем на Java S crip t-объекты в «дикой природе»,
то есть в их родной среде — в браузере!

Вы, возможно, уже стали замечать...


...что объекты буквально окружают вас. К прим е­
ру, docum ent и w indow — это объекты, равно как и
элементы , возвращ аемы е посредством d ocu m en t,
g e t E lem en t By Id. Но это лиш ь часть того множ е­
ства объектов, с которы м и мы будем сталкиваться
в дальнейшем, —когда дойдем до API-интерф ейсов
HTML5, вы увидите, что объекты встречаю тся
на каждом шагу!
Д авайте еще раз взглянем на некоторы е объекты,
которы е уже использовали ранее в книгет

Объекты, с к о ­ document
торы ми мы уже domain
1
сталкивались. title
movie
URL
А вот наш
объект movie. title
genre getElementByld
N— 7 rating getElementsByTagName
showtimes

getNextShowing createElement L button ~1


window on click I
Мы изобразили объекты document
следующим образом: вверху
\ocation
приводятся свойства... ^
onload
...а внизу — методы, I status innerHTML
благодаря чему вы сразу childElementCount
alert value
можете увидеть свод­ firstChild
prompt
ку по каждому объекту
open
со всеми его свойствами appendChild
dose
и методами. setTimeout insertBefore
setlnterval

188 глава 4
ф ункции и объект ы ja v a s c rip t

Что такое объект window?


Когда вы будете писать код, вы полняем ы й в бра­
узере, объект window станет частью ваш ей ж изни.
Д аппы й объект представляет собой глобальную
среду для JavaScript-nporpaM M , а также главное
окпо п рилож ения и как таковой содерж ит множе­
ство важпых свойств и методов. Д авайте взглянем W e b v ille C in e m a

па пего. 7
@ hnp:/ localhosi/mavle.htm l Google

Вот наш объект window вм ест е с н е­


сколькими примечат ельны ми свойствами h tt p : / /lo c a l h o s t

и м е т о д а м и >о которых вам нужно знать. Next showing of Butkaroo Banzai is i:00pm
Помимо нихj есть еще множество других...

focation содержит
U R L -аЭ р е с с т р а н и ц , : .
Е сли и з м е н и т е е г о ,

L " f « Г Г
новмй URL -адрес.
Вы, несомненно, уже сталкивались с ним
ранее, onload — это свойство, содержа­
status содержит стро
щее функцию, которая вызывается после
Ку, которая отобра­ полной загрузки страницы.
жается в ст атусной
строке браузера. С в о й с т в о d o c u m e n t с о д е Р * “ ™ ° 6*у
ек т н ую модель документа (РОМ).
Вы уже знакомы
с мет одом a lert,
который выводит v r o m . p t подобен a l e r t , за т е м и с к л ю ­

соот вет ст вую щ ее чением, ч т о получает информацию


диалоговое окно. от пользователя.

О т к р ы в а е т новое^
окно браузера.
В ы з ы в а е т о б р а б о т ч и к по и с т е ч е н и и
З акр ы ва ет окно , заданного и н т ер в а л а врем ен и.
s e tT im e o u t

s e tln te rv a l
Многократно вызывает обработчик
через заданный инт ервал времени.

дальше ► 189
как работает w indow .onload

Мы все время писали alert,


а не window alert... А откуда
браузер будет знать, что мы име­
ем в виду метод a le rt объекта
window?

Объект window является глобальным.


Это может показаться немного страппым,
но объект window действует как глобальпая
среда, поэтому любые имена свойств или ме­
тодов из данного объекта разреш аю тся даже
в том случае, если вы не указали перед пими
слово window.
К роме того, лю бые глобальные перем еппы е,
которы е вы определяете, также помещ аю т­
ся в пространство имен window, так что вы
сможете ссылаться на них следующим обра­
зом: w in d o w .имя_переменной.

Более пристальный Взгляд на window.onload


По ходу к п иги мы с вами часто использовали обработчик собы тий w in d o w .o n lo a d .
Путем присваивания фупкции свойству w in d o w .o n lo a d мы сможем гараптировать,
что паш код пе будет вы полпяться до тех пор, пока загрузка страпицы пе закопчится
и объектпая модель докумепта (DOM) пе будет полпостью сгеперировапа. В операто­
ре w in dow , o n lo a d мпого чего происходит, поэтому давайте еще раз взгляпем па пего,
чтобы вы четко во всем разобрались.

Вот наш глобальный onload является свой - Это анонимная функция, которая
объект window ст вом объекта window. f присваивается свойству onload.

L ^ *
^ w in d o w . o n l o a d = f u n c t i o n ( ) {
// code h e re
} ;
И, конечно же, тело функции будет выполняться
как.только window полностью загрузит страницу
и вызовет нашу анонимную функцию!

190 глава 4
ф ункции и объект ы ja v a s c rip t

Еще один взгляд на объект document


О бъект docum ent также уже вам зпаком — мы использовали его для доступа к объектпой
модели докумепта (DOM). О п является свойством объекта window. Мы, копечпо, пе указы­
вали его как w indow , docum ent, поскольку в этом пе было пеобходимости. Д авайте загляпем
внутрь пего и посмотрим, какие еще там имею тся и птересп ы е свойства и методы:
Свойство dom ain — это домен сервера,
с которого загружается докум ент ,
например wickedlysmart.com.
Свойство title можно использовать для и з ­
влечения заголовка докум ент а, для чего нужно
Свойства domain указат ь document.title.
title
URL -адрес докум ент а.
URL £ Как вы уже зна е т е, данный м ет од позволяет
извлекать элем ент в соот вет ст вии с его
getElementByld идент иф икат ором.
Методы
getElementsByTagName Эти два схожи с g e t E lem e n ts у Id за и с к л ю ­
getElementsByClassName чением т огоj что они позволяют извлекать
элементы в соот вет ст вии с именами тегов
createElement и классов.

Мы использовали данный м ет од в главе 3


для создания новых элемент ов плейлиста.
Как вам уже известно, он генерирует э л е ­
м е н т ы , подходящие для включения в DOM.

Более пристальный взгляд на document.getElementByld


В пачале главы мы обещали, что к ее копцу вы пойм ете, что такое
d o c u m e n t.g e tE le m e n tB y ld . Ч то ж, вы справились с изучепием фупк-
ций, объектов и методов и теперь готовы к этому! Взгляпите па следу-

r
ЮЩее’ э т о объект document, который является в с т р о ­
енным JavaScript-объектом, обеспечивающим
доступ к объектной модели документа (РОМ).
var div = document.getElementByld("myDiv");

Это м е т о д , который... ...принимает один аргу


м е н т в виде значения id
элемент а <div> и возвря
щ ает объект элемента.
То, что рапее выглядело как приводящ ая в замеш ательство строка сип-
таксиса, теперь каж ется пампого более попятпы м, пе так ли? Перемеп-
пая d iv также является объектом —объектом элемепта. Д авайте более
пристальпо взгляпем и па пего.

дальше ► 191
объект элемента

Еще один объект, о котором нуЖно знать: объект элемента


Не забы вайте, что п ри работе с методами вроде g e tE le m e n tB y ld элемепты , которы е опи возвращают,
также являю тся объектами! Ладпо, вы могли и пе осозпавать этого, по теперь, с учетом того, что вам
уже известпо, вы, возможпо, пачали считать, что все в JavaScript является объектами (что, впрочем ,
в больш ой степепи верпо).
Вы уже зпакомы с пекоторы м и свойствами элемептов, паприм ер со свойством innerHTML; давайте
взгляпем па ряд более прим ечательпы х свойств и методов.
Свойство innerHTML уже вам знакомо; два
других свойства - э т о childElementCount Свойства и методы
(количество дочерних элементов у эле элемент а <р>, од­
мент а) u firstChild (первый дочерний э л е - _ inner HTML нако их поддержи­
м е н т , если таковой имеется). childElementCount ва ю т и все другие
firstChild элементы.
Бы можете использовать м е т о ­
ды appendChild и insertsefore для appendChild
вставки новых элементов в РОМ / in sertBefore
в качестве дочерних по отношению setAttribute
к определенному э л е м е н т у . getAttribute

Мы будем использовать setA ttrib ute и g e tA ttr ib u te


для задания и извлечения а т ри б ут о в>таких как src,
class и id, в случае с элементами.

Част°
ЧаДаБаеМ ы е
В опросы

Поскольку windo______ — „ „ . „ а . 0 » Да, правильно. Однако мы не рекомендуем так поступать


чает ли это, что я могу использовать его свойства и методы, в данном конкретном случае, поскольку существует масса других
не указывая перед ними слово window? объектов, имеющих свойство o n lo a d , в силу чего ваш код будет
намного яснее, если вы укажете window, перед o n lo a d .
0 : Все верно. Вам решать, указывать ли слово w indow перед
именем свойства или метода объекта window. В случае, напри­ Причина, по которой мы не пишем window.onload = initO,
мер, с a l e r t все знают, что это за метод, и никто не указывает в том, что в результате этого произошел бы вызов данной
перед ним window. С другой стороны, если вы используете менее функции, а не присваивание ее значения свойству onload?
известные свойства или методы, то можете захотеть сделать свой
код более легким для понимания, и в таком случае вам потребуется 0 : Все верно. Когда вы указываете круглые скобки после имени
указывать перед их именами слово window. функции, например i n i t (), то этим вы говорите, что хотите вы­
звать функцию i n i t . Если же вы укажете ее имя без круглых
Технически, я могу написать onload = init вместо window, скобок, то под этим будет подразумеваться, что вы присваиваете
onload = init, не так ли? значение функции свойству o n lo a d . Это тонкий момент, который
легко упустить из виду при создании кода, однако он влечет за собой
весомые последствия, так что будьте очень внимательны.

192 глава 4
ф ункции и объект ы ja v a s c rip t

• Какой из двух способов создания обработчика window, J y * В чем разница между встроенными объектами вроде
onload лучше: с указанием имени функции или посредством window и document и теми, которые создаем мы?
использования анонимной функции?
0 : Первое различие заключается в том, что встроенные объекты
Q l Один не является лучше другого, поскольку при использовании отвечают принципам, определяемым спецификациями, и вы можете
любого из этих способов вы, по сути, будете делать одно и то же — обраться к спецификациям W3C, чтобы разобраться во всех их
задавать значение w in d o w , o n lo a d в виде функции, которая свойствах и методах. Во-вторых, многие встроенные объекты (на­
станет выполняться после полной загрузки страницы. Если вам по пример, s t r i n g ) обладают свойствами, которые не могут быть
какой-то причине потребуется вызывать i n i t из другой функции изменены. Кроме того, объекты есть объекты. Замечательная
позже в своей программе, то придется определить функцию i n i t . вещь, касающаяся встроенных объектов, состоит в том, что они
В противном случае не будет важно, какой способ вы предпочтете. уже созданы и готовы к использованию вами.

( Д а , String — это объект! Загляните


в хороший справочник по JavaScript,
чтобы узнат ь все подробности о его
свойствах и методах-

Поздравляем! Вы завершили
свое путешествие по объектам и преодолели
несколько глав учебного курса по Ja va S crip t.
Настало время применить эти знания и заняться
программированием с использованием H TM L5
и всех новы х A P I-интерсрейсов J a v a S c rip t
начиная со следую щ ей главы!
Вы завершаете эту главу, зная об объек­
тах и ф ункциях больше, чем м ногие дру­
гие л ю д и. Естественно, вы всегда можете
научиться чем у-то еще, и м ы призываем вас
именно так и поступить (после то го , как
закончите читать данную книгу)!

П ередохните нем ного, завершив


эту главу, и прежде, чем двинуться даль­
ше, ознакомьтесь с секцией «Кл ю чевы е
м ом енты » и решите кроссворддля закре­
пления изученного материала.

дальш е ► 193
обзор ф ункций и объектов

КЛЮЧЕВЫЕ
МОМЕНТЫ

■ Для создания функции необходимо использовать ■ Если присвоить новую переменную, не используя
ключевое слово fu n c tio n в сочетании с круглы­ ключевое слово v a r, эта переменная будет гло­
ми скобками, в которые будут заключаться пара­ бальной, даже если вы впервые присваиваете ее
метры при наличии таковых. функции.
■ Функции могут быть именованными либо аноним- ■ Функции — это значения, которые могут присваи­
ными. ваться переменным, передаваться другим функ­
■ Правила присваивания имен функциям являются циям, сохраняться в массивах и присваиваться
теми же самыми, как и в случае с переменными. свойствам объектов.

■ Тело функции заключается в фигурные скобки и со- " Объекты — это коллекции свойств.
держит операторы, выполняющие работу функции. ■ Обращаться к свойствам объектов можно с ис­
■ Функция может возвращать значение посредст­ пользованием точечной или скобочной нотации.
вом оператора re tu rn . ■ При использовании скобочной нотации имя свой­
■ Для вызова функции необходимо указать ее имя ства следует заключать в кавычки, как строку, на­
и передать все необходимые аргументы. пример: myObj e c t [ "имя"].

■ В JavaScript используется передача параметров " Вы можете изменять значения свойств, удалять
по значению. свойства и добавлять новые свойства в объекты.

■ Когда вы передаете объект (например, d o g ) ■ Вы можете перечислять свойства объектов, ис­


в качестве аргумента функции, соответствующий пользуя ЦИКЛ f o r - i n .
параметр получает копию ссылки на данный в Функция, присвоенная свойству объекта, называ­
объект. ется методом.
■ Переменные, определяемые внутри функций, и Метод может использовать специальное ключе­
включая параметры, называются локальными. вое слово t h is для ссылки на объект, в отноше­
■ Переменные, определяемые вне функций, назы­ нии которого он был вызван.
ваются глобальными. и Конструктор — это функция, создающая объекты.
■ Локальные переменные невидимы вне функции, и Работа конструктора заключается в создании но­
в которой они определены. Это называется обла­
вого объекта и инициализации его свойств.
стью видимости переменной.
■ Для вызова конструктора с целью создания объ­
■ Если объявить локальную переменную с тем же
екта необходимо использовать ключевое слово
именем, что и у глобальной переменной, то гло­
new. Например, new Dog () .
бальная переменная окажется «в тени» локаль­
ной переменной. ■ По ходу книги мы с вами уже использовали не­
сколько объектов, включая docum ent, window,
■ При указании ссылок на множественные Java-
а также различные объекты элементов.
Script-файлы на странице все глобальные пере­
менные должны определяться в одинаковом гло- ■ МеТОД d o cu m e n t. g e tE le m e n tB y ld ВОЗВраща-
бальном пространстве. ет объект элемента.

194 глава 4
ф ункции и объект ы ja v a s c rip t

U I M L 5 - K f ° CCB ° r A

Это была ураганная глава о функциях, объектах, свойствах и методах, так


что вам много чего необходимо закренить в намяти. Вот кроссворд к главе 4,
которы й вам нужно реш ить.

По горизонтали По вертикали
2. Функция без имени. I. По соглашению, имена конструкторов должны начинаться
6. Эти переменные доступны только внутри функций. с __________ буквы.
8. Функции без операторов return возвращают это. 3. Связывание свойств и вызовов функций посредством оператора
9. Функция в объекте. «точка».
12. Объект__________ представляет собой объектную модель до­ 4. То, что указывается в вызове функции.
кумента (DOM). 5. Функция данного рода создает объекты.
13. Аргументы передаются по__________. 7. Свойство в window, которое мы присваиваем функции обработ­
15. Данное ключевое слово необходимо использовать в начале чика.
определения функции. 10. Оператор «________ » позволяет получить доступ к свой­
17. Настоящий глобальный объект. ствам и методам объекта.
18. То, что указывается в объявлении функции. II. Функции могут включать, а могут и не включать данный оператор.
14. Область видимости переменной, которая доступна повсеместно.
16. Указывает на текущий объект в методе объекта.

дальш е ► 195
решение упражнения

г ^ о зь м и в руку карандаш
Решение Воспользуйтесь своими знаниями о функциях и передаче аргументов
параметрам для оценки приведенного ниже кода. Сделав это, напишите
внизу, какое значение будет иметь каждая из переменных. Вот наше ре­
шение этого задания.

fu n c tio n d o g s A g e (a g e ) {

re tu rn age * 7;

va r m yD ogsA ge = d o g s A g e (4 ) ;

fu n c tio n r e c t a n g le A r e a ( w id t h , h e ig h t ) {

va r a re a = w id th * h e ig h t ;

re tu rn a re a ;

va r re c tA re a = r e c t a n g le A r e a ( 3 , 4) ;

fu n c tio n a d d U p (n u m A rra y ) {

va r to ta l = 0;

fo r (v a r i = 0; i < n u m A r r a y . le n g t h ; i+ + ) {

to ta l += n u m A r r a y [ i] ;

}
re tu rn to t a l;

}
va r th e T o ta l = addU p([1 , 5, 3, 9 ]) ;

fu n c tio n g e tA v a ta r ( p o in ts ) {

va r a v a ta r;
Hanuvuume
i f ( p o in ts < 100) { ^
^ здесьj какое
a v a ta r = "M o u s e " ; значение будет
} e ls e i f ( p o in ts > 100 && p o i n t s < 1000) { и м е т ь каждая
a v a ta r = "C a t" ; [ из переменных.
} e ls e {

a v a ta r = "A p e "; О О
m yD ogsA ge = . .......................

re tu rn a v a ta r;
re c tA re a = . . . Ш . .......................
} th e T o ta l = ...% Z ............................
va r m y A v a ta r = g e t A v a t a r (3 3 5 ) ; m y A v a ta r = . ...C & t. ...................

196 глава 4
ф ункции и объект ы ja v a s c rip t

K M L 5 ” K F4><rBoP A* Г еШ ение

дальш е ► 197
g создание 1 П Ж -ст р а н и ц с поддержкой
определения м есто п о л о ж ен и я ^ _ф _

Куда бы вы ни отправились, вас можно найти. Порой знание того, где


вы находитесь, имеет существенное значение (особенно для веб-приложений).
Из этой главы вы узнаете, как создавать веб-страницы с поддержкой опреде­
ления местоположения, — иногда вы сможете определять местонахождение
своих пользователей вплоть до угла, на котором они стоят, а иногда вам будет
удаваться выяснить лишь район города, в котором они находятся. Время от
времени вы вообще не сможете получить хоть какую-то информацию о местопо­
ложении пользователей в силу технических причин или просто потому, что им не
нравится ваше чрезмерное любопытство. Да, представьте себе! Так или иначе,
в этой главе мы рассмотрим API-интерфейс JavaScript под названием Geolocation.
Возьмите свое лучшее устройство с поддержкой определения местоположения
(даже если это будет настольный компьютер), и давайте приступим к работе.
api-интерфейс geolocation

Ваши пользователи путешествуют с мобильными


устройствами, поддерживающими определение ме­
стоположения. Наилучшими будут приложения, которые О
повышают качество пользовательского взаимодействия путем
использования данных об их местонахождении.

Местоположение, местоположение...
Знание того, где находятся ваши пользователи, дает возможность обеспечи­
вать для них более качественное взаимодействие: вы мож ете указывать им
направление; советовать, куда бы они могли отправиться; дать им знать о том,
кто еще, находящ ийся поблизости, интересуется, наприм ер, теми же м еро­
приятиям и, что и они. Существует бесчисленное множество путей использо­
вания и нф орм ации о местополож ении.
С помощью HTML5 (и API-интерф ейса G eolocation на основе JavaScript) вы
можете легко получать доступ к инф орм ации о м естополож ении на своих
страницах. Однако есть вещи, о которы х вам необходимо знать, прежде чем
мы приступим к работе. Д авайте рассмотрим их.

Часто
Задаваем ы е
BolJpocTbl

ъ- • Я слышал, что Geolocation не является настоящим API-


интерфейсом.
инте| Это так?
5='Если мое устройство раскрывает мое местоположение,
разве
разв это не вторжение в частную жизнь?

0 :
Geolocation не считается полноценным членом семейства
существующего стандарта HTML5, однако следует отметить, что
О , Спецификации API-интерфейса Geolocation определяют, что
любой браузер должен получить от пользователя специальное
он является стандартом W3C, который широко поддерживается, разрешение на использование данных о его местоположе­
и многие относят Geolocation к числу важных API-интерфейсов нии. Таким образом, если ваш код задействует API-интерфейс
в HTML5. И его наверняка можно назвать настоящим API-
Geolocation, то первое, что сделает браузер, — это удостове­
интерфейсом JavaScript!
рится в том, что пользователь согласен раскрыть информацию
о своем местонахождении.
f t API-интерфейс Geolocation и API-интерфейс Google
Maps
Maps — это не одно и то же?
5 =Насколько хорошо поддерживается API-интерфейс
Geolocation?
Geoh
0: Нет. Это абсолютно разные API-интерфейсы. Geolocation
сосредоточен исключительно на получении информации о ме­
стоположении человека на поверхности Земли. API-интерфейс
Google Maps — это JavaScript-библиотека от компании Google,
0 :Очень хорошо. Фактически, он доступен почти в любом
современном браузере, включая настольный и мобильный
которая обеспечивает доступ ко всей функциональности Google сегменты. Только необходимо убедиться, что вы используете
Maps. Если вам необходимо отображать местоположение своих последнюю версию браузера. Если это так, скорее всего, ни­
пользователей на карте, то API-интерфейс от Google станет каких проблем с поддержкой API-интерфейса Geolocation у вас
удобным инструментом. не возникнет.

200 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

Широта и долгота...
Ч тобы узнать, где вы находитесь, нотребуется система координат на новерхности Земли. К сча­
стью, у нас им еется такая штука, которая задействует ш ироту и долготу в качестве системы коор­
динат. Ш ирота онределяет северную /ю ж ную точку на новерхности Земли, а долгота — восточ­
ную / занадную точку. Ш ирота изм еряется от экватора, а и зм ерение долготы ведется от Гринвича, _
Англия. Задача API-интерф ейса G eolocation заклю чается в том, чтобы дать нам координаты на- *\
шего м естонолож ения в лю бой момент времени, иснользуя следующие координаты:
О т Королевской
Ш ирота — это расстояние обсерват ории
Координаты Си­ на север или на юг от экватора. в Г р и н в и ч е , ес ли
ликоновой долины: быть точными.
3737, - г г г я г Координат ы Гринвича,
Англия: 5 1 .4 7 , О
Координаты
Н ью -Й орка:
4 0 .7 7 , - 7 3 Я 2 Долгот а — это рас­
стояние на восток
или на запад от
Гринвича , Англия .

Координаты
П о р т о -Ново,
Тренин: (о.4Я, 2-.(о1
Координаты Л и м ы ,
Перу: - 1 2 . 0 5 , - 7 7 . 0 4

/> П о д л е е ° ш и ^ о т а е /т я г о т е

Вам, вероятно, доводилось видеть, что широта и долгота указываются как в градусах/минутах/секундах,
например (47°38'34", 122°32|32"), так и в десятичных значениях, например (47.64, -122.54). В случае
с API-интерфейсом Geolocation мы всегда будем использовать десятичные значения. Если вам по­
требуется преобразовать градусы/минуты/секунды в десятичные значения, это можно будет сделать
с помощью следующей функции: *■
Следуем о т м е т и т ь ,
function degreesToDecimal (degrees , minutes , seconds) { ито западная долгота
return degrees + (minutes / 60.0) + (seconds / 3600.0) ; w южная ш и р о к а пред
ставляются отрица-
) т е л ь н ы м и зн а ч е н и я м и .

дальше ► 201
определение мест оположения

Как A PI-интерфейс Geolocation определяет местоположение пользователя


Вам необязательно иметь новейш ий см артф он, чтобы онределять свое местонолож ение. Это нозволя-
ют делать даже настольны е браузеры. У вас мож ет возникнуть вонрос о том, как настольны й браузер
мож ет онределить ваше м естонолож ение, если у него нет GPS или другой снециальной технологии,
даю щ ей возмож ность сделать это. Ч то ж, все браузеры (установленные в онерационны х системах мо­
бильны х устройств и настольны х комнью теров) иснользую т несколько снособов онределения м естопо­
лож ения, н ричем одни дают более точны й результат, чем другие. Д авайте взглянем н а них.

Я выиграла новейший
смартфон со встроенной под­
держкой GPS и теперь могу с вы­ 1Р-адресс
сокой точностью определять свои
координаты!
Для получения информации
о местоположении пользова­
теля по его IP-адресу исполь­
зуется внешняя база данных,
посредством которой 1Р-адрес
соотносится с физическим ме­
стоположением пользователя.
Преимущество данного под­
хода заключается в том, что он
может работать везде; однако
зачастую оказывается, что IP-
адреса принадлежат, напри­
мер, местному офису интернет-
провайдера, обслуживающего
пользователей. Данный способ
можно считать надежным,
если речь идет о городе
ЫуЛ или его окрестностях.
ш
GPS
Глобальная система определения координат (Global
Positioning System), поддерживаемая многими со­
временными мобильными устройствами, позволяет
очень точно определять местоположение благода­
ря спутникам. Информация о местоположении мо­
жет включать данные о высоте, скорости и направ­
лении. Однако для того, чтобы пользоваться этой
системой, вашему устройству необходимо «видеть»
небо, при этом получение данных о местоположе­
нии иногда занимает много времени. GPS также
может ускорить разрядку аккумуляторной батареи
вашего устройства.

202 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

У меня мобильник устаревшей мо­


дели. В этом «малыше» нет GPS. Однако
посредством триангуляции с использованием
вышек сотовой связи мой телефон способен
помочь определить мое местоположение
с довольно большой точностью, чем может
воспользоваться браузер.

Мобильный
телефон
Триангуляция с использованием
вышек сотовой связи и мобиль­
ного телефона позволяет опре­
делить местоположение, взяв за
Я перемещаюсь из одного кафе
основу расстояние, на котором
в другое с ноутбуком и беспроводным
его обладатель находится от од­
подключением. Определить мое место­
ной или более вышек (очевидно,
положение можно посредством триангу­
что чем больше будет вышек, тем
ляции с использованием точек беспро­
точнее окажется информация о местоположении).
водного доступа. Данный способ должен
Данный способ может давать довольно точный ре­
довольно хорошо работать.
зультат и работает в помещениях (в отличие от GPS);
кроме того, иногда он позволяет намного быстрее
получить итоговые данные, чем GPS. Однако если
пользователь окажется в какой-нибудь глухомани,
где есть только одна вышка сотовой связи, точность
определения его местоположения будет невысокой.

При WiFi-позиционировании за­


действуется одна или более точек
доступа WiFi, что позволяет
вычислить местоположение
пользователя. Данный способ
может давать весьма точный ре­
зультат, является быстрым и рабо­
тает в помещениях. Очевидно, что
он требует, чтобы пользователь
оставался в некоторой степени не­
подвижным (например, сидел и пил
чай со льдом в кафе).

дальш е ► 203
мет од определения м ест оположения

Здорово, что у нас


есть так много способов опре­
делить свое местоположение.
А как узнать, какой из них будет
использовать мое устройство.

Никак.
К раткий ответ на ваш вонрос —«никак»,
поскольку подход к онределению ме­
стополож ения зависит от реализации
браузера. Однако есть и хорош ая но­
вость: браузер мож ет иснользовать лю­
бой из упоминавш ихся выше снособов
определения местополож ения. Ф акти­
чески, если браузер достаточно умен,
он сначала мож ет задействовать три ан ­
гуляцию с использованием вышек сото­
вой связи, если таковая достунна, для
грубой оценки м естополож ения, а за­
тем выдать вам более точны й результат
посредством WiFi или GPS.
П озже вы увидите, что не стоит бесно-
коиться о том, как именно определяет­
ся м естонолож ение. Вместо этого мы
сосредоточимся на точности опреде­
лен и я м естонолож ения. Исходя из точ­
ности результатов вы сможете реш ить,
насколько нолезны ми окажутся для вас
но лученные данные. Мы вернем ся к во-
нросу точности чуть нозже.

204 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

-Возьми в руку карандаш

Задумайтесь об HTML-страницах и прилож ениях, которы е уже у вас


имеются (или которые вы хотите создать); для чего может быть полезна
включенная в них функция, позволяющая определять местоположение
пользователей?

| | Дать пользователям возможность отыскивать находящихся по­


близости других людей с аналогичными интересами.

| | Помогать пользователям находить местные развлекательные


заведения или услуги.

| | Отслеживать, где именно пользователи что-то делают.

| | Указывать направление пользователям относительно той точки,


где они находятся в текущий момент.

| | Использовать данные о местоположении для выяснения иной


демографической информации о пользователях.

□ ........................................................................................

□ ........................................................................................

□ ........................................................................................

□ ........................................................................................

Свои идеи напиш ите здесь!

дальш е ► 205
использование ар1-интерфейса geolocation

Так где Же Вы находитесь?


К онечно же, ям знаете, где находитесь, однако давайте носмот-
рим, каково ваше м естонолож ение с точки зрен и я браузера.
Д ля этого мы создадим небольшую HTM L-страницу.
8 верхней части располагаются привычные
вещи, включая ссылку на файл myLoc.js, в к о ­
т ором будет размещ ат ься наш JavaScript,
< ! d o c ty p e h tm l> и таблицу ст илей myLoc.css для придания
< h tm l> приложению красивого внешнего вида.
<head>
Наш геолокационный
< m e ta c h a r s e t = " u t f - 8 M>
код будет р а з м е ­
< title > W h e r e am I? < / t it le >
щаться в myLoc.js.
< s c r ip t s rc = "m y L o c . j s " X / s c r i p t >
C lin k r e l = Ms t y l e s h e e t 11 h r e f = Mm y L o c . c s s " >
< /h e a d >
<body>

< d iv id = " lo c a tio n " >


Данный э лем ент <div>
будет использоваться
Your lo c a t io n w ill go h e re .
для вывода информации
< /d iv >
о вашем местоположении.
< /b o d y >
< /h tm l> К , Весе» э т о т HTML необходимо
п о м е ст и т ь в файл myLoc.html.

Тенерь создадим файл m yLoc. j s и наниш ем немного кода; сделаем это


быстро, а чуть нозже вернемся к данному коду и проанализируем его.
Д обавьте нриведенны й ниж е код в файл m yLoc. j s .
Мы вызываем функцию getMyLocation, как только
браузер заканчивает загрузку страницы.
Проверяем, поддерживает ли браузер AP I-инт ерф ейс
Geolocation; если объект navigator.geolocation п р и с у т -
w in d o w .o n lo a d = g e tM y L o c a tio n ; f
с т в у е т , то все в порядке!
Если поддержка имеется, вызываем мет од
fu n c tio n g e tM y L o c a tio n () { s- getCurrentPosition и передаем функцию обра-
I ботчика событий displayLocation. Мы р е а л и ­
i f ( n a v ig a to r .g e o lo c a tio n ) { Y
зуе м ее через несколько мгновений.
n a v ig a t o r . g e o lo c a t io n . g e t C u r r e n t P o s it io n ( d is p la y L o c a t io n ) ;

} e ls e { функция displayLocation —
— это обработчик, которому
a l e r t (" O ops , n o g e o lo c a tio n s u p p o r t " ) ; будет передаваться объект
у с данными о местоположении.
Если браузер НЕ поддерживает A P I-инт ерф ейс Geolocation,
} то просто выводим диалоговое окно alert с с о о т в е т с т в у ю ­
щ им сообщением для пользователя.
206 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

Обработчику getCurrentPosition п е р е ­
Обработчик, который будет вы­ дается объект position, содержащий
зываться, когда браузер получит ш иро т у и долготу вашего м е с т о п о л о ­
данные о м ест ополож ении.^ жения (наряду с данными, касающимися
точност и, о которых мы поговорим
fu n c tio n d is p la y L o c a tio n ( p o s itio n ) {
немного позже).
va r la titu d e = p o s it io n . c o o r d s . l a t it u d e ; П

va r 1 o n g i tu d e = p o s i t i o n . c o o rd s .1 o n g i tu d e ; \
Извлекаем ш и рот у и долготу
вашего местоположения из объ­
екта position.coords.
va r d iv = d o c u m e n t . g e t E le m e n t B y ld ( " l o c a t i o n " ) ;

d iv .in n e r H T M L = "Y o u a re a t L a titu d e : " + la titu d e + L o n g itu d e : " + lo n g itu d e ;

х
З а т е м извлекаем наш X
<div> из HTML * 4 ваше
... и задаем * местоположение
в качестве содержимого элем ент а
<div> с использованием innerHTML.

Tecm-драйб местоположения
Н аберите нриведенны й выше код и нроведите тест-драйв сво­
ей новой страницы.
□ Request P erm ission o n ly once
e v e ry 2 4 h o u rs
П ри нервом вы нолнении геолокационного веб-нрилож ения
вы увидите в браузере окно с занросом на разреш ение исноль-
зовать данны е о вашем м естонолож ении. Это нроверка систе­
мы защ иты браузера, и вы мож ете отказать браузеру в данном Запрос на разрешение может
занросе. Поскольку нреднолагается, что вы хотите протести ­
ровать свое веб-нриложение, нужно будет нажать кнонку Allow
(Разреш ить) или Yes (Да). П осле этого н рилож ение выдаст ко­
t выглядеть п о-ра зн ом у в зависи­
м о ст и о т используемого вами
браузера, но будет приб лизи­
ординаты вашего м естонолож ения, как но казано ниже. тельно таким.

& О О J Q W h e r e a m [?

f 4 С? Л ® localhost/~Beth/i-L. Q s & | Ejj £3 4* Л


А вот и ваши координаты! Ваше
местоположение определенно будет
You are at Latitude: 47.62485, Longitude: -122.52099
отличаться от нашего (а если н е т ,
то мы будем волноваться за вас).

Если ваше приложение не выдает к о ­


ординаты местоположения и вы дваж­
ды проверили код на наличие опечаток,
то немного подождите, поскольку через
несколько страниц вы познакомитесь
l И м ейт е в виду, что получение данных о м е ­ с диагностическим т е ст о м , который
стоположении не всегда происходит мгновенно поможет найти причину неполадок...
и может занят ь некоторое время...
дальш е ► 207
обзор кода geolocation

Е с л и ваш браузер поддер­


живает A P I-интерфейс Geolocation,
то вы обнаружите свойство
geo location в объекте navigator
Что мы только что сделали...
Тенерь, когда мы с вами создали и протестировали геолокационны й код
(онять-таки, если данное н рилож ение не выдало вам координат, п отерпите
немного, носкольку мы очень скоро ноговорим об отладочных методиках),
давайте нройдем ся но коду более детально.

А Первое, что вам необходимо знать, если вы собираетесь написать


геолокационный код, — это «поддерживает ли данный браузер
API-интерфейс Geolocation?». Опирайтесь на тот факт, что свойство
g e o l o c a t i o n присутствует в объекте n a v i g a t i o n браузера только
в том случае, если он поддерживает API-интерфейс Geolocation.
Таким образом, мы можем проверить, присутствует ли свойство
g e o l o c a t i o n , и если оно имеется, то воспользуемся им; в про- I
тивном случае мы дадим пользователю знать об отсутствии под­
держки API-интерфейса Geolocation посредством вывода соответ­
ствующего сообщения в диалоговом окне a l e r t :
Мы м ож ем выяснить, имеется ли в объекте свойство
i f ( n a v ig a to r .g e o lo c a tio n ) { geolocation (если оно о т с у т с т в у е т , то р е зу л ь т а т о м
S оценки navigator.geolocation окажется null, и значение
Уe l s e { соот вет ст вую щ его условия будет false).
a le r t ("O o p s , no g e o lo c a tio n s u p p o rt"); Е-сли свойство п р и с у т с т в у е т , то мы
^ смо>келл использовать его, а если его н е т ,
то уведомляем пользователя посредством
диалогового окна alert.
А Если МЫ все же обнаружили свойство n a v i g a t o r . g e o l o c a t i o n , A P I -интерфейсы —
можно воспользоваться им. Фактически, данное свойство представ- \ это просто объекты
ляет собой объект, содержащий весь API-интерфейс Geolocation colocation. ^ со свойствами и м е т о -
Основной метод, поддерживаемый этим API-интерфейсом, назы­ дами! Теперь вы рады,
вается g e t c u r r e n t P o s i t i o n и занимается извлечением информа­ что загодя прошли
ции о местоположении браузера. Более пристально взглянем на JavaScript-подготовку?
данный метод, обладающий тремя параметрами, два последних
из которых являются опциональными:
e r r o r H a n d l e r является другой ф у н к ц и ­
s u c c e s s H a n d l e r — ф ункция, которая вызывается,

с
ей , которая вызывается, если ч т о - т о
если браузер способен успешно определить ваше
пойдет не т ак и браузер не сможет
местоположение.
\ определить ваше местоположение.
getcurrentPosition (successHandler, errorHandler, options)
] 'ft ^ Параметр options
Эти два пара м ет р а являются опциональ­ позволяет сконф и­
ными, что объясняет, почему они не т р е ­ гурировать работу
бовались нам ранее. API -инт ерф ейса
Qeolocation.
208 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

А сейчас взглянем на вызов метода g e t c u r r e n t P o s i t i o n . Мы передаем ар­


гумент в виде обработчика успешного исполнения для обработки удачной по­
пытки извлечения данных о местоположении браузера. Чуть позже мы рассмо­
трим ситуацию, когда браузеру не удается отыскать местоположение.

Помните объединение в цепочку, о кот ором говорилось


в главе 4 ? Мы используем объект navigator для п о л и -
чения доступа к объекту geolocation, который я в л я -

/ ется свойством объекта navigator.

n a v ig a t o r . g e o lo c a t io n . g e t c u r r e n t P o s it io n ( d is p la y L
ции? К
здесь ак передаем
мы отмечалось
одну
Вызываем м ет од getcurrentP osition в главе 4, другой
функции
Когда АР [ - и н т е р ф е й с ' функцию ф унк-
объекта geolocation с использованием являются значениями,
определит ваше м е ­
одного аргум ент а — обработчика по эт ом у мы можем
стоположение, он вы ­
успешного исполнения.
зовет displayLocation. это делать.
Теперь взглянем на обработчик успешного исполнения d i s p l a y L o c a t i o n .
При вызове d i s p l a y L o c a t i o n API-интерсрейс Geolocation передает ему объ­
ект p o s i t i o n , включающий информацию о местоположении браузера, в том
числе объект c o o r d i n a t e s , в котором содержатся широта и долгота (а также
прочие значения, о которых мы поговорим позже).
position — это объект, который A P I-
интерфейс Geolocation передает вашему
обработчику успешного исполнения.
Объект position обладает свойством
coords, которое содержит ссылку
на объект coordinates...
fu n c tio n d is p la y L o c a tio n ( p o s itio n ) {

va r la titu d e = p o s it io n . с о o r d s T la t it u d e ;

va r 1 o n g i tu d e = p o s i t i o n . со o r d s .1 o n g i tu d e ; .объект coordinates,
свою очередь, содержит
ваши ш ирот у и долготу.
va r d iv = d o c u m e n t. g e tE le m e n t B y ld ( " l o c a t i o n " ) ;

d i v . in n e rH T M L = "Y o u a re a t L a titu d e : " + la titu d e + L o n g itu d e : " + lo n g itu d e ;

t
А эт а часть к настоящему м о м ен т у должна быть вам
абсолютна ясна: мы просто берем информацию о коор­
динатах и отображаем ее в элемент е <div> страницы.

дальш е ► 209
как работает получение т екущ ей позиции

Как бее это работает


Теперь, когда мы прошлись по коду, давайте посмотрим,
как все это работает во время выполнения.

Затем API-интерфейс
6eolocation запраши­
вает у пользователя
разрешение.
The w ebsite ,£http ://lo c a lh o s t" would like to
use your current location.
Если пользователь дает разреше­
ние, то API-интерфейс Seolocation
□ Request p erm iss io n o n ly once every 2 4 hours прикладывает максимум усилий
D o n ’t A llo w 3 (_ A llo w )
для извлечения информации о ме­
стоположении браузера (посред­
Браузер ством GPS, триангуляции и т. д.).

С ( i [С И м аДНвц М а Ь /Н ... О ☆ К ** *
p o s i t i o n .c o o r d s .l a t i t u d e

You are at LaMude: 47 .6 24 65 , Longitude: -1 2 2.5 20 99 p o s i t i o n .c o o r d s .l o n g i t u d e

И если API-интерфейсу 6eoloca+ion удается


определить местоположение браузера, он
вызывает обработчик успешного исполне­
Браузер
ния и передает ему объект с координатами.

210 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

si
-Диагностический тест-драйв
Когда дело касается API-интерфейса Geolocation, не каждый тест-драйв оказывается удачным; даже
если в случае с первым тестом все пройдет успешно, в дальнейш ем все равно что-то может пойти
не так. Поэтому мы создали небольшой диагностический тест, который вы можете добавить в свой
код. Таким образом, если у вас возникнут проблемы, вы сможете выяснить их причины; и даже если
они обойдут вас стороной, кто-то из ваших пользователей все равно может столкнуться с той или
иной проблемой, и вам будет необходимо знать, как решить ее в своем коде. Поэтому добавьте
приведенный ниже код, и если вы обнаружите неполадки, заполните диагностическую форму в
конце данной секции, указав в ней проблему, которую вам удалось диагностировать:
Для создания диагностического теста мы добавим обработчик ошибок в вызов метода
g e t c u r r e n t P o s i t i o n . Данный обработчик будет вызываться всякий раз, когда API-интерфейс
Geolocation сталкивается с рудностями определения вашего местоположения. Вот как будет осу­
ществляться его добавление:
Д о б а в ь т е в т о р о й а р г у м е н т в с вой вы зов getcurrentPosition с и м е н е м
d l T u Z o r . Э т о ф у н к ц и я , к о т о р а я б у д е т в ш и в а т ь с я , к о гд а А Р -
инт ересу Geolocation не у д а е т с я о п р е д е л и т ь м е с т о п о л о ж е н и е .

n a v ig a t o r . g e o lo c a tio n .g e tc u r r e n tP o s itio n ( d is p la y L o c a tio n , d is p la y E r r o r ) ;

Теперь необходимо написать код обработчика ошибок. Для этого вам нужно знать, что API-интерфейс
Geolocation передает вашему обработчику объект e r r o r , содержащий числовой код с описанием при­
чины, по которой он не смог определить местоположение вашего браузера. В зависимости от кода
также может выводиться сообщение с дополнительной информацией о возникшей ошибке. Вот как
мы можем использовать объект e r r o r в обработчике:
Вот нам новый обработчик, кот ором у API -
f f ' интерфейс deolocation передает объект error.
f u n c tio n (@jrjrojr) { О бъект error содержит своиамво error.code, Koimo —
_ рое им еет числовое значение от О до 3. Бот о т -
va r e rro rT y p e s личный способ ассоциировать сообщение об ошибке
0: "U n k n o w n e rro r", с соо т вет ст в ую щ и м кодом JavaScript:
" P e r m is s io n d e n ie d by u s e r" — Создаем объект с несколькими свойст вами,
" P o s itio n is no t a v a ila b le " , им ею щ им и имена О, И, 2 и 3 соот вет ст венно.
Эти свойства пр едст авляю т собой строки
"R e q u e s t tim e d o u t" с соо§ще,ниями об ошибке, которые мы х о т и м
}; ассоциировать с со о т вет ст вую щ и м кодом.
va r e rro rM e s s a g e = e rro rT y p e s [e r r o r . co d e ] ; ________ Используя свойство error.
i f (e rro r, code == 0 | | e r ro r, code = 2) { code} М Ы присваиваем
одни из этих ст рок новой
e rro rM e s s a g e = e rro rM e s s a g e + 11 " + e rro r .m e s s a g e ; и Г
^ переменной errorMessage.
3 случае с ошибками О и 2 иногда
va r d iv = d o c u m e n t. g e tE le m e n t B y ld ( " l o c a t i o n " ) ;
в свойстве error.message п р и с у т -
d i v . in n e r H T M L = e rro rM e s s a g e ; РЧ с т в у е т дополнительная инфор
А за т е м добавляем сообщение к с т р а - ' м ация, поэт ом у мы добавляем его
нице для уведомления пользователя. в нашу ст року error.Message.

дальше ► 211
П р е ж д е чем вы полнить тест, более пристально взглянем на типы о ш и б о к ,
ко то р ы е м о гу т вы водиться на экр ан .
Это общая ошибка, которая выводится в с и т у а ­
циях, когда ни одна из остальных ошибок не под-
ходит. О брат ит есь к свойству error message
va r e rro rT y p e s = { J для получения дополнительной информации.
"U n k n o w n e rro r" , — Это означает, что пользователь от ка-
" P e r m is s io n d e n ie d by u s e r" , ^ запросе на разрешение использовать
" P o s itio n is no t a v a ila b le
информацию о местоположении.
А это означает, что браузер попытался,
"R e q u e s t tim e d o u t"
но не смог определить ваше м ест ополо-
У' \ жение. О пят ь-т аки, для получения до-
И наконец, A P I -интерфейс Geolocation полнительной информации обратитесь
предусматривает такую внутреннюю к свойству error.message,
настройку, как время ожидания (timeout), г- . Л Л Л
и если оно истекает до того, как будет Позже 6 этой главе вы Узнает е>как изменять
определено местоположение, выводится значение tim eout, задаваемое по умолчанию
данная ошибка. в случае API-интерфейса Geolocation.

Набрав диагностический тест, запустите его. Если вы получите


координаты местоположения, значит, все работает нормаль­
но, и никаких сообщений об ошибках выводиться не будет.
Вы можете форсировать вывод сообщения об ошибке, отказав
браузеру в его запросе на разрешение использовать инфор­ *7®/ отв.*,,с
** O' [(£> Q
мацию о вашем местоположении. Либо вы можете проявить
T im e d o u t
более творческий подход: например, войти в помещение
HOCtjf QHyLgmltm
со своим телефоном, поддерживающим GPS, что приведет *■ -> С fl [Q ■■• G - S 1 ^
к пропаданию GPS-сигнала от сети спутников. P e rm issio n d e n ie d by u s e r
В наихудшем случае, если вы долго ждете, но данные о ме­
стоположении так и не поступают и не выводится никаких
сообщений об ошибке, то, скорее всего, для tim eout задано
большое значение, то есть время ожидания будет продолжи­
тельным. Чуть позже в этой главе мы расскажем, как сократить
длительность ожидания.

Укажите здесь результаты проведенной вами диагностики


□ Я не давал разрешения использовать информацию о моем местоположении.
| | Мое местоположение оказалось недоступно.

□ Я получил сообщение о том, что время ожидания ответа на запрос истекло.

□ Вообще ничего не произошло — я не получил ни координат местоположения,


ни сообщения об ошибке.
□ Нечто другое______________________________________
создание HTML-ст раниц с поддерж кой определения мест оположения

а
буд ьте
Для тестирования своего геолокаци-
онного кода на мобильном устройстве
Част°
ЧаДаВаеМые
B oD poC fci
вам потребуется сервер.
o O H o j= > o JK H bi
Если у вас нет средств загрузки своих
HTML-, JavaScript- и CSS-файлов напря­
5 =Значения широты и долготы моего
местоположения,
мест возвращаемые прило­
мую на мобильное устройство, то их жени
жением, не совсем точны. В чем же дело?

будет проще всего протестировать, разместив на сервере


Существует масса методик, посред­
(загляните в следующую главу, чтобы узнать, как установить 0:
свой собственный сервер в случае необходимости), и обра­ ством которых ваше устройство и поставщик
услуг по определению местоположения вы­
щаться к ним уже там. Если же у вас имеется сервер и вы
числяют место, где вы находитесь; при этом
решите именно так и поступить, мы полностью вас под­
одни из них дают более точный результат,
держиваем. С другой стороны, если данный вариант вам не чем другие. GPS зачастую позволяет полу­
подходит, знайте, что мы разместили соответствующий код чать самые точные показатели. Мы с вами
на серверах Wickedly Smart, так что вы сможете провести те­ рассмотрим способ определить уровень точ­
стирование с использованием своих мобильных устройств. Мы ности данных, возвращаемых локационной
также рекомендуем вам сначала протестировать код на своем службой как часть объекта position, благо­
настольном компьютере; если все будет нормально работать, даря чему вы сможете понять, насколько
переходите к его тестированию на мобильном устройстве, точные данные о местоположении можно
используя сервер (свой собственный или Wickedly Smart). получить.

При проведении первого тест-драйва (включая диагности­


рование ошибок) вводите на своем устройстве адрес http://
wickedlysmart.com/hfhtml5/chapter5/latlong/myLoc.html.

Раскрываем наше тайное убеЖище...


Теперь, когда вы изучили осповы, сделаем кое-что более ин
тереспое в плапе определепия м естополож епия. Как пасчет
того, чтобы узпать, пасколько далеко вы паходитесь от пашего
тайпого убежища — штаб-квартиры Wickedly Smart? Д ля этого
пам потребую тся ко о р дипаты даппой ш таб-квартиры, а также
зпапие того, как вы числяется расстояпие между двумя коор
дипатами. Спачала добавим еще одип элемепт <div> в HTML:

Координаты ш т а б -
<body> квартиры Wickedly Sm art.
< d iv id = " lo c a tio n " > 4 7 .6 Я 4 8 5 ,
Your lo c a t io n w ill go h e re .

< /d iv >
< d iv id = " d is t a n c e " >
D is ta n c e fro m W i c k e d l y S m a r t HQ w i l l go h e re .

< /d iv >
< /b o d y > ^
< /h tm l> Добавьте э т о т новый элем ент <div> в свой HTML

дальш е ► 213
пригот овленны й код для вы числения расст ояния

у-1ojpoBo х у п о т р е б л е н и е ; вы чи сл я е м р а с с т о я н и е _________________________

Вам когда-нибудь хотелось узнать, как вычисляется расстояние между двумя


точками на поверхности планеты? Подробности этого процесса покажутся вам
весьма любопытными, однако они лежат немного вне рамок данной главы. По­
этому мы заранее приготовили для вас код, который просто выполняет эту зада­
чу. Для вычисления расстояния между двумя координатами в большинстве слу­
чаев применяется формула гаверсинуса, реализация которой приведена ниже.

Данная функция прини м ает две точки


координат — начальную (startCoords)
и конечную (destCoords) — и возвращает
расстояние между ними в километрах.

fu n c tio n c o m p u te D is ta n c e ( s ta r tC o o r d s , d e s tC o o rd s ) {

va r s ta rtL a tR a d s = d e g r e e s T o R a d ia n s ( s ta r tC o o r d s . l a t i t u d e ) ;

va r s ta rtL o n g R a d s = d e g r e e s T o R a d ia n s ( s ta r tC o o r d s . l o n g i t u d e ) ;

va r d e s tL a tR a d s = d e g r e e s T o R a d ia n s ( d e s tC o o r d s . l a t i t u d e ) ;

va r d e s tL o n g R a d s = d e g re e s T o R a d i a n s (d e s tC o o r d s . 1 o n g i t u d e ) ;

va r R a d iu s = 6371; / / радиус Земли в кил о м е тр а х

va r d is ta n c e = M a th , a c o s (M a th , s i n ( s t a r t L a t R a d s ) * M a th , s i n (d e s tL a tR a d s ) +

M a th .c o s ( s ta rtL a tR a d s ) * M a th .c o s (d e s tL a tR a d s ) *

M a th .c o s (s ta rtL o n g R a d s - d e s tL o n g R a d s ) ) * R a d iu s ;

re tu rn d is ta n c e ;

fu n c tio n d e g r e e s T o R a d ia n s ( d e g r e e s ) { 3w y ф ун кц и ю МЫ ещ е у в и д и м в г л а в е ,
va r r a d ia n s = (d e g re e s * M a th .P I)/1 8 0 ; посвященной элем ент у canvas.
re tu rn r a d ia n s ;

Добавьт е данный код в свой файл myLoc.js.

214 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

М ы хоидиМ вь1Иислиидь
Написание кода для определения расстояния р а с с т о я н и е оил б а с
до н а с то п р я м о й

Теперь, когда у пас имеется фупкция для вы числепия расстояпия между дву­
мя точками коордипат, определим паше (то есть пас, авторов) местополо­
ж ение —коордипаты ш таб-квартиры Wickedly Sm art (паберите и этот код)::
С
Определяем литеральный объект
var ourCoords = { у для координат местоположения
latitude: 47.624851, нашей ш т аб-кварт иры Wickedly
longitude: -122.52099 S m art. Добавьт е его как глобаль­
ную переменную в верхнюю часть
};
своего файла myLoc.js.

А теп ерь папиш ем код: все, что пам потребуется сделать, — это передать
коордипаты вашего и паш его местополож епия фупкции com puteD istance:

f u n c t io n d is p la y L o c a tio n ( p o s itio n ) {
v a r la titu d e = p o s itio n .c o o r d s . la t it u d e ;
v a r lo n g it u d e = p o s i t i o n . c o o r d s . l o n g i t u d e ;

v a r d i v = d o c u m e n t .g e t E le m e n t B y ld ( " l o c a t i o n " ) ;
d iv .in n e r H T M L = "Y o u a r e a t L a t i t u d e : " + la titu d e + ", L o n g it u d e : " + lo n g it u d e ;
Передаем координаты ваш е­
го и нашего местоположения
v a r km = c o m p u t e D is t a n c e ( p o s it io n . c o o r d s , o u r C o o r d s ) ;
функции computeDistance.
v a r d is t a n c e = d o c u m e n t. g e tE le m e n tB y ld ( " d is t a n c e " ) ;
d is ta n c e .in n e r H T M L = "Y ou a r e " + km + " km fr o m th e W ic k e d ly S m a rt HQ";

А за т е м берем резу л ьт а т ы и обновляем со­


держимое элемент а <div> с id в виде distance.

Локационный тест-драйв
П роведем тест-драйв пашего пового кода. Заверш ите добав­
ление кода в myLoc.js, а затем перезагрузите myLoc.html
в своем браузере. П осле этого вы долж пы увидеть коордипа­
ты вашего местополож епия, а также расстояпие, па котором
You are at Let,tude: 4 7 .6 2 4 6 5 ,. Longitude: -12 2.5 20 99
паходитесь от пас. You are 0 km from the W ickedlySm art HQ

Ваше местоположение и расстояние от -


ш т аб-кварт иры Wickedly S m a r t явно б у ­
дет отличаться в зависимости от т ого,
в какой точке планеты вы находитесь.

Проведите тестирование онлайн: h t t p : / / w ic k e d l y s m a r t.c o m / h f h t m l S / c h a p te r s/d is ta n c e /m y L o c .h tm l

дальш е ► 215
добавление google maps

Да, знать координа­


ты своего местоположения в виде
34.20472, -9 0 .5 7 5 2 8 — это, конечно,
здорово, однако в данный момент как
нельзя кстати пришлась бы карта!

Отображение Вашего местоположения на


Как мы уже отмечали, API-иптерф ейс G eolocation довольпо п рост — оп позволяет вам
определять (и, как вы еще увидите, отслеживать) то, где вы паходитесь, одпако пе преду­
см атривает пикаких ипструмептов для визуализации вашего местополож епия. Д ля это­
го пам придется обратиться к стороппему ипструмепту, и, как вы уже могли догадаться,
Google Maps —паиболее популярпое средство для реш епия даппой задачи. Google Maps
пе является частью специф икации HTML5, одпако мож ет отличпо взаимодействовать
с HTM L5, поэтому мы пе прочь пемпого отклопяться кое-где от пашего марш рута и по­
казывать вам, как иптегрировать Google Maps с API-иптерф ейсом G eolocation. Н апри ­
мер, вы мож ете пачать с добавлепия приведеппого пиж е кода в <head> своего HTML-
докумепта, а чуть позже мы поговорим о том, как можпо добавить карту к страпице:

< s c r ip t s r c = Mh t t p : / / m a p s . g o o g l e . c o m / m a p s / a p i / j s ? s e n s o r = t r u e " X / s c r i p t >

^ ^ Убедитесь, что вы набрали данный код точно,


Здесь находится A P I-инт ерф ейс как ,д оказано здесь, включая п а р ам е т р за п р о -
JavaSciript Google Maps. са sens0r (API-инт ерф ейс не будет без него рабо­
тать). Мы указали sensor-true, поскольку наш код
задейст вует ваше местоположение. Если бы мы
просто использовали ка рт у без вашего м е с т о п о л о ­
жения, то напечатали бы sensor-false.

216 глава 5
Ж^Отклоняемю
Как добаВить карту к странице от маршрута

Теперь, когда вы указали ссылку па API-иптерф ейс Google Maps, все его возмож пости будут доступпы
вам посредством JavaScript. Одпако пам потребуется место для разм ещ епия карты Google, для чего пе­
обходимо определить элемепт, которы й будет ее содержать.

<body>
< d iv id = " lo c a tio n " >
Your lo c a t io n w ill go h e re .
< /d iv >
< d iv id = " d is t a n c e " >
D is ta n c e fro m W ic k e d ly S m a r t HQ w i l l go h e re .
< /d iv >
< d iv id = "m ap "> , В о т н а ш <div>. С л е д у е т о т м е т и т ь , ч т о м ы о п р е д е л и л и
с т и л ь в m y L o c . j s , к о т о р ы й з а д а е т для э л е м е н т а <div> с id
1V й gu de т а р р а з м е р 4 0 0 на 4 0 0 п и к с е л о в и ч е р н у ю р а м к у .
< /b o d y >
< /h tm l>

Подготовка к созданию к а р т ы ...


Д ля создапия карты пам потребую тся ш ирота и долгота (а мы уже зпаем, как их извлечь), а также па-
бор парам етров, описывающ их, какой имеппо долж па быть паш а карта. Н ачпем с ш ироты и долготы.
Мы зпаем, как извлекать их посредством API-иптерф ейса G eolocation. П ри этом следует отметить, что
API-иптерф ейс Google Maps предпочитает, чтобы опи были «упаковапы» в его собствеппы й объект.
Д ля создапия одпого из таких объектов мы можем воспользоваться копструктором, предусматривае-
мым API-иптерф ейсом Google Maps: Не з а б ы в а й т е , ч т о и м е н а к о н с т р у к т о р о в
должны начинаться с прописной буквы.
va r g o o g le L a tA n d lio n g = new g o o g le .m a p s . L a t L n g ( l a t i t u d e , l o n g i t u d e ) ;_______ J

google.maps ст авит ся пеюед ^ ^ з


и м е н а м и всех м е т о д о в A P I - J К о н с т р у к т о р , кот орый п р и н и м а ет ш и р о т у и долгот у
интерфейса Google Maps. м в°звРаи4ает новь'й o5veKm’ где они содержаться.
API-иптерф ейс Google Maps обеспечивает паличие парам етров, которы е мы можем задавать с целью
коп троля итогового вида паш ей карты. Н априм ер, можпо указать, пасколько увеличеппым или умепь-
ш еппым будет исходпое пред став лепие карты , какое м естополож епие будет отображ аться в ее цептре,
какого типа будет карта (папример, ROADMAP), предусмотреть представлепие Satellite (Спутпик) и т. д.
П арам етры задаются следующим образом:
Д ля п ара м ет р а zoo m можно указывать значение о т О до 2-1. Поэкспе­
р и м е н т и р у й т е с ним: более высокие значения с о о т вет ст в ую т больше­
м у увеличению (то есть вы сможете р а ссм от рет ь больше деталей).
va r m a p O p tio n s = Значение Ю подразумевает , т ак сказат ь, размер «с город».
zoom : 10, ^ ---- Новый объект, который мы только что создали. Мы ко т им ,
c e n te r: g o o g l e L a t A n d L o n g , чтобы данное местоположение отображалось в центре карты.

m a p T y p e ld : g o o g l e .m a p s . М а р Т у р е I d . ROADMAP Вы также МОЖете попробовать под-


}; ст а ви т ь сюда SATELLITE или HYBRID.

дальш е ► 217
код для от ображения карт ы Отклоняемся
от маршрута
Отображение карты
Соберем все воедипо в п овой фупкции с имепем showMap, которая при-
п им ает пабор коордипат и отображ ает карту па веб-страпице:
Объявляем глобальную переменную т а р >которая будет со-
va r ш ар; держать нашу к арт у Google после т ого, как мы ее создадим.
Ч ут ь позже вы увидит е, как она используется.

fu n c tio n s h o w M a p (c o o rd s ) { _____ Задействуем ш ирот у и дол­


va r g o o g le L a tA n d L o n g = OL гот у из объекта coords...
new g o o g le .m a p s . L a t L n g ( c o o r d s . l a t i t u d e ,
c o o r d s . lo n g itu d e ) ...и применяем их
для создания объекта
va r m a p O p tio n s = {
google, maps.LatLng.
zoom : 1 0 ,-

c e n te r : g o o g le L a tA n d L o n g f Создаем объект mapOptions


m ap T y p e I d : g o o g l e . m a p s . M a p T y p e l d . ROADM AP
с п а р а м е т р а м и >которые х о ­
т и м задать для нашей карты.
>;
va r m a p D iv = d o c u m e n t. g e tE le m e n t B y ld ( "m a p ") ; И наконец, извлекаем т а р.Div
m ap = new g o o g l e . m a p s .M a p ( m a p D i v , m a p O p tio n s ) из объектной модели документа
(РОМ) и передаем его вмест е
FT с mapOptions к онст рукт ору
' ^ Еще один конст рукт ор из API - Мар с целью создания объекта
Присваиваем новый интерфейса Google Maps>к о т о - google.maps.Map. Посредством
объект Мар нашей рыи при ним ает элем ент и наши него на нашей странице будет
глобальной п е р е - п а р а м е т р ы , после чего создает отображаться карта.
менной тар. и возвращает объект тар.
Добавьте даппы й код в пижпю ю часть своего JavaScript-файла. Затем остапется лиш ь присоединить
его к уже имеющемуся у пас коду. Сделаем это путем редактирования фупкции d is p la y L o c a t io n :
fu n c tio n d is p la y L o c a tio n ( p o s itio n ) {

va r la titu d e = p o s it io n . c o o r d s . la t it u d e ;

va r 1 o n g i tu d e = po s i t i o n . c o o rd s .1 o n g i tu d e ;

va r d iv = d o c u m e n t . g e t E le m e n t B y ld ( " l o c a t i o n " ) ;

d iv .in n e r H T M L = "Y o u a re a t L a titu d e : " + la titu d e + L o n g itu d e : " + lo n g itu d e ;

va r km = c o m p u te D is ta n c e ( p o s i t i o n , c o o r d s , o u rC o o rd s ) ;

va r d iv = d o c u m e n t . g e t E le m e n t B y ld ( " d i s t a n c e " ) ;

d i s t a n c e . in n e r H T M L = "Y o u a re " + km + " km fro m th e W ic k e d ly S m a r t H Q ";

show M ap ( p o s i t i o n . c o o r d s ) ;
Ъудем вызывать showMap из displayLocation после
т ого, как обновим остальные <div> на странице.

218 глава 5
Tecm-gpauB нашей новой карты
У б ед и тесь, ч то вы д о б а в и л и весь А вот и наша
повы й код с предыдущей страницы , новая карта
а также элемент < d iv > с i d в виде тар V/
Google
в свой HTM L. Затем п ерезагрузите
веб-страницу, и если браузеру удастся
о п р ед ел и ть ваш е м естоп олож ен и е,
вы увидите карту.

Здесь демонстрируется м ест о­


положение велосипедиста с коор­
динатами 3 4 .Я 0 4 7 Я , -<40.57522,
вы, естественно, скорее всего оу
дете находиться в другом месте.

Здорово! А есть ли
способ увидеть мое точное
местоположение на карте?
Отмеченное, например,
булавкой?

3t?i действительно
х о т и т е , чтобы эта
штука валялась рядом
с вашим велосипедом?

Проведите тестирование онлайн: h t t p : / /w ic k e d l y s m a r t.c o m / h f h t m l S / c h a p te r s / т а р / m yLoc.htm l

дальш е ► 219
добавление маркера google
Отклоняемся
от маршрута
ПрикалыВаем булаВку на карту...
Будет пампого лучше, если вы сможете увидеть па карте
свое точпое м естополож епие. Если вам доводилось поль­
Space Needle ;J
зоваться Google Maps, то вы, вероятпо, видели, что там ме­ 219 4th Avenue North
стополож епие искомых ф изических объектов отмечается Seattle, WA 98109
(206) 9Q&-21&Q
spaceneedlB.com
с помощью своего рода булавок. Н априм ер, если вы ищ е­ **** 28reviews
те башпю Space N eedle («Космический шпиль») в Сиэтле,
Directions Search nearby Save to
ш тат Вашипгтоп, то система поиска выдаст вам карту, где map more Y

рядом с этой баш пей в городе будет «приколота» булавка,


щелкпув па которой вы увидите ипф орм ац иоп п ое окпо с
подробностям и о даппом сооружепии. Эти булавки назы ­
ваю тся маркерами и являю тся одпой из мпогих возмож но­
стей, которы е предлагает АРI-иптерф ейс Google Maps.
Д обавлепие м аркера с всплывающим ипф орм ациоппы м Если вы и щ е т е какой-либо объект в Google
окпом потребует паписапия пекоторого кода, поскольку кM a p s , т о его местоположение на карт
вам будет пеобходимо создать сам маркер, ипф орм ац иоп ­ будет отмечено красным маркером.
пое окпо и обработчик собы тий click, инициируем ы е при
щ елчке пользователя па даппом м аркере (что приводит к
откры тию окпа). Поскольку мы отклопяемся от маршрута,
па рассм отрение даппого аспекта потратим пе мпого вре-
мепи, тем более, что у вас уже имею тся все пеобходимы е
зпапия, чтобы без особого труда во всем разобраться!

<£> Начнем с создания новой функции a d d M a r k e r , после чего воспользуемся


A P I-интерсрейсом Google Maps для создания маркера:
функция addM arker п рини м ает т а р , latlong, title, для м а р ­
кера, а также co n te n t для информационного окна.
J V \ 'ч ,
fu n c tio n a d d M a rk e r(m a p , la tlo n g , t it le , c o n te n t) {

va r m a r k e r O p tio n s = {

p o s it io n : la tlo n g , Создаем объект markerOptions с latlong, m a p и title


4- a макже указываем, к о т и м ли мы, чтобь/ пользова­
m ap: m ap, т ель имел возможность щ елкнут ь на маркере...

t it le : t it le ,
...задаем для clickable значение true, поскольку к от и м ,
c lic k a b le : tru e гчтобы пользователь мог щелчком на маркере выво-
FZ ' дить информационное окно.
>;

va r m a rk e r = new g o o g l e .m a p s . M a r k e r ( m a r k e r O p t i o n s )

^ З а т е м создаем объект m arker, используя еще один конст рукт ор из API -ин т ер-
фейса Google Maps, ко т ором у передаем ранее созданный объект markerOptions.

220 глава 5
Отклоняемся
0 П»р«ру»

(5 } Создадим информационное окно путем определения специфичных для него парамет­


ров, после чего сгенерируем новый объект InfoWindow с помощью A P I-интерфейса
Google Maps. Добавьте приведенный ниже код в свою ф ункцию addMarker:

fu n c tio n a d d M a rk e r(m a p , la tlo n g , t it le , c o n te n t) {

; Млшостальной кодпо-преж нему здесь, мы просто экономим место...

А теперь определяем парамет ры


tг информационного окна.
va r i n f o W in d o w O p tio n s = {

co n ten t: co n ten t, ^— Н а м п о т р е б у е т с я содерж имое...

p o sitio n : la tlo n g ^ ^
------------ ...а т акж е ш и р о т а и долгот а.
>;

va r in fo W in d o w = new g o o g l e . m a p s . I n f o W i n d o w ( i n f o W in d o w O p t i o n s ) ;

С п о м о щ ь ю эт о го м ы создаем
и н ф о р м а ц и о н н о е окно.
g o o g le .m a p s . e v e n t . a d d L i s t e n e r ( m a r k e r , " c lic k " , f u n c t i o n () { ^

i n f o W i n d o w . o p e n (m a p ) ; ^ f ^
/к П е редае м с л у ш а т е л я З а т е м мы и с п о л ь з у е м м е т о д
}>; / Ф ункции, к о т о р а я a d d U ste n e r A PI-инт ерф ейса
1 вы зы вае т ся, когда G o o g l e M a p s для добавления с л у -
} Когда пользоват ель щ е л - пользоват ель щ е л к а - ш а т е л я с о б ы т и и click. С л у ш а т е л ь
к а е т на м а р к е р е , п р о и с к о - е т на м а р к е р е . подобен о б р а б о т ч и к у со б ы т и и
д и т вы зо в д а н н о й ф у н к ц и и , ( н а п р и м е р , o n lo a d или on chck),
и на к а р т е о т к р ы в а е т с я с к о т о р ы м вы с т а л к и в а л и с ь р а не е.
и н ф о р м а ц и о н н о е окн о.

0 Осталось только вызвать функцию addMarker из showMap, убедившись, что мы пе­


редали все надлежащие аргументы для четырех параметров. Добавьте данный код
В НИЖ НЮ Ю ЧаСТЬ СВОеЙ ф уН КЦ И И showMap!

va r t it le = "Y o u r L o c a tio n " ;

va r c o n te n t = "Y o u a re h e re : " + c o o rd s . la titu d e + ", " + c o o rd s . lo n g itu d e ;

a d d M a rk e r(m a p , g o o g le L a tA n d L o n g , t it le , c o n te n t);

r ? < ,
П ередаем объ ект ы m a p
и g o o g le L a tA n d L o n g, создан- a такж е c m P 0KU t i t , e u c o n t e n t Здя м а р к е р а ,
ные с и с п о л ь з о в а н и е м A P I -
и н т е р ф е й с а Google Maps...

дальш е ► 221
больше google maps
Отклоняемся
от маршрута
Tecm-драйВ маркера
Щ « ► « CO ft
Добавьте весь код, касаю щ ийся addM arker, обповите showMap
для вы зова addM arker и перезагрузите страпицу. П осле этого вы I
увидите карту с маркером, указывающ им ваше местополож епие. 1 —

Щ елкпите па маркере кпопкой мыши. В результате этого по­ I ~


В ** "■
явится всплываю щ ее окпо, в котором будут отображ аться ш иро­
та и долгота вашего местополож епия.
Все это здорово, поскольку теперь вы мож ете точпо узпать,
где паходитесь (паприм ер, если заблудились).
Вот как будет выглядеть наша карта
с м аркером и всплывающим окном.
г
Проведите тестирование онлайн: h t t p : / /w i c k e d l y s m a r t .c o m / k f k t m l s / c h a p t e r S / m a r k e r /m y L o c .h t m l

Прочие интересные Вещи, которые моЖно сделать


с использованием A PI-интерфейса Google Maps
Мы лиш ь поверхпостпо затропули то, что можпо сделать с помощью Google Maps, подробпое изу­
чепие даппого API-иптерф ейса выходит за рамки пастоящ ей кпиги. Но у вас пе возпикпет сложно­
стей, если вы захотите сделать это самостоятельпо. П риведем ряд вещ ей, для реализации которы х
оп мож ет использоваться, а также пекоторы е подсказки для вас о том, с чего пачать.

Элементы управления: ваша карта Google по умолчанию будет включать несколько элементов управле­
ния, позволяющих, например, изменять масштаб, осуществлять панорамирование, переключаться между
представлениями Мар (Карта) и Satellite (Спутник) и даже просматривать улицы (позволяющий делать это
элемент управления выглядит как маленький оранжевый человечек над кнопками масштабирования). Вы
можете обращаться к этим элементам управления программно из JavaScript, чтобы использовать их в своих
приложениях.
Службы: вам когда-нибудь доводилось искать маршруты с помощью Google Maps? Если да, то вы пользо­
вались при этом службой Directions (Направления). Для обращения к этой и другим службам, позволяющим,
например, узнавать расстояние и просматривать улицы, вам потребуется прибегнуть к API-интерфейсам
Google Maps для работы со службами.
Слои: они позволяют размещать дополнительное представление поверх карты Google (например, карту по­
годы). Если вы собираетесь в поездку, то сможете проверить загруженность дорог транспортом с помощью
слоя трафика. Используя API-интерфейсы Google Maps, позволяющие работать со слоями, вы получаете
возможность создавать пользовательские слои (например, пользовательские маркеры, применять в слоях
свои фотографии) и делать массу всего другого, что только сможете себе представить.

Все это доступно посредством API-интерфейса JavaScript Google Maps. Если у вас возникнет желание пойти
еще дальше в своих экспериментах, изучите документацию по адресу:
h t t p : / / c o d e . g o o g l e . c o m /a p is /m a p s /d o c u m e n t a t i o n /j a v a s c r ip t /

222 глава 5
в с т р к Ч Л к М
Л Р 1 ~ И Ш ,Ё Р <Р Е р 1 .С
Интервью недели:
Разговор с тем, кто хочет стать
API-интерфейсом HTML5...

Head First: Добро пожаловать, API-интерфейс чина, по которой я стал первым API-интерфейсом,
Geolocation. Сразу хочу отметить, что немного удив­ которому была отведена отдельная глава?
лен видеть Вас здесь.
Head First: Давайте поговорим о поддержке.
Geolocation: Почему же?
Geolocation: Тут не о чем особо говорить, посколь­
Head First: Вы даже не являетесь «официальной» ча­ ку меня поддерживают почти все браузеры как в на­
стью спецификации HTML5, однако стали первым стольном, так и в мобильном сегменте.
API-интерфейсом, которому была отведена целая
глава в данной книге! Чем это объясняется? Head First: Какая от Вас польза на устройствах, кото­
рые не поддерживают GPS?
Geolocation: Что ж, Вы правы в том, что я опреде­
лен в спецификации, отдельной от HTML5, однако Geolocation: Это заблуждение, что я как-то зависим
являюсь официальным стандартом W3C. Оглянитесь от GPS. На сегодняшний день существует масса дру­
вокруг: я уже реализован в браузерах, устанавливае­ гих способов определять местоположение, напри­
мых на любом стоящем мобильном устройстве. Под мер посредством триангуляции с использованием
этим я подразумеваю следующее: будет ли много вышек сотовой связи и мобильного телефона, по­
пользы от мобильного веб-приложения, если оно не средством IP-адресов и т. д. Если в Вашем устройстве
поддерживает меня? есть GPS, то это здорово, поскольку в этом случае я
смогу быть для Вас еще более полезным; если же GPS
Head First: Какие приложения задействуют Вас?
отсутствует, то Вы всегда можете прибегнуть к массе
Geolocation: К их числу относится большинство других способов определения местоположения.
приложений, которыми люди пользуются в дороге:
Head First: Быть еще более полезным?
начиная с приложений, позволяющих обновлять
свой статус и включать геолокационную информа­ Geolocation: Если у Вас достаточно хорошее мо­
цию, и заканчивая приложениями для фотокамер, бильное устройство, то я смогу сообщить Вам еще и
фиксирующими то, где были сделаны снимки, а так­ высоту, направление, скорость, то есть все возмож­
же социальными приложениями, дающими возмож­ ные показатели.
ность отыскать местных друзей или отметиться в
разных местах. Люди используют меня даже для фик­ Head First: Допустим, что ни один из этих способов
сации того, где они ездили на велосипеде, бегали не сработал —ни GPS, ни IP-адрес, ни триангуляция.
или останавливались перекусить, а также для того, Какой тогда от Вас толк?
чтобы добраться до нужного пункта назначения. Geolocation: Что ж, я не всегда могу ручаться, что
Head First: Вы как API-интерфейс выглядите просто­ Вам обязательно удастся определить местоположе­
вато, то есть я хочу сказать, что у Вас в сумме имеется ние, однако есть и положительный момент — я даю
лишь несколько методов и свойств, ведь так? возможность выяснить причину проблемы. Все, что
Вам нужно сделать, —это дать мне обработчик оши­
Geolocation: В компактности и простоте заключена
бок, и я буду вызывать его в случае возникновения
мощь. Разве многие жалуются на меня? Нет. У меня проблем.
есть то, что нужно всем разработчикам, которые каж­
дый день создают массу приложений с поддержкой Head First: И это хорошо. Что ж, наше время истек­
определения местоположения. Кроме того, моя ком­ ло. Благодарю Вас, API-интерфейс Geolocation, за то,
пактность означает, что меня можно быстро и легко что посетили нас. И поздравляю с обретением стату­
освоить, не так ли? Может, в этом и заключается при­ са настоящего стандарта W3C!

дальш е ► 223
детали geolocation api

Возвращаясь к A PI-интерфейсу Geolocation...


Мы с вами уже прош ли довольпо длиппы й путь, используя
API-иптерф ейс Geolocation: мы определяли паше м естополо­
ж ение, вычисляли расстояпие до других объектов, обраба­
ты вали состояпия ошибки API-иптерф ейса и даже добавляли
карту с помощью API-иптерф ейса Google Maps. Одпако от­
дыхать еще рапо, поскольку мы только подош ли к рассм отре­
нию иптереспы х особеппостей API-иптерф ейса G eolocation.
Мы также приблизились к точке, которая отделяет человека,
зпающего о даппом API-иптерф ейсе, от того, кто мастерски
Geolocation
им владеет, поэтому пе будем останавливаться!
П реж де чем двипуться дальше, пам пеобходимо более при- getcurrentPosition
стальпо взглянуть па сам этот API-иптерф ейс. Как уже отмеча­ watchPosition
лось рапее, даппы й API-иптерф ейс довольпо п рост и вклю чает clearWatch
лишь тр и метода: g e t c u r r e n t P o s i t i o n (о пем вам уже кое-что A-
известпо), w a t c h P o s i t io n (подробпости о пем вы узпаете до­
вольпо скоро) и cle a r W a tc h (o n , как вы уже догадались, свя-
Методы, являющиеся частью
зап с w a t c h P o s i t io n ) . П еред тем как мы п ерей ти к этим двум
API -инт ерф ейса Geoiocation.
повы м методам, еще раз взгляпем па g e t c u r r e n t P o s i t i o n и
связаппы е объекты, такие как P o s i t i o n и C o o r d in a te s . Вы от­
кроете для себя то, о чем рапы не пе зпали. Вызов errorHandler происходит, когда
браузеру не удается определить м е с т о ­
положение пользователя. Как мы уже в и ­
дели, причин т о м у может быть немало.

getcurrentPosition(successHandler, errorHandler, positionOptions)

Как вы можете пом н ит ь, successHandleru


(или функция обратного вызова) вызыва­
I У нас также имеется новый п а рам е т р, который
мы еще не использовали, позволяющий н а с т р а и ­
вать поведение API -инт ерф ейса Geolocation.
ется, когда местоположение определено,
и ем у передается объект position. Вам уже знакомы latitude
и longitude, однако в объ­
екте coordinates имею т ся
и другие свойства.
Coordinates
Position
latitude Эти т ри гарант ирован-
coords _ но будут там: latitude,
longitude
timestamp
accuracy ongtitude и accuracy.
altitude
Вы уже знаете о свойстве coords, однако altitudeAccuracy
Остальные м о гу т как
в position также имеет ся свойство tim e s ta m p , heading s поддерживаться, так
содержащее значение времени создания объек­ speed и не поддерживаться, —
та position. Оно позволяет узнат ь, насколько это зависит от и сп оль­
ст ары м является местоположение. зуемого устройства.

224 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

МоЖем ли мы поговорить о точности?


О пределение местополож епия пе является точпой паукой. В зависимо­
сти от методики, прим епяем ой вашим браузером, вы сможете узпать
только штат, город и квартал города, в котором паходитесь. С другой
сторопы , если устройство будет более продвинутым, то вы сможете
определить собствеппое м естополож епие с точпостью до 1 0 метров,
вклю чая показатели своей скорости, паправлепия и высоты.
Так как же писать код, исходя из даппой ситуации? Разработчики API-
и п тер ф ей са G eolocation заклю чили с пами пеболы ной договор: каждый
раз, когда опи даю т пам коордипаты м естополож епия, опи также сооб­
щают пам их точпость в метрах в пределах 95%-пого уровпя достоверпо-
сти. Так, если бы мы пам сообщ или паше местополож епие с точпостью
до 500 метров, то мы могли бы быть достаточпо уверепы в его досто-
верпости, если пе выходить за пределы этих 500 метров. В таком случае можпо, паприм ер, давать
пользователям верпы е реком ендации отпосительпо города или его окрестпостей, по пе сообщ ать
им подробпы й уличпый маршрут проезда. В любом случае очевидпо, что ваше прилож епие будет
реш ать, как опо хочет использовать даппы е, касаю щ иеся точпости.
Но хватит разговоров, давайте взгляпем па точпость в случае с вашим текущим местополож ени­
ем. Как вы уже зпаете, ипф орм ация, касаю щ аяся точпости, является частью объекта c o o r d i n a t e s .
И звлечем ее, а затем используем в фупкции d i s p l a y L o c a t i o n .

fu n c tio n d is p la y L o c a tio n ( p o s itio n ) {

va r la titu d e = p o s it io n . c o o r d s . l a t i t u d e ;

va r 1 o n g i tu d e = p o s i t i o n . coo r d s .1 o n g i tu d e ;

va r d iv = d o c u m e n t. g e tE le m e n tB y ld ( " l o c a t i o n " ) ;

d iv .in n e r H T M L = "Y o u a re a t L a titu d e : " + la titu d e + ", L o n g itu d e : " + lo n g itu d e ;

d iv .in n e r H T M L += " ( w ith " + p o s it io n . c o o r d s . a c c u ra c y + " m e te rs a c c u ra c y )" ;

' Используем свойство accuracy,


va r km = c o m p u te D is ta n c e ( p o s i t i o n , c o o r d s , o u rC o o rd s ) ; которое добавляем в конец
va r d iv = d o c u m e n t . g e t E le m e n t B y ld ( " d is t a n c e " ); innerHTML элем ент а <div>.
d i s t a n c e . in n e r H T M L = "Y o u a re " + km + " km fro m th e W ic k e d ly S m a rt H Q ";

s h o w M a p ( p o s itio n .c o o r d s ) ;

Проверка точности
Убедитесь, что вы добавили приведепную выше выделепную строку
ко д ак своей страпице, после чего загрузите ее. В результате вы увидите,
пасколько точпо было определепо ваше местополож епие. Не забудьте
провести даппы й тест па имеющемся у вас мобильпом устройстве.
Тест онлайн: W ttp://wickedlys m a r t . c o m / k f k t m l 5 / chapters/accuracy/m yLoc.i

дальш е ► 225
от слеживание перемещ ения

«Wherever you go, there you are»


И сточпик происхож депия ф разы из заголовка (одпо из ее зпачепий: «Куда
бы ты пи шел —ты имеппо там», то есть в философ ском смысле здесь под­
разумевается, что от себя пе убежишь) горячо обсуждается. Н екоторы е
утверждают, что опа впервы е упомипалась в фильме «Бакару Бапзай»
(Buckaroo Banzai), в то врем я как другие полагают, что опа происходит из
дзеп-буддийских текстов, а третьи ссылаю тся па различпы е кпиги, прочие А к т о Лпо-ваш ем у,
кипоф ильм ы и популярпы е песпи. Н еваж по, что имеппо послужило ее ис­ прав в дебатах по
точником, главпое — опа была увековечепа, и тем более сохрапится после поводу источника
даппой главы, потому что мы п ревратим ее в пеболы ное веб-приложепие с происхождения дан­
соответствующ им имепем. Одпако пам потребуется пемпого участия с ва­ ной фразы? Исходит
ш ей читательской сторопы . она от веб-ресурса
Вам предстоит расш ирить свой текущий код таким образом, чтобы оп Banzai Institute или
смог отслеж ивать ваше перем ещ епие в реальпом времепи. Д ля этого мы же берет свое нача­
соберем все вместе, вклю чая два последпих метода, имею щ ихся в API- ло в дзен-буддийской
и п терф ей се G eolocation, и создадим п рилож епие, которое будет отслеж и­ л и т ер а т ур е?
вать ваше перем ещ епие в реж им е, близком к режиму реальпого времепи.

Как мы будем отслеживать ваше перемещение

Вы уже зпаете, что API-иптерф ейс G eolocation вклю чает метод w a t c h P o s it io n . Д аппы й метод делает
то, что подразумевает его имя: оп следит за вашим перем ещ ением и докладывает о вашем м естополо­
ж ении по мере того, как опо измепяется. М етод w a t c h P o s i t io n п а самом деле очепь схож с методом
g e t c u r r e n t P o s i t i o n , по ведет себя пемпого по-другому: оп повторпо вы зы вает обработчик успешпого
исполпепия каждый раз, когда изм епяется ваше м естополож епие. Д авайте посмотрим, как оп работает.

/ Т \ Ваше приложение /^ Ч w a t c h P o s i t io n «си-


вызывает метод дит» в фоне и посто­
w a t c h P o s i t i o n , передавая янно отслеживает ваше
ему функцию обработчика местоположение.
успешного выполнения.

Браузер p o s i t i o n .c o o r d s .l a t i t u d e

p o s i t i o n .c o o r d s .l o n g i t u d e

При изменении вашего ме-


w a t c h P o s i t io n будет про­
©: должать отслеживать ваше
стоположения watchPosition
вызывает функцию обработчика
местоположение (и доклады­
успешного исполнения для до­
вать о нем обработчику успешного
клада ей о вашем новом место­
исполнения) до тех пор, пока вы
положении.
не остановите отслеживание путем
вызова clea r W a tc h .

226 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

Приступаем к созданию приложения


В качестве отправпой точки мы возьмем приводивш ийся рапее
код; спачала добавим пару кпопок в HTML, чтобы можпо было
запускать и останавливать отслеж ивапие вашего м естополож е­
ния. Зачем вообщ е нужпы кпопки? П режде всего пользователи пе
хотят, чтобы их перем ещ епия отслеживались постояппо, и, как
правило, хотят иметь коптроль пад этой процедурой. Но есть и
вторая причипа: п остояппая проверка местополож епия па мо- -*
бильпом устройстве п отребляет мпого электроэпергии, и если
оставить ее активироваппой, это приведет к бы строй разрядке
аккумулятора. Поэтому мы в первую очередь обповим HTM L с це­
лью добавить форму и две кпопки: одну для зануска отслеж ивапия
вашего м естополож епия, а другую —для его остаповки.
Г
Отслеживание местоположения
< ! d o с ty p e h tm l> пользователя в режиме реального
< h tm l>
времени может пагубно сказаться
на уровне заряда аккумулятора.
<head>
Убедитесь, что вы предост авля­
< m e ta c h a r s e t = Mu t f - 8 M> ет е пользователям информацию
< t itle > W h e r e v e r you go, th e re you a r e < /title > об отслеживании их м е с т о п о л о ­
< s c r ip t s rc = "m y L o c . j s " X / s c r i p t > жения', а также средства к о н т р о ­
ля над этой процедурой.
< lin k r e l = Ms t y l e s h e e t " h r e f = Mm y L o c . c s s M>

< /h e a d >
Мы добавляем э л е ­
<body> м е н т form с двумя
< fo r m > кнопками, одна из
которы х, имеющая id
< in p u t ty p e = " b u tto n " id = " w a tc h " v a lu e = "W a tc h m e ">
в виде "watch", будет
< in p u t ty p e = "b u tto n " id = " c le a r W a tc h " v a lu e = " C le a r w a tc h " >
использоваться для
< /fo rm > запуска отслеживания,
< d iv id = " lo c a tio n " > а вт орая, с id в виде
Your lo c a t io n w ill go h e re .
"clearWatch", — для его
остановки.
< /d iv > ^

< d iv id = " d is t a n c e " > Снова воспользуемся нашими


прежними элем ент ам и <div>
D is ta n c e fro m W ic k e d ly S m a r t HQ w i l l go h e re .
для сообщения информации
< /d iv >
о местоположении в режиме
< d iv id = " m a p " > реального времени
< /d iv >

< /b o d y >

< /h tm l> Ч уть позже мы вернемся и п о за ­


ботимся о карте Google...

дальш е ► 227
использование w atchposition

Дорабатываем наш старый код...


Теперь пам пеобходимо добавить обработчики собы тий c l i c k , инициируем ы е при щ елчке па кпопке,
для двух паш их кпопок. Мы будем добавлять их в фупкцию g e tM y L o c a tio n только п ри паличии под­
держ ки API-иптерф ейса G eolocation. И поскольку мы собираемся полпостью контролировать геолока-
циоппое отслеж ивапие посредством двух кпопок, удалим существующий вызов g e t c u r r e n t P o s i t i o n из
g e tM y L o c a tio n . И так, удалим соответствующ ий код и добавим два обработчика: w a tc h L o c a tio n — для
кпопки, используемой для зануска отслеж ивапия, и c le a rW a tc h — для кпопки, прим епяем ой для оста-
повки отслеживапия: с ^ „
Е сли б р а у з е р п о д д е р ж и в а е т A P I - и н т е р ф е й с
^ — G e o lo c a tio n , т о м ы д о б а в л я е м о б р а б о т ч и к и с о -
fu n c tio n g e tM y L o c a tio n () { q/ б ы т и й click. В их д оба в ле нии не б у д е т с м ы с л а
i f ( n a v ig a to r .g e o lo c a tio n ) { в с л у ч а е о т с у т с т в и я т а к о й поддерж ки.
n a v i g a t o r . g e o l o e a f e i o n . g e fe C u g g e n fe P o s i f e i o n . ( d i a p l a y L o e a f e i o n , d i a p l a y E g g o g ) ;

va r w a tc h B u tto n = d o c u m e n t. g e tE le m e n t B y ld ( " w a t c h " ) ;

w a tc h B u tto n . o n c lic k = w a t c h L o c a t io n ;

va r c le a r W a tc h B u tto n = d o c u m e n t. g e tE le m e n t B y ld ( " c le a r W a t c h " ) ;

c le a r W a tc h B u tto n .o n c lic k = c le a r W a tc h ;

У Ъудем вы зы ват ь w a tchL o ca tion


e ls e { для з а п у с к а о т с л е ж и в а н и я ,
a l e r t ("O o p s , no g e o lo c a tio n s u p p o rt") ; й c l e a r W a tc h - для его о с т а -
новки.

Написание обработчике watchLocation


В о т ч т о м ы попы таемся сделать: когда пользователь паж имает кпопку с i d в виде " w a tc h " , оп хочет
пачать отслеж ивапие своего местополож епия. Поэтому мы воспользуемся методом g e o lo c a t io n .
w a t c h p o s it io n для зануска отслеж ивапия его м естополож епия. М етод g e o l o c a t io n . w a t c h p o s it io n об­
ладает двумя парам етрам и — обработчиком успешпого исполпепия и обработчиком ошибок, так что
мы сможем повторпо использовать обработчики, которы е у пас уже имеются. О п также возвращ ает
w a tc h ld , что мож ет использоваться в лю бой момепт для отмепы отслеживающ его поведепия. Мы п ри ­
прячем w a t c h ld в глобальпой перем еппой, которую используем, когда будем писать обработчик собы­
ти й c l i c k для кпопки, прим епяем ой для остаповки отслеж ивапия. Вот код для фупкции w a t c h L o c a tio n
и w a tc h ld , которы й вам пужпо добавить в m y L o c . j s:
va r w a tc h ld = n u ll; £ ___________ Д о б а в ь т е w a t c h l d в в е р х н ю ю ч а с т ь своего ф а й л а к а к г л о -
б а л ь н у ю п е р е м е н н у ю . М ы и н и ц и а л и з и р у е м ее з н а ч е н и е м null.
О н а п о т р е б у е т с я н а м позже для о с т а н о в к и о т с л е ж и в а н и я .
fu n c tio n w a t c h L o c a t io n () {

w a tc h ld = n a v ig a t o r . g e o lo c a t io n . w a t c h P o s it io n (d is p la y L o c a t io n ,
d is p la y E r r o r ) ;

В ы з ы в а е м м е т о д w a t c h p o s i t i o n , п е р е д а в а я е м у уже н а п и с а н н ы й о б р а б о т ч и к у с п е ш н о г о
и с п о л н е н и я d i s p l a y L o c a ti o n , а т а к ж е и м е ю щ и й с я у нас о б р а б о т ч и к о ш и б о к d isp la y E rro r.

228 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

Написание обработчика clearlVatch

Теперь паппш ем обработчик для остаповки отслеживапия. Д ля этого пам


потребуется взять w a tc h ld и передать его методу g eo l o c a t i o n . clea r W a tc h .

fu n c tio n c le a r W a t c h () { Убеждаемся, что у нас имеется w atch ld, а затем...


i f ( w a tc h ld ) {

n a v ig a t o r . g e o lo c a t io n . c le a r W a tc h ( w a tc h ld ) ; ^ ^ ...вызываем м ет од geolocation.
clearWatch, передав ему
w a tc h ld = n u ll;
watchld. Это приведет
} к остановке отслеживания.

Еще необходимо внести небольшое обновление в displayLocation...


Есть еще одпо пеболы ное обповлепие, которое пам нужпо вы полпить, и касается опо кода Google Maps,
паписаппого рапее. В даппом коде мы вызы ваем showMap для отображ епия карты Google (showMap ге-
перирует повую карту па веб-страпице). П ри этом пам пеобходимо, чтобы даппая процедура осущест­
влялась только одип раз. Одпако, как вы мож ете помпить, при запуске отслеж ивапия вашего местопо­
лож епия посредством w a tc h P o s i t io n обработчик d is p l a y L o c a t io n будет вы зы ваться каждый раз, когда
происходит обповлепие вашего местополож епия.
Ч тобы гараптировать, что вызов showMap состоится только одип раз, спачала проверим , существует ли
карта, и если опа отсутствует, то вы зовем showMap. В п ротивпом случае, если карта присутствует, это
будет озпачать, что вызов фупкции showMap уже происходил, карта была сгеперировапа, поэтому пам
пе пужпо вызы вать ее спова.

fu n c tio n d is p la y L o c a tio n ( p o s itio n ) {

va r la titu d e = p o s it io n . c o o r d s . l a t it u d e ;

va r 1 o n g i tu d e = po s i t i o n . c o o rd s .1 o n g i tu d e ;

va r d iv = d o c u m e n t. g e tE le m e n t B y ld ( " l o c a t i o n " ) ;

d iv .in n e r H T M L = "Y o u a re a t L a titu d e : " + la titu d e + ", L o n g itu d e : " + lo n g itu d e ;

d iv .in n e r H T M L += " ( w ith " + p o s it io n . c o o r d s . a c c u ra c y + " m e te rs a c c u ra c y )" ;

va r km = c o m p u te D is ta n c e ( p o s itio n .c o o r d s , o u rC o o rd s );

va r d is ta n c e = d o c u m e n t. g e tE le m e n tB y ld ( " d is t a n c e " ) ;

d i s t a n c e . in n e r H T M L = "Y o u a re " + km + " km fro m th e W ic k e d ly S m a r t H Q ";

i f (m a p = = n u ll) {

s h o w M a p ( p o s itio n .c o o r d s ) ;
Если функция showMap еще не вызывалась, следует
} вызвать ее; в прот ивном случае ее не нужно будет
вызывать при каждом вызове displayLocation.

дальш е ► 229
т ест ирование от слеживания пользоват еля

Пора отправляться в путь!


Убедитесь, что вы добавили весь п овы й код, и перезагрузите свою страпицу m y L oc.h tm l. Теперь, для
того чтобы по-пастоящему п ротести ровать даппую веб-страпицу, вам потребуется перем еститься са­
мим, чтобы обповить свое м естополож епие. П оэтому отправляйтесь па прогулку, прокатитесь па вело­
сипеде или автомобиле либо воспользуйтесь любым другим видом трапспорта.
С тоит ли говорить, что если вы будете тестировать даппое п рилож епие па своем пастольпом компью те­
ре, то опо покаж ется довольпо скучпым (так как вы пе сможете взять его с собой), поэтому вам следует
проводить тестирование с использованием мобильпого устройства. А если вам потребуется доступ со
своего мобильпого устройства к версии кода, разм ещ еппой оплайп, вы сможете пайти ее по адресу
http: / / w ickedlysm art.com /hfhtm l5 / chapter5 / watchm e / myLoc.htm l.

В о т наш т е с т о в * .« лрогон...

Эти показатели будут


обновляться по мере вашего
перемещения.

Следует о т м е т и т ь , что на
данный м о м е н т в центре карты
будет отображаться ваше н а ­
чальное местоположение...

Проведите тестирование онлайн: h t t p : / /w i c k e d l y s m a r t .c o m / h f h tm ls / c h a p t e r S / w a t c h m e /m y L o c .h t m l

230 глава 5
Часш°
ЧаДаВаеМые
В опросы

Как я могу регулировать частоту обновления браузером 0 : Нет гарантий, что эти свойства обязательно будут поддержи­
моего местоположения при использовании watchPosition? ваться (и, очевидно, их поддержка будет обеспечиваться только на
мобильных устройствах высшего класса), поэтому вам потребуется
Q j Никак. Браузер сам определяет оптимальную частоту обнов­ удостовериться в том, что ваш код сможет справиться с отсутствием

ления и судит о том, когда именно произошло изменение вашего их поддержки.

местоположения.
Что такое heading и speed?
В
Почему показатели моего местоположения изменяются
по нескольку раз при первой загрузке страницы, даже несмотря 0 : h e a d in g — это направление, в котором вы двигаетесь,
на то что я сижу на месте не перемещаясь? a s p e e d — скорость, показывающая, насколько быстро вы это
делаете. Представьте, что вы едете в автомобиле на север по ав­

0 : Помните, мы говорили, что браузер может применять разные томагистрали, а спидометр показывает 90 км/ч. Ваше направление
методики для определения вашего местоположения? В зависимости в данном случае — на север, а скорость равна 90 км/ч. Если же вы
от методики (или методик), используемой браузером для выяснения сидите в машине, стоящей на парковке, то ваша скорость равна О,
того, где вы находитесь, точность определения вашего местопо­ а направления у вас нет (поскольку вы не двигаетесь).
ложения со временем может изменяться. Как правило, точность
улучшается, но иногда (например, если вы заехали в сельскую Когда я проверяю по карте расстояние от своего место­
местность, где есть только одна вышка сотовой связи) может положения до вашего, у меня получается намного больший
ухудшаться. Кроме того, вы всегда можете задействовать свойство результат, чем рапортует приложение. В чем причина?
accuracy в объекте position.coords, чтобы следить за точностью.

0 : Как вы можете помнить, функция c o m p u te D is ta n c e вы­


Могу ли я использовать свойства altitude и altitudeAccuracy числяет расстояние по прямой. Ваш картографический инструмент,
объекта coordinates? скорее всего, выдает расстояние, которое придется проехать
на автомобиле по извилистому пути.

Возьми в руку карандаш


Ниже приведена альтернативная реализация для displayLocation. Сможете ли вы
догадаться, что она делает? Взгляните на нее и напишите свой ответ в самом низу.
Если в вас проснулась предприимчивость, то затем протестируйте данный код!

d i a t a n e e . i n n e rH T M L — " Y o u a re п— I— fem—I— M k m f r o m t h e W i e k e d l y D m a g t IIQ M ;


i f (k m < 0 .1 ) {
d is ta n c e .in n e r H T M L = " Y o u 'r e on fir e !" ;
} e ls e {
i f (p re v K m < km ) {
d is ta n c e .in n e r H T M L = " Y o u 'r e g e ttin g h o tte r!";
} e ls e {
d is ta n c e .in n e r H T M L = " Y o u 'r e g e ttin g c o ld e r ..." ;

}
}
p re v K m = km ;

д е л а е т в есь э т о т код. ^

дальш е ► 231
обзор объектов geolocation

Параметр positionOptions...
До пастоящ его момепта мы пе затрагивали трети й парам етр g e t c u r r e n t P o s i t i o n (и w a t c h p o s it io n ) —
p o s it io n O p t io n s . С помощью даппого парам етра мы можем контролировать, как API-иптерф ейс
G eolocation вы числяет соответствующ ие показатели. Д авайте взгляпем па три парам етра вместе с их
зпачепиям и по умолчапию.
Сначала идет свойство, которое а к т и в и р ует высо­
кую точность; что именно под э т и м подРаз^ ев
ется, м ьi поговорим через несколько мгновений...
var positionOptions = {
Параметр tim e o u t позволяет конт роли ро ва т ь,
enableHighAccuracy: false, как долго браузер сможет определять м е с т о ­
положение пользователя. По умолчанию для
timeout: Infinity, данного п ар ам ет ра задается значение Infinity,
то есть браузер получит столько времени,
сколько ему потребуется.
maximumAge: 0
Д л я данного пара м ет р а также можно задать
} значение в миллисекундах (например, ю ООО),
И наконец, с помощ ью п а ра м ет ра m a xim um A ge то есть браузер по луч ит Ю секунд на о п р е ­
устанавливаем максимальный « во зр а ст » данных деление местоположения, в прот ивном случае
о местоположении, который они м о гу т и м е т ь будет вызван обработчик ошибок.
до того, как браузеру пот ребует ся заново опре
делит ь местоположение. По ум олчанию данный
па р а м е т р и м е ет значение О, которое подраз­
ум евает , что браузеру придется всегда зано
во определять местоположение пользователя
(при каждом вызове getcurrentPosition).

Нельзя ли сноба поговорить о т о ч н о с т и ?

Вы уже видели, что все даппы е о м естополож епии, возвращ аемы е пам API-
иптерф ей сом G eolocation, включают свойство a c c u r a c y . Одпако мы также мо­
жем сказать API-иптерфейсу G eolocation, что хотим получать только паиболее
точпы е результаты, которы е оп способеп выдать. Но это будет лиш ь памек брау­
зеру, а различпы е реализации в действительности могут по-разпому отпоситься
к такому памеку. Н есм отря п а то что даппы й вариапт мож ет показаться мало-
важпым, оп песет в себе массу подтекста. Н априм ер, если вас пе иптересует
суперточпость результатов определепия м естополож епия — вам мож ет быть вполпе достаточпо зпать,
что ваш пользователь паходится в Балтиморе, —то API-иптерф ейс G eolocation сможет очепь быстро и
дешево (в плапе эпергопотреблепия) сообщ ить вам эти сведепия. С другой сторопы , если вы захоти­
те узпать улицу, па которой паходится ваш пользователь, то пет проблем, одпако в таком случае API-
иптерф ейсу G eolocation придется задействовать GPS и использовать массу электроэпергии для извле­
чен ия даппой ипф орм ации. П осредством парам етра en a b le H ig h A c c u r a c y вы говорите API-иптерфейсу
G eolocation, что вам пеобходимы паиболее точпы е результаты определепия м естополож епия, какие оп
только способеп дать, нусть даже и вы сокой цепой. И м ейте в виду: использование даппого п арам етра
пе гараптирует того, что браузеру обязательпо удастся выдать вам более точпое местополож епие.

232 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

Мир параметров timeout и maximumAge...


Еще раз взгляпем па то, что представляю т собой парам етры tim e o u t
и maximumAge.
timeout: сообщ ает браузеру, как д олго оп сможет определять место­
полож ение пользователя. Следует отметить, что если пользователю
будет предложепо одобрить запрос па определепие местоположепия,
то отсчет врем епи ож идапия пе пачпется до тех пор, пока оп пе даст
своего согласия. Если браузеру пе удастся определить повое м естопо­
лож ение в течепие врем епи в миллисекупдах, указаппого в зпачепии
t im e o u t , п р о и зой д ет вы зов об раб отчи ка ош ибок. Параметр timeout
по умолчанию имеет значение Infinity.
maximumAge: сообщает браузеру, пасколько у старевш и м и могут быть
даппы е о м естоп олож еп ии . Таким образом , если у браузера им ею тся д ан ны е о м есто­
п олож ении, которое было определепо 60 секупд пазад, а для maximumAge при этом задано
зп ачеп ие 9 0 0 0 0 (90 секупд), то вы зов g e t c u r r e n t P o s i t i o n п риведет к возврату уже имею щ ихся
кэш ироваппы х даппы х о местополож епии (то есть браузер пе стапет пы таться определить повое ме­
стополож ение пользователя). Одпако если в даппой ситуации для maximumAge будет задапо зпачепие,
равпое 30 секупдам, браузеру придется определять повое м естополож епие пользователя.

Таким образом, посредством maximumAge я могу устанавливать,


насколько часто браузер будет пересчитывать или определять мое ме­
стоположение. Я понимаю, что это позволит сделать мое приложение более
быстрым и энергоэффективным. А как насчет timeout? Как я могу использо­
вать данный параметр, чтобы сделать код лучше?

Вы правы в своих суждениях насчет maximumAge. Ч то касается t im e o u t,


следует рассуждать так: при использовании maximumAge вы получаете
стары е (кэш ированны е) данные, пока они остаю тся «моложе» значе­
ния, заданного для maximumAge, и это действительно помогает оптим и­
зировать производительность вашего прилож ения. Но что будет, ког­
да «возраст» данных о местополож ении превы сит значение, заданное
для maximumAge? В таком случае браузер попы тается извлечь данные
о новом местополож ении. Бы ть может, все это не будет слишком вас
беспокоить, наприм ер, вас устроят данны е о новом местополож ении,
если они есть у браузера, а если же их у него нет, то эти сведения не по­
требуются сию же минуту. Вы могли бы задать для tim eout значение 0,
и если у браузера будут данны е о м естополож ении, которы е проходят
«тест» maximumAge, то все отлично, в противном случае соответству­
ю щий вызов незамедлительно потерп ит неудачу и произойдет вызов
обработчика ош ибок (с кодом ошибки TIM EO UT). Это лиш ь прим ер
творческого подхода к использованию maximumAge и t im e o u t для па-
стройки поведепия вашего прилож епия.

дальш е ► 233
упражнение на использование парамет ров geolocation

+КТ 9 И Н Т^»Б Л а
т
1т ? _____
Ниже приведены параметры, касающиеся API-интерфейса Geolocation.
Ваша задача заключается в том, чтобы подобрать каждому параметру
пару в виде соответствующего ему поведения.

Мпе требую тся только кэш ироваппы е


{maximumAge:600000}
даппы е о м естополож ении, которы м
мепыне 10 минут. П ри отсутствии таких
даппы х я хочу получить даппы е о по-
вом м естополож епии, по только в том
случае, если па это уйдет 1 секупда или
мепыне.

{timeout:1000 , maximumAge :б00000 } Я буду использовать кэш ироваппы е дап­


пы е о м естополож епии, если таковы е
будут иметься у браузера, и при этом им
будет мепыне 10 минут; в противпом слу­
чае я хочу получить даппы е о повом ме­
стополож епии.

{timeout:0 , maximumAge :Infinity} Мпе требую тся только даппы е о повом


местополож епии. Браузер мож ет ис­
пользовать столько времепи па опреде­
ление м естополож епия, сколько ему по­
требуется.

{timeout:Infinity, maximumAge:0 } Мпе требую тся только кэш ироваппы е


даппы е о м естополож епии. М епя устро­
ят даппы е лю бого «возраста». Если кэ­
ш ироваппы е даппы е о м естополож епии
будут полпостью отсутствовать, про­
изойдет вызов обработчика ошибок.
Сведепия о повом местополож епии из­
влекаться пе будут! Д аппы е пастройки
предпазпачепы для использования в си­
туациях, когда речь идет об автопом пой
работе.

234 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

Как задавать параметры


Одпа из зам ечательпы х особеппостей JavaScript заклю чается в том, что если пам потребуется задать
целы й пабор парам етров в объекте, мы сможем сделать это, просто вставив литеральпы й объект прямо
посередипе вы зова метода. Допустим, пам пеобходимо активировать высокую точпость, а также задать
максимальпый «возраст» для даппы х о м естополож епии, равпы й 60 секупдам (60 ООО миллисекупд).
П ерем еппая o p t i o n s создается следующим образом: 0
г ^ ^ г уже начали з а м е -
v a r o p t i o n s = { e n a b l e H i g h A c c u r a c y : t r u e , m a x im u m A g e : 6 0 0 0 0 } ; г- j чат ь>Что JavaScript —
. это n o -настоящ ему
Затем мы можем передать o p t i o n s либо g e t Cur r e n t P o s i t i o n , n^ „
r круто? По крайней
либо w a t c h P o s i t i o n , как показало далее: '
м е р е } мы считаем
n a v ig a t o r . g e o lo c a tio n .g e tC u r r e n tP o s itio n ( именно так. ©
displayLocation, Передаем наши параметр*.

o p tio n s ) ; КГ <
литерального o o v -
И ли мы могли бы просто добавить соответствую щ ий объект как встроеппы й: екта прямо в вызов
n a v ig a t o r . g e o lo c a t io n . g e t C u r r e n t P o s it io n < Вы б у д е т е ч а с т о с т а л - функции! Н е к о т о р ы е
киваться с использова- с ч и т а ю т , что так
d is p la y L o c a tio n , / нием т акой методики будет прощ е, п о -
d is p la y E r r o r , в Ja vaS cript-коде. ц^~скольку код п о л у -
{e n a b l e H i g h A c c u r a c y : t r u e , m a x im u m A g e : 6 0 0 0 0 } ) ; ЧитСЯ более удобо­
читаемым.
Теперь, когда вы зпаете, что представляю т собой даппы е парам етры , что опи делают и как их задавать,
можпо переходить к их использованию . Этим мы и займемся далее, одпако пе забы вайте, что опи пред-
пазпачепы для пастройки вашего прилож епия, которое мож ет предъявлять свои специф ические тр е­
бования. Н а эти п арам етры также влияет используемое вами устройство, реализация браузера и сеть,
поэтому полпы м их исследованием вам придется запяться самостоятельпо.

— Диагностический тест-драйв ^
Ранее, при выполнении диагностических тест-драйвов, сталкивались ли вы с ситуациями, когда вы все ждали
и ждали, но ничего не происходило? Причина, скорее всего, заключалась в том, что для t i m e o u t было задано
значение I n f i n i t y . Другими словами, браузер будет бесконечно долго пытаться определить местоположение,
пока не столкнется с условием возникновения ошибок. Что ж, теперь вы знаете, как исправить это, поскольку
можете заставить API-интерфейс Geolocation вести себя более рационально в подобных ситуациях, задав соот­
ветствующее значение для t i m e o u t . Вот как это делается:
fu n c tio n w a t c h L o c a t io n () {

w a tc h ld = n a v ig a t o r . g e o lo c a t io n . w a t c h P o s it io n (
d is p la y L o c a tio n , З ад ав для t i m e o u t значение SOOO м и л л и с е ­
кунд ( S секунд), вы с д е л а е т е т а к , ч т о д р а у -
d is p la y E r r o r , ^ ^ ^ S y d e m бесконечно долго п ы т а т ь с я
определит ь местополож ение.
{ t im e o u t : 5 0 0 0 }) ;

} J
Проведите т ест ирование, подставляя сюда разные значения.

дальш е ► 235
г И С П Ы Т А Й Т Е С Ь с д е л а т ь э т о д о м а
(КА К ЗАСТАВИТЬ GEOLOCATION РАБОТАТЬ
НА ПРЕДЕЛЕ ВОЗМОЖНОСТЕЙ)
Разве не интересно узнать, как быстро браузер сможет определить ваше местопо­
ложение? Мы усложним для него задачу, насколько это представляется возможным:

■ активируем высокую точность;

■ не позволим ему использовать кэшированные данные о местоположении (за­


дав для maximumAge значение 0);

■ ограничим его по времени, задав для tim e o u t значение 100, которое будем
увеличивать после каждой неудачной попытки браузера определить местополо­
жение в течение заданного времени.

Предупреждение: мы не знаем, как долго продержится аккумулятор того или


иного устройства при определении местоположения на основе таких настроек,
поэтому используйте их на свой страх и риск!

Вот как будут выглядеть наши исходные параметры:


Mt?i начнем с этого...
{ e n a b le H ig h A c c u r a c y : tru e , tim e o u t: 100 , m a x im u m A g e : 0 } и если браузеру
не удастся опреде­
{ e n a b le H ig h A c c u r a c y : tru e , tim e o u t: 20 0 , m a x im u m A g e : 0 }
лить мест ополо­
жение, дадим ему
больше времени...
{ e n a b le H ig h A c c u r a c y : tru e , tim e o u t: 3 0 0 , m a x im u m A g e : 0 }

^ и т ак далее...
Теперь ознакомьтесь с кодом, приведенным на следующей странице, — он покажется вам довольно
интересным. Наберите его (можете добавить его в свой JavaScript-файл m yLoc. j s ). Протестируйте
данный код на различных устройствах, которые у вас имеются, а результаты запишите здесь:

ме\мь\ме yciMjpoutw о д 3j ect? у КаЖите время


3 десь по

На местоположение было определено з а миллисекунд

На. местоположение было определено за миллисекунд

На. местоположение было определено з а _____ миллисекунд

На местоположение было определено з а _____ миллисекунд

Тестирование онлайн: h t t p ://w ic k e d ly s m a r t.c o m /h fh tm ls /c h a p te r s /s p e e d te s t/s p e e d te s t.h tm l

236 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

var options = { enableHighAccuracy: true, timeout: 100, maximumAge: 0 };


window.onload = getMyLocation; Сначала мы инициализируем options
function getMyLocation() { при эт о м tim e o u t будет и м е т ь
if (navigator.geolocation) { значение Ю О , a m a X i m u m A g e O,
navigator.geolocation.getcurrentPosition (
displayLocation, ^ ^ Здесь по ст упаем как обычно : задей ст ву-
displayError , eM displayLocation и display Error в качестве
соот вет ственно обработчика успешного
op i o ns), 4- исполнения и обработчика ошибок — и п е р е -
} else { даем options в роли т р ет ьего параметра.
alert("Oops, no geolocation support");
}
> Первым делом разбираемся
function displayError(error) с обработчиком ошибок.
var errorTypes = {
"Unknown e r r o r " , Э т от код будет т ак им же,
"Permission d enied", как и прежде...
"Position is not available",
"Request timeout" /
};
var errorMessage = errorTypes[error.c ode];
if (error.code = 0 || error.code == 2) {
errorMessage = errorMessage + " " + error.message;
} 8 случае, если браузеру не
var div = document.getElementByld (" location" ) ; удастся определить м е с т о ­
div.innerHTML = errorMessage; положение, будем увеличивать
options .timeout += 100; ^ -- - значение tim e o u t на Ю О м и л ­
navigator.geolocation.getcurrentPosition (
лисекунд и давать ему п о ­
вт орную попытку. Мы также
di splayLocation,
уведомим пользователя о п о ­
displayError,
вторении попытки.
options);
div.innerHTML += " ... checking again with timeout= + options .timeout
}
function displayLocation(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var div = document.getElementByld("location");
div.innerHTML = "You are at Latitude: " + latitude +
", Longitude: " + longitude;
div.innerHTML += " (found in " + options.timeout + " milliseconds)
} 7^ Когда браузеру удастся определить местоположение пользователял
V. мы сооощим ему, сколько времени это заняло.
J
237
добавление п ут и на карт у

Шлифуем наше приложение!


Е с л и откинуться па спипку стула и призадуматься,
то мы с вами, используя пемпого HTM L и JavaScript,
создали веб-приложепие, которое способпо пе толь­
ко определять ваше местополож епие, по также от­
слеж ивать и отображ ать его почти в режиме реального
времени. Да, HTM L и вправду серьезпо подрос (как
и ваши п авы ки !).
Одпако если вести речь о даппом прилож епии, пе ка­
ж ется ли вам, что опо нуждается в пеболы ной шли­
фовке с целью придапия ему заверш еппого вида?
Н априм ер, мы могли бы сделать так, чтобы ваше ме­
стополож епие отображ алось па карте по ходу п ере­
мещения; кром е того, мы могли бы п ойти еще даль­
ше и показы вать места, где вы были, то есть па карте
будет отображ аться ваш путь.
Н апиш ем фупкцию для того, чтобы ваше м естополо­
ж епие продолжало отображ аться в ц еп тре карты по
мере вашего передвиж епия. Будем добавлять повы й
маркер, отмечая каждое повое местополож епие.
будем вызывать данную
И т а к,

ф ункцию и Iпередавать ей соот Данные координаты будут указы ват ь на ваше


вет ст вую щ ие координаты. Г~ самое, последнее местоположение, которое мы
( Jy ст анем отображать в центре к ар т ы , а также
о т м е т и м его м ар кер о м .
fu n c tio n s c r o llM a p T o P o s itio n ( c o o r d s ) { Сначала извлечем новые ш ирот у
va r la titu d e = c o o rd s . la titu d e ; u долгот у и создадим для них объ-
ект google.maps.LatLng.
va r lo n g itu d e = c o o rd s . lo n g itu d e ;

va r la tlo n g = new g o o g le .m a p s . L a t L n g ( l a t i t u d e , lo n g itu d e ) ;

Метод panTo объекта m ap п риним ает объект LatLng


m a p .p a n T o ( la tlo n g ) ; и прокручивает карт у т ак им образом, чтобы ваше
новое местоположение отображалось в ее центр.
a d d M a rk e r(m a p , la tlo n g , "Y o u r new lo c a t io n " , "Y o u m oved to :

la titu d e + ", " + lo n g itu d e ) ;

И наконец, добавляем м аркер для о т м е т к и вашего нового местоположения,


используя ф ункцию addMarker, написанную нами ранее, которой передаем
т ар, объект LatLng, заголовок и содержимое для нового маркера.

238 глава 5
создание HTML-ст раниц с поддерж кой определения мест оположения

интеграция нашей новой функции


Н ам остапется лишь обповлять фупкцию d is p l a y L o c a t io n для
вы зова s c r o llM a p T o P o s it io n каждый раз, когда изм епяется
ваше местополож епие. Н е забы вайте, что при первом вызове
d is p l a y L o c a t io n мы вызы ваем showMap для геп ери ровап ия кар­
ты и отображ епия маркера, отмечаю щ его ваше пачальпое место­
полож епие. Каждый раз после этого пам потребуется вызы вать
s c r o llM a p T o P o s it io n для добавлепия пового м аркера и цептри-
р овап ия карты запово. Вот как будет выглядеть обповлеппы й код:
function displayLocation(position) {
var latitude = position.coords.latitude;
var 1ongi tude = po s i ti o n .coo r d s .1ongi tude;
var div = document.getElementByld("location");
div.innerHTML = "You are at Latitude: " + latitude
+ ", Longitude: " + longitude;
div.innerHTML += " (with " + position.coords.accuracy + meters accuracy)";
var k m = computeDistance(position.coords, ourCoords);
var distance = document.getElementByld("distance") ;
distance.innerHTML = "You are " + k m + km from the WickedlySmart HQ" ;
При первом вызове displayLocation нам необ­
if (map == null) { ходимо сгенерировать и отобразить к а р т у ,
showMap(position.coords) ;
а также добавить первый маркер.
} else { После этого останется лишь добавлять
scrollMapToPosition(position.coords); новые маркеры на имею щ уюся карту.

U еще раз... о®
П ерезагрузите свою страпицу и пачпите движепие...
г *
/\орожка из м а р к е ­
Ну как, вы черчивается па карте ваш нуть? Вы долж- ров, показывающая
пы увидеть дорожку из маркеров, добавляемы х па наш недавний п у т ь
карту по мере вашего передвиж епия (если, копеч- от ш т аб-кварт иры
по, вы пе сидите за пастольпым компью тером!). Wickedly S m a r t до
Таким образом, даппое прилож епие мы представля­ тайного подземно­
ем как твердое доказательство того, что «куда бы ты го логова... Ой, зря
пи шел —ты имеппо там» (в паш ем случае под этой мы проболтались
ф илософ ской ф разой попимается, что вас можпо об этом...
будет пайти).

Тестирование онлайн: h ttp ://w ic k e d ly s m a r t . c o m / h f h t m l s / c h a p t e r s / w a t c h m e p a n / т у Loc.html

дальш е ► 239
оптимизация использования маркеров

лечения с магнитами
Завершая эту главу, мы предполагаем, что вы можете захотеть
еще больше отшлифовать рассмотренное выше приложение. Вы
обратили внимание (в силу тех или иных обстоятельств) на то, что
на карту добавляется слишком много маркеров, когда ведется от­
слеживание вашего местоположения?
Это происходит потому, что w a t c h P o s i t i o n слишком часто детек­
тирует перемещение, что приводит к вызову обработчика успешно­
го исполнения d i s p l a y L o c a t i o n каждый раз, когда вы успеваете
сделать лишь несколько шагов. Один из способов исправить это
заключается в добавлении кода, благодаря которому новый маркер
будет создаваться только после того, как вы пройдете более значи­
тельное расстояние (например, 20 метров в целях тестирования).
У нас уже имеется функция, которая вычисляет расстояние между З а м не к а ж е т с я ,
двумя точками ( c o m p u t e D i s t a n c e ) , поэтому нам останется лишь
ч т о зд е сь ч р е з м е р ­
сделать так, чтобы ваше местоположение сохранялось при каж­
но м н о г о м а р к е р о в ?
дом вызове d i s p l a y L o c a t i o n и проводилась проверка того,
является ли расстояние между вашим предыдущим местоположе­
нием и новым больше 20 метров, прежде чем произойдет вызов
s c r o l l M a p T o P o s i t i o n . Необходимый для этого код приведен
ниже; ваша задача заключается в том, чтобы заполнить имеющиеся в
нем пробелы. Будьте внимательны, поскольку некоторые магнитные
таблички нужно использовать более одного раза!

function displayLocation(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var div = document.getElementByld(Mlocation");
div.innerHTML = "You are at Latitude: " + latitude + ", Longitude: 11 + longitude;
div.innerHTML += " (with " + po s i t i o n .coords.accuracy + 11 meters accuracy) " ;
var km = computeDistance(position.c oords, ourCoords);
var distance = document.getElementByld("distance");
distance.innerHTML = "You are " + km + " km from the Wickedly Smart HQ";
if (map = null) {
showMap(position.coords);
prevCoords = _________________ ;
} else {
var meters = _________________ (position, c oords, prevCoords) * 1000;
if ( > ) {
scrollMapToPosition(position.coords);

240 глава 5
создание HTML-страниц с поддержкой определения местоположения

КЛЮЧЕВЫЕ
— МОМЕНТЫ
Я

■ API-интерфейс Geolocation не является «официаль­ При вызове g e t C u r r e n t P o s i t i o n ВЭШ браузер


ной» частью спецификации HTML5, но считается ча­ должен удостовериться, что вы дали разрешение на
стью семейства технологий HTML5. использование информации о вашем местоположении.

■ Можно использовать разные методики определения ■ w atc h P o sitio n — ЭТО МвТОД объекта geo l o c a t i o n ,
своего местоположения в зависимости от устройства, который отслеживает ваше местоположение и вызыва­
которое у вас имеется. ет обработчик успешного исполнения при изменении
вашего местоположения.
■ GPS позволяет получать более точные данные о ме­
стоположении, чем триангуляция с использованием ■ Как И у g e t C u r r e n t P o s i t i o n , у w a t c h P o s i t i o n

вышек сотовой связи и мобильного телефона или имеется один обязательный параметр — обработчик

методика на основе применения 1Р-адресов. успешного исполнения и два опциональных — обра­


ботчик ошибок И o p t i o n s .
■ В случае с мобильными устройствами, не поддержива­
ющими GPS, для определения местоположения можно ■ c l e a r W a t c h используется для остановки отслежива-
ния местоположения пользователя.
прибегнуть к триангуляции с использованием вышек
сотовой связи и мобильного телефона. ■ При использовании w a t c h P o s i t i o n энергопотребле­
ние устройства возрастает, поэтому его аккумулятор
■ API-интерфейс Geolocation включает три метода и не­
будет разряжаться быстрее.
сколько свойств.
■ Третий параметр методов g e t C u r r e n t P o s i t i o n И
■ Основным методом в API-интерфейсе Geolocation
w a t c h P o s i t i o n с именем o p t i o n s представляет со­
является g e t C u r r e n t P o s i t i o n — МвТОД объекта
бой объект со свойствами, которые вы задаете с целью
n a v i g a to r . g eo lo catio n .
контроля над поведением API-интерфейса Geolocation.
■ У g e t C u r r e n t P o s i t i o n имеется один обязательный
■ Свойство m a x im u m A g e устанавливает, будет ЛИ
параметр — обработчик успешного исполнения, и два
g e tC u rre n tP o sitio n ИСПОЛЬЗОВЭТЬ КЭШИрОВЭННЫе
опциональных — обработчик ошибок И o p t i o n s .
данные о местоположении, и если да, то насколько
■ Объект p o s i t i o n передается обработчику успешного устаревшими смогут быть эти данные, прежде чем
исполнения наряду с информацией о местоположении потребуется определять новое местоположение.
пользователя, включая широту и долготу. ■ Свойство t i m e o u t устанавливает, сколько времени

■ Объект p o s i t i o n содержит СВОЙСТВО c o o r d s , кото­ будет у g e t C u r r e n t P o s i t i o n на определение но­

рое является объектом c o o r d i n a t e s . вого местоположения, прежде чем произойдет вызов


обработчика ошибок.
■ Объект c o o r d i n a t e s обладает свойствами, включая
■ СВОЙСТВО en ab leH ig h A ccu racy Н ам екает устр ой-
l a t i t u d e , lo n g itu d e Иaccuracy.
ствам на то, что им следует затрачивать больше усилий
■ Некоторые устройства могут поддерживать и дру­ на определение точного местоположения, если это
гие свойства объекта c o o r d i n a t e s : a l t i t u d e , представляется возможным.
a l titu d e A c c u r a c y , h e a d in g И speed.
■ Вы можете использовать API-интерфейс Geolocation
■ Свойство a c c u r a c y используется для определения в сочетании с API-интерфейсом Google Maps для ото­
точности местоположения в метрах. бражения своего местоположения на карте.

дальше ► 241
кроссворд

1 Л Щ , 5 - К Г °ссК°Г Д
Вы проделали довольпо длиппы й путь в этой
главе, используя свой п ервы й API-иптерф ейс
JavaScript. Закреп и те изучеппы й материал,
реш ив даппы й кроссворд.

По горизонтали По вертикали
3. Измерение долготы ведется о т _______________, Англия. 1. В случае применения устройств без поддержки GPS опре­
4. Точность определения местоположения имеет опреде­ делить ваше местоположение можно будет посредством
ленный подтекст в случае с веб-приложениями, который _______________ с использованием вышек сотовой связи.
заключается в том, что она может сказываться на уровне 2. Для вычисления расстояния между двумя точками ко­
заряда аккумуляторной_______________ устройства. ординат можно использовать формулу_______________.
7. Не давайте кому-либо рекомендаций насчет направления 5. Вы никогда не получите кэшированных данных о место­
движения, если ваши координаты не будут обладать до­ положении, если для параметра_______________ задано
статочной _______________. значение 0.
9. Фраза «Куда бы ты ни шел — ты уже там» упоминалась 6. Центрирование карты заново осуществляется с исполь­
в ф ильме__________________________ . зованием м етод а_______________.
10. Если вы откажете браузеру в его запросе на разреше­ 8. Место, где располагается город_____________ , имеет
ние использовать данные о вашем местоположении, широту и долготу соответственно 40.77, -73 .9 8.
это приведет к вызову обработчика ошибок с кодом
_______________ в виде 1.
11. Тайное местоположение штаб-квартиры______________
имеет координаты 47.62485, -12 2.52099.

242 глава 5
создание HTML-страниц с поддержкой определения местоположения

Развлечения с магнитами, решение


Ваша задача заключается в том, чтобы заполнить пробелы в приведенном ниже коде, благодаря которо­
му новый маркер будет отображаться только в том случае, если вы пройдете более 20 метров от места,
отмеченного предыдущим маркером. Для заполнения пробелов в коде используйте соответствующие
магнитные таблички. Будьте внимательны, поскольку некоторые из них придется использовать более
одного раза! Приведем решение этого задания.

p re v C o o rd s = n u l l ;

function displayLocation(position) {

var latitude = position.coords.latitude;

var 1ongi tude = po si ti o n .c oords.1ongi tud e ;

var div = document .getElementByld ("location") ;

div.innerHTML = "You are at Latitude: " + latitude + ", Longitude: " + longitude;

div.innerHTML += " (with " + position.coords.accuracy + " meters accuracy)";

var k m = computeDistance(position.coords, ourCoords);

var distance = document.getElementByld("distance") ;

distance.innerHTML = "You are " + k m + " k m from the WickedlySmart HQ";

if (map == null) {

showMap(position.coords);

prevCoords = posi t i o n .coords

}
else {

var meters = coirputeDistance \ (position.coords, prevCoords) * 1000;

> -L i° I <
scrollMapToPosition (position, coords) ;

prevCoords p o s i t i o n .c o o r d s ^ j ;

r *
Так намного лучше!

Проведите тестирование онлайн:


h t t p : / /w ic k e d ly s m a r t.c o m /h fh tm l 5 / c h a p t e r ^ / final/ m yLoc.htm l

дальше ► 243
решение упражнения

^.Возьми в руку карандаш


Решение Ниже приведена альтернативная реализация для d i s p l a y L o c a t i o n .
Сможете ли вы догадаться, что она делает? Взгляните на нее и напишите
свой ответ в самом низу. Если в вас проснулась предприимчивость, про­
тестируйте данный код!

distance .innerHTML = "You are 11— I— km I


— 11 km from the Wickedly Omar t IIQ" ;
if (km < 0 . 1 ) {
distance.innerHTML = "You’re on fire!";
} else {
if (prevKm < km) {
distance.innerHTML = "You're getting hotter!";
} else {
distance.innerHTML = "You're getting colder...";

Данный код превращает наше приложение в игру «Горя­


}
prevKm = km;
чо/холодно». Он выводит сообщение “You're getting hotter!"
("Теплее!"), если вы подходите ближе к штаб-квартире
Wickedly Smart, либо “You're getting colder!" ("Холоднее!"),
де- , если вы уходите все дальше от нее. Когда вы окажетесь
л а е т весь э т о т код. fi километра от штаб-квартиры Wickedly Sm art,
появится сообщение "You're on fire!" ("Очень горячо!")

Мы прот ест ировали данный код,


и вот что у нас получилось!!

244 глава 5
создание HTML-страниц с поддержкой определения местоположения

+
+
КТ9 И

Ниже приведены параметры, касающиеся API-интерфейса Geolocation.


Ваша задача заключается в том, чтобы подобрать каждому параметру
пару в виде соответствующего ему поведения.

Мпе требую тся только кэш ироваппы е


{maximumAge:600000 }
даппы е о м естополож епии, которы м
мепьше 10 мипут. П ри отсутствии таких
даппых я хочу получить даппы е о по-
вом м естополож епии, по только в том
случае, если па это уйдет 1 секупда или
мепьше.

{timeout:1000, maximumAge:600000} Я буду использовать кэш ироваппы е дап-


ны е о местополож епии, если таковы е
будут иметься у браузера, и при этом им
будет мепьше 1 0 мипут; в противпом слу­
чае я хочу получить даппы е о повом ме­
стополож епии.

{timeout:0 , maximumAge :Infinity} Мпе требую тся только даппы е о повом


местополож епии. Браузер мож ет ис­
пользовать столько времепи па опреде­
ление м естополож епия, сколько ему по­
требуется.

{timeout:Inf ini t y , maximumAge:0 } Мпе требую тся только кэш ироваппы е


даппы е о местополож епии. М епя устро­
ят даппы е любого «возраста». Если кэ­
ш ироваппы е даппы е о местополож епии
будут полпостью отсутствовать, п ро­
изойдет вызов обработчика ошибок.
С ведепия о повом местополож епии из­
влекаться пе будут! Д аппы е пастройки
предпазпачепы для использования в си­
туациях, когда речь идет об автопом пой
работе.

дальше ► 245
решение упражнения

Д Н г Ш М Ь 5 _ к Г оссБоР л - f e ffleHue

246 глава 5
6 оё>1Ц 0Н ие с В0ё>— с л у ж б а м и

Приложения-экстраверты
— Ес л и бы я только
знала, что обращение к веб­
службам и взаимодействие
с ними м ожет быть настолько
увлекательным...

Что-то вы слишком засиделись на своей странице. Настало время


пообщаться с веб-службами с целью сбора данных и последующего возврата
этой информации, что позволяет создавать более эффективные веб-ресурсы,
которые объединяют собираемые данные. Это важный момент в написании
современных НТМ1_5-приложений, а чтобы успешно этим заниматься, вам
необходимо знать, как происходит общение с веб-службами. Кроме того, вы
научитесь внедрять данные от веб-служб в свои страницы. Усвоив изложен­
ный здесь материал, вы сможете взаимодействовать с любой веб-службой.
Мы даже расскажем вам о новомодном жаргоне, которым следует пользоваться
при общении с веб-службами. Вы познакомитесь с некоторыми новыми API-
интерфейсами — так называемыми коммуникационными API-интерфейсами.
приложение mighty gumball

Ознакомьтесь с нашей новой моделью


Компании Mighty Gumball автомата для продажи жевательной резинки
М62200, поддерживающей подключение
требуется Веб-прилоЖение к Интернету. Он произведет настоящую рево­
люцию в бизнесе.
Свежая п о в о с т ь : и пповациоппая ком папия
Mighty Gum ball, Inc., которая п роизводит и уста­
навливает настоящие автоматы для продажи же­
Вы можете пом н ит ь
вательной резинки в виде шариков, связалась с нами
э т у компанию по нашей
и попросила помочь. Если вы еще не знаете, то
книге «И зучаем шаб­
эта ком пания недавно стала оснащ ать свои то р ­
лоны п ро ект иро ва­
говые автоматы возможностью подклю чения к
ния» (Head First Design
Интернету, чтобы отслеживать уровни продаж
Patterns), где мы п о м о ­
п очти в реж им е реального времени.
гали им разрабатывать
С тоит ли говорить, что в Mighty G um ball рабо­ код на стороне сервера.
таю т те, кто знает толк в автоматах для продажи
ж евательной резинки, а не разработчики п ро­
граммного обеспечения, поэтому они и обрати­
лись к нам за помощью и попросили написать Исполнительный директор
п рилож ение, которое позволит отслеживать Mighty Gumball
уровни продаж данной ж евательной резинки.
Вот что они нам прислали:

Б л а г о д а р и м , ч т о с о г л а с и л и с ь п о м о ч ь ! В о т к а к , на на ш в з г л я д , долж ен
р а б о т а т ь и н с т р у м е н т д л я о т с л е ж и в а н и я продаж ж е в а т е л ь н о й р е з и н к и
и з а в т о м а т о в , и м ы н а д е е м с я , ч т о вы см о ж е т е его д ля нас р е а л и з о в а т ь !
Miehty Gumball Inc. О б р а щ а й т е с ь , ес ли у вас в о з н и к н у т к а к и е - л и б о в о п р о сы !
Там, где автомат для
продажи жевательной
К р о м е т о г о , м ы в с к о р е в ы ш л е м в а м сп е ц и ф и к а ц и и , к а с а ю щ и е с я в е б ­
резинки никогда не пуст
наполовину служ бы. — —к о м п а н и и M ig h ty C jum ball
И нж енеры

М о б и ль н ы е
и наст оль­
ны е у с т р о й ­
ст ва будут кг
получат ь
св е д ен и я
Н аш и н т е р н е т -
о продаж ах
о т сервера
'я сервер
Н а м н е о б х о д и м о , чт о б ы
Все наши а вт ом ат ы для п р о ­
реально­ дажи жевательной резинки
вы н а п и с а л и э т у ч а с т ь ,
го в р е м е н и будут о т п равлят ь отчеты
ест ест вен н о , используя
с пом ощ ью на центральный сервер.
веб -служ б ы . HTMLSH

248 глава 6
общение с веб-службами

Прежде чем мы п р и с т у п и м , п о т р а т ь т е немного времени и подумайте,


как бы вы подошли к разработке приложения, которое извлекает дан­

Г ные, предоставляемые веб-службой, и использует их для обновления веб­


страницы. Не беспокойтесь, если вы еще не знаете, как извлекать данные,
просто обдумайте высокоуровневый дизайн приложения. Сделайте наброски,
пом ет ки, напиш ите псевдокод для любого кода, который вам может п о ­
требоваться. С чит айте это разминкой для мозга...
---------------
Заметки по разработке
MieMyOumballlnc-
Там, где автомат для
продажи жевательной
резинки никогда не пуст
наполовину

Как мы будем извлекать


данные, предоставляемые
UX
веб-службой, и направлят ь
к нашей веб-странице?

Как мы будем обновлять


ст раницу после того,
как извлечем данные?

Какие проблемы у нас м о г у т


возникнуть с получением дан­
ных о т удаленного сервера?

дальше ► 249
обзор системы mighty gumball

Подробнее о системе Mighty Gumball


В ероятпо, вам пеобходимо более подробпо разобраться во всей этой системе, чем было описапо в
краткой записке от ипж еперов из Mighty Gum ball. И так, вот как обстоит дело: во-первых, у даппой
ком папии есть автоматы для продаж и ж евательпой резипки, которы е располагаю тся по всей страпе
и отправляю т отчеты па сервер Mighty Gum ball, которы й, в свою очередь, собирает все эти отчеты и
делает их доступпыми с помощью веб-службы. Во-вторых, пас просят создать веб-приложепие, отобра­
жающее показатели продаж в браузере для группы сбы та Mighty Gum ball. К роме того, опи, скорее все­
го, захотят, чтобы даппая отчетпость обповлялась по мере изм епепия уровпя продаж по прош ествии
времепи. Вот как все это будет выглядеть паглядпо в общих чертах:

Всем спасибо, я принял ваши )О 0

отчеты об уровне продаж Л


и соберу их все вместе. J

о Торговые автоматы Mighty Gumball


установлены по всей стране и
отправляют отчеты об уровне про­ Сервер
даж на центральный сервер дан­ Mighty
ной компании. Затем центральный Gumball
сервер собирает все отчеты вместе
и делает их доступными с помо­
щью веб-службы.

250 глава 6
общение с веб-службами

Браузер загружает веб­


приложение Mighty 6umball(
включая HTML-разметку,
CSS и JavaScript.

Приложение отправляет веб-запрос


с целью извлечения собранных вме­
сте данных об уровне продаж с сер­
вера Mighty Gumball.

Приложение изучает данные,


после чего обновляет объектную
модель документа (DOM) стра­
ницы для того, чтобы отразить
новые данные об уровне продаж.

/Ж 1 М Т Т \0

Обратно приложение получает


данные с сервера Mighty feumball.

V
Приложение возвраща­
Браузер обновляет страницу
на основе DOM, в результа­
те чего пользователи могут
увидеть результаты.
ется к шагу 3 и постоян­
но запрашивает новые
данные. В результате
этого страница обнов­
ляется почти в режиме
реального времени.

дальше ► 251
подготовка разметки

Приступаем к созданию приложения...


П ока мы ждем специф икаций от и пж еперов из Mighty G um ball, займемся HTM L-разметкой.
Н аверпяка вы уже сообразили, что пам пе попадобится больш ой объем HTM L-разметки, чтобы успеш-
по пачать создавать паше веб-приложепие. Все, что пам требуется, — это место для разм ещ епия отче­
тов об уровпе продаж по мере их поступлепия, а все остальпое мы доверим сделать JavaScript. Н абери­
те приведеппую пиж е разметку, после чего мы взгляпем па то, как извлекать даппы е с веб-сервера по
протоколу HTTP.

И сп о льзуем ст а н д а р т ­
<! d o cty p e h tm l> ны е H T M L S - э л е м е н т ы
<html lang="en"> <head> и <body>.
<head>
Заранее размещаем ссылку
< title > M ig h ty G u m b a ll (J S O N )< /title > на JavaScript-ф айл , зная , что
< m e ta c h a r se t= " u tf-8 " > вскоре напишем соответству­
< s c r ip t sr c = " m ig h ty g u m b a ll. j s " X / s c r i p t >
ющий JavaScript-код!
< lin k r e l= " s ty le s h e e t" h r e f = nm i g h t y g u i n b a l l . c s s " >

< /h e a d > (hr Т<якже з а д е й с т в у е м C S S д ля e m u -


<body> л и з а ц и и о т ч е т а о продаж ах
M ig h ty G u m b a ll, ч т о б ы его вн еьи -
< h l> M ig h tY G u m b a ll S a le s < /h l>
н и й ви д п о н р а в и л с я и с п о л н и т е л ь -
< d iv i d = Hs a l e s " > ном у директ ору.

Сюда мы будем помещать дан­


< /d iv >
ные об уровне продаж. Каждый
< /b o d y >
элемент данных об уровне продаж
< /h tm l> будет добавляться сюда как <div>.

Забодите двигатель для тест-драйба

Н абрав приведеппы й выше код, загрузите его в своем лю­


бимом браузере и протестируйте, прежде чем двипетесь
дальше. И пе забы вайте, что загрузить CSS (и п рочи й код,
использоваппы й в этой главе) вы сможете со страпицы
http: / / wickedlysm art.com /h f h tm l 5 .

252 глава 6
общение с веб-службами

Как Выполняются запросы, адресованные Веб-слуЖбам?


Д авайте пемпого приторм озим ... Вы уже зпаете, как браузер запраш ивает страпицу с веб-сервера — оп
отправляет H TT P-запрос серверу, а тот возвращ ает соответствующую страпицу паряду с дополпитель-
пыми метадаппыми, которы е (обы чпо) «видит» только браузер. Одпако, возможпо, вы пе зпаете, что
браузер способеп апалогичпы м образом извлекать данные с веб-сервера по протоколу HTTP. Вот как это
происходит:
Браузеры
собРаннЫе могут\ запра -
Сервер, ожидающий ПР° А0Ж ЖВ°4^ — ^ в а т ь данные
^прилож е­
запросов от браузеров ний на сервере,
н а п р и м е р от
п р и л о ж е н и я

Веб-сервер Sb M ' 3 ^ t y G u m b a ll,


которое соби-
Рае^\ данные об
«Конечно, вот они» уровн£ ^
К
Сервер возвращает
ЗАПРОС: используется протокол запрошенные данные
НТТР1.1 для извлечения ресурса П олезпо взгляпуть пемпого пристальпее па запрос, отправля
из « / gumballsales» (наше прило­ поступает. Запрос сообщ ает браузеру, какие даппы е пас ипт
жение на сервере). которы й пас иптересует), а ответ будет содерж ать метадапп
мацию, запрош еппую пами:
ZOO — ОТВЕТ: первым идет заголовок про­
код ответа
сервера, означаю­ 1.1; здесь сообщается ,
токола HTTP
щийj чточтовсе дляпро
передачи
- —? H данного
TTP/1.1 200ответа ок ис­
пользовался
шло нормально. протокол
^ Content-lengthHTTPj 756
а также
Content-type: application/json
приводится код ответа.
Метаданные: мы получили [{"name":"C AMPBELL",
" tim e " : 1302212903099,
содержимое, которое и м е- "sales": "3"},
ет длину 7 5 6 байт и т и п {"name": "FRESNO",
application/json... " t i m e " : 13 022 12 9 0 31 0 0,
"sales"; 2},
Метаданные: мы
...при этом запрос исходит от бра­
отправляем запрос у зересовм ест им ого с Mozilla 5.0 17
на хост gumball. (данный пользовательский агент ...а вот данные,
wickedlysmart.com... используется в случае с Safari , к о т о р ы е мы запрашивали!
Chrome и другими браузерами).
Примечание: данный шаблон извлечения данных с использованием XMLHttpRequest
обычно называется Ajax или XHR.
дальше ► 253
использование xmlhttprequest

Как выполнять запросы из JavaScript


Итак, теперь мы зпаем, что можпо извлекать даппы е по протоколу HTTP, по как имеппо? Н апиш ем пе-
болы ной код для геп ери ровап ия пастоящ его H TTP-запроса, после чего п опросим браузер соверш ить
запрос от пашего имепи. Выполпив даппы й запрос, браузер передаст пам даппы е, которы е получит в
ответ. П ош агово рассм отрим соверш епие НТТР-запроса.

Начнем с URL. Ведь, в конце концов, нужно же нам как-то ска "js<m" о зн а ч а е т ф о р ­
зать браузеру, где искать данные, которые нас интересуют: м а т о б м ен а д а н н ы м и
Вот наш URL -адрес (к н е м у м ы в е р н е м с я
someserver.com н е м н о го позж е).

V
var url = "http://someserver.com/data.j son11
T
Сохраним URL-адрес в переменной u rl,
кот орую будем использовать далее.

О Теперь создадим объект r e q u e s t следующим образом:

var request = new XMLHttpRequest();


А 1
Присваиваем Используем конст рукт ор Х М LHttpRequest
объект request для создания нового объекта request. Совершенно новый объект
переменной О XM L в данном имени мы поговорим XMLHttpRequest.
request. чуть позже
Далее нам необходимо сообщить объекту r e q u e s t , какой URL ему нуж­
но найти и какого рода запрос он должен использовать (мы задействуем О б н о вл ен н ы й о б ъ ­
стандартный HTTP-запрос GET так же, как на предыдущей странице). Для е к т Х М L H ttp R e q u e st,
этого воспользуемся методом open объекта r e q u e s t . Может показаться, к о т о р ы й « з н а е т » не
что, судя по имени o p e n , данный метод может не только задавать соответ­ о бхо д и м ы й URL -а д р ес .
ствующие значения в объекте r e q u e s t , но и открывать новое соедине­
ние и извлекать данные. На самом деле это не так. Несмотря на имя, метод
o p e n лишь задает URL для объекта r e q u e s t , а также сообщает ему, какого
рода запрос следует использовать, чтобы XMLHttpRequest смог произве­
сти верификацию соединения. Вызов метода o p e n осуществляется следу­
ющим образом:

request.open ("GET11, url) ;

Настраиваем объект request


задействуя Н Т Т Р -запрос ^
который является ст андарт ­
Т
Настраиваем объект request
на использование URL -адреса,
а м средством извлечения сохраненного в переменной url.
данных по протоколу HTTP.

254 глава 6
общение с веб-службами

Итак, мы подошли к важной части и особенностям работы X M L H t t p R e q u e s t :


когда мы, наконец, попросим объект X M L H t t p R e q u e s t извлечь данные, он
приступит к работе и извлечет требуемую информацию. Это может занять
90 миллисекунд (что довольно много по компьютерным меркам), а порой XMLHttpRequest
даже 10 секунд (целая вечность по компьютерным меркам). Вместо того
method: SET
чтобы просто дожидаться данных, мы предусмотрим обработчик событий,
который будет вызываться при их поступлении (эта процедура в некоторой
URL: "h ttp ://..."
степени уже должна быть вам знакома):
onload:
Наш объект request
Когда браузер получит
r e q u e s t , o n lo a d = f u n c t i o n () { о т в ет от удаленной веб- request.onload = function!) {
if (request.status = 200) {
if ( r e q u e s t , s t a t u s == 2 0 0 ) { службы, он вызовет данную alert("Data received!");
функцию. }
a l e r t ( " D a ta r e c e i v e d ! 11) ; };

} / Сначала обработчику необходимо п р о ве р и т ь, является ли кодом от вет а


у. ' сервера значение ZOO, то есть все ли в порядке, после чего он сможет
ч т о - т о сделать с данными. На данный м о м е н т мы просто будем выво­
дить для пользователя диалоговое окно alert с сообщением>что данные
пост упили. Вскоре мы пр им еним здесь более выразительный код.
Остался последний шаг: нам все еще нужно сказать объекту r e q u e s t , чтобы
он извлек данные, для чего воспользуемся методом s e n d :
Благодаря эт о м у происходит отправка запроса на сервер.
re q u e s t, send ( n u ll) ; nep e$aeM n u /ij если не от правляем какие-либо данные
удаленной службе (чего мы как раз и не делаем).
Давайте еще раз пройдемся по всему процессу: мы создаем объект X M L H t t p R e q u e s t , снабжаем его
URL-адресом и HTTP-запросом наряду с обработчиком. Затем мы отправляем запрос и дожидаемся по­
ступления данных. Когда данные поступают, происходит вызов обработчика.

- — ■ ь
Запрос Данные

Веб-служба

дальше ► 255
как получить доступ к http-omeemy

Я так ничего и не услышал о том, как из­


влекать данные, полученные с помощью
H T T P -вызова. Я вижу ф ункцию onload, но где
код для доступа к этим данным? И ли я что-то
пропустил?

Мы просто еще не дошли до рассм отрения дан­


ного аспекта. И нф ормацию , полученную посред­
ством H T T P-запроса GET, можно найти в свойстве
responseText объекта request. Таким образом,
мы можем написать код вроде следующего:
Вызов данной ф у н к ­
ции происходитj
когда объект request
request.onload = function() {
получает ответ.
if (request.status = 200) {
alert(request.responseText);

Мы можем извлечь о т в ет
„ 1 1
из свойства respc
responseText
объекта request.
П отерни те немного, носко льку мы но чти но до­
шли к моменту нанисания реального кода, в кото­
ром задействуется r equest.responseText.

256 глава 6
общение с веб-службами

развлечения с магнитами
г\
Новая веб-служба http://wickedlysmart.com/ifeelluckytoday возвращает u n l u c k y либо l u c k y при каж­
дом обращении к ней. Логика в данном случае базируется на тайном и древнем алгоритме, о котором
мы не можем вам рассказать, однако эта служба дает возможность пользователям узнать, повезет им
(lu c k y ) или нет (u n lu c k y ) в определенный день.
Нам требуется ваша помощь в создании показательной реализации, чтобы продемонстрировать дру­
гим, как они могут включить ее в свои сайты. Ниже приведен скелет кода; помогите нам заполнить
пробелы в нем, используя магнитные таблички. Будьте внимательны, поскольку здесь есть лишние
таблички. Одну из табличек мы уже разместили в нужном месте.

w in d o w . o n lo a d = f u n c t i o n () {

v a r u r l = " h t t p : / / w ic k e d ly s m a r t . c o m / i f e e ll u c k y t o d a y " ;

v a r r e q u e s t = __________________________

{
if (_________________________ ) {

d i s p l a y L u c k (_ );

Чувствуете, что вам


сегодня повезет? Х отите
Разместит е со­
быть в этом уверены? Т о г­
от вет с т ву ю щ и е
да воспользуйтесь нашей
таблички с кодом
службой!
} в нужных местах!
f u n c t i o n d i s p la y L u c k ( lu c k ) {

v a r p = d o c u m e n t.________ ( " lu c k " ) ;

P in n e rH T M L = "T o d a y y o u a r e " + l u c k ;

}
У-

request.onload = function() |
new XMLHttpRequest()
m yLuckyText^^""^^"*"^™ "*™ ^"™ "^^

g e tE le m e n tB y ld
r e q u e s t . s t a t u s == 200

дальше ► 257
решение упражнения

развлечения с магнитами, решение

Новая веб-служба http://wickedlysmart.com/ifeelluckytoday возвращает u n l u c k y либо l u c k y при


каждом обращении к ней. Логика в данном случае базируется на тайном и древнем алгоритме,
о котором мы не можем вам рассказать, однако эта служба дает возможность пользователям уз­
нать, повезет им ( lu c k y ) или нет ( u n lu c k y ) в определенный день.

Нам требуется ваша помощь в создании показательной реализации, чтобы продемонстрировать


другим, как они могут включить ее в свои сайты. Ниже приведен скелет кода; помогите нам за­
полнить пробелы в нем, используя магнитные таблички. Будьте внимательны, поскольку здесь есть
лишние таблички. Вот наше решение этого упражнения.

window.onload = function () {

var url = "http://wickedlysmart.com/i feel lucky today" ;

n e w X M L H t t p R e q u e s t ();
var request =
1
r e q u e s t . o n l o a d = f u n c t i o n () [{
r e q u e s t .status == 200 1) {
if (_

di s p 1 a y L u c k ( r e q u e s t .responseText );

Чувствуете, что вам


сегодня повезет? Хотите
быть в этом уверены? Т о г­ Размест ит е со­
да воспользуйтесь нашей request.o p e n ("GET", url) ; о т вет ст вую щ ие
службой! L
таблички с кодом
request.send(null) ; | в нужных местах!
I

function displayLuck(luck) {

var p = document. I ^etElementById l("luck");

p. innerHTML 1 = "Today you are " + luck;

Лишние таблички

request.create("GET", url)

myLuckyText

258 глава 6
общение с веб-службами

Интервью недели:
Признания объекта XMLHttpRequest

Head First: Д обро ножаловать, X M LH ttpR equest, ционны е данны е о том, что раснолож ено но бли­
мы рады, что вы смогли вы кроить для нас время зости... П очти любые данные, которы е вы только
в своем нлотном граф ике. Расскажите, как Вы вни- можете себе нредставить, нонадают во Всемирную
сываетесь в нроцесс создания веб-нриложений. наутину в форме, с которой я могу работать.
XMLHttpRequest: Я нолож ил начало целому Head First: Это же ведь все исклю чительно XML-
тренду но нривнесению внеш них данны х в веб­ данны е, не так ли? Я имею в виду, что в Вашем име­
страницы. Слышали о Google Maps? О GMail? Это ни присутствует часть XML.
все я. Без меня все это было бы невозможным. XMLHttpRequest: Неужели? П озвольте ответить
Head First: В каком смысле? нрямо. Н есомненно, было время, когда я, главным
образом, занимался извлечением XML-данных, од­
XMLHttpRequest: До моего ноявления люди гене­ нако мир не стоит на месте. В настоящ ее врем я я
рировали веб-страницы на стороне сервера, нри могу извлекать всевозмож ны е данные. Естествен­
этом в них закладывались сразу все данные. Я же но, н екоторы е из них являю тся XML-данными,
нозволяю нолучать данны е после того, как страни­ однако я нолучаю все больше занросов на извлече­
ца сгенерирована. Всномните Google Maps: дан­ ние JSO N -данных.
ная служба обновляет то, что им еется на страни­
це, каждый раз, когда нроисходит корректи ровка Head First: В самом деле? А что такое JSON и н е­
вашего м естонолож ения на карте, без необходи­ чему он набирает такую нонулярность?
мости перезагрузки страницы целиком. XMLHttpRequest: JSO N — это сокращ ение от
Head First: Вы нользуетесь уснехом. В чем ваш се­ JavaScript O bject N otation (нотация JavaScript-
крет? объектов). У этого ф орм ата им еется ряд преиму­
ществ: разм ер, удобочитаемость, а также тот факт,
XMLHttpRequest: В моей ненритязательности и что он является «родным» для наиболее нонуляр-
нростоте. Д айте мне URL-адрес, и я отнравлю сь ного язы ка програм м ирования, иснользуемого
но нему и извлеку необходимы е вам данные. Н е нри создании веб-нрилож ений, которы м, конечно
более того. же, выстунает м ой друг JavaScript.
Head First: И этим все ограничивается? Head First: А нравда, что на самом деле ф орм ат
XMLHttpRequest: Ч то ж, вам нотребуется сказать не долж ен иметь для Вас значения? П ользовате­
мне, что дальше делать с данны ми носле того, как ли долж ны быть снособны занраш ивать данны е в
я их извлеку. Вы мож ете нросто дать мне функцию ф орм ате XML, JSO N , а также телетайнное тексто­
обработчика — функцию обратного вызова, — вое содерж имое с Вашей номощью. И ли нет?
и когда я добуду данны е, я нередам их этому обра­ XMLHttpRequest: < s i l e n c e >
ботчику, которы й сможет сделать с ними все, что
Head First: Ч то ж, судя но вашему молчанию , я за­
ему нотребуется.
тронул болезненную тему. Ладно, н ора сделать
Head First: О какого рода данны х мы говорим нереры в... Послушайте, X M LH ttpR equest, ведь у
в данном случае? нас же еще будет врем я для общ ения с Вами нозже
в этой главе?
XMLHttpRequest: С оврем енны й И н терн ет нолон
всевозмож ны х данных; нрогнозы ногоды, карты , XMLHttpRequest: Да, хоть здесь и нет ничего ра­
социальны е сведения о разны х людях, геолока- достного, но я вижу это в своем раснисании...

дальше ► 259
знакомство с json

Подвинься, XML: встречайте JSON


Как вы мож ете номнить (а мож ете и не ном нить), XML собирался стать наш им всеобщ им снасителем, —
это ф орм ат данных, которы й удобочитаем для человека и мож ет быть нодвергнут разбору маш иной,
н ри этом он был готов п реврати ться в универсальны й ф орм ат для обмена данны ми во всем мире. Д ей­
ствительно, с ноявлением XMLHttp Re quest XML стал форматом, с номощью которого мы все обменива­
лись данны ми (отсюда и часть XML в им ени XMLHttpRequest).
Однако но ходу дела XML, но-видимому, «носкользнулся на банановой кож уре», которую ему нодбросил
JSON. Ч то такое JSON? Это наиболее соврем енны й и отличны й ф орм ат данных, рож денны й JavaScript,
которы й обретает ноддержку в сф ере И н терн ета —в браузерах и на стороне сервера. И нтересно, удаст­
ся ли ему быстро стать предпочтительным форматом для НТМ Ьб-нриложений?
Так что же такого зам ечательного в JSON? Это внолне удобочитаемый для человека формат, данны е в
котором могут быть легко и быстро разобраны и нреобразованы нрямо в JavaScript-значения и объекты.
В отличие от XML, он такой классный и симнатичны й... так или иначе, разве мож но носле всего этого
сказать, что он нравится нам лиш ь чуть-чуть? Вы много раз будете сталкиваться с JSO N далее в книге.
Мы будем иснользовать его для обмена JavaScript-данными через И нтернет, для сохранения данны х в
localStorage с нрим енением API-интерф ейса Web Storage, а также как часть еще одного нодхода к нолу-
чению достуна к веб-данным (вскоре мы ноговорим об этом нодробнее).
Постойте-ка, ф орм аты обмена данными ч ерез И нтернет... ф орм аты хранения... все это так сложно, не
нравда ли? Н е беснокойтесь, носкольку н а п ротяж ении следующих десяти страниц мы будем превра­
щать вас в эксперта вы уже знаете нрактически все необходимое о JSON. Ч тобы иснользовать JSON,
вам потребуется лиш ь нонимание JavaScript-объектов (а эти знания у вас уже есть), а также два нросты х
вы зова методов.

Q У нас имеется JavaScript-объект, мы хотим ф Результатом будет строка, представ­


обменяться им или сохранить его, поэтому ляющая объект. Мы можем сохранить
вызываем метод J S O N . s t r i n g i f y и пере­ данную строку, передать ее функции,
даем ему этот объект в качестве аргумента. отправить через Интернет и т. п.

ляОТЯ. s tr : ingifY<®ovie)

{"title":"Plan 9 from Outer


Space","genre":"Cult Classic"
M О VI в 1 ,"rating":5,"showtimes":["3:0
0pm" ,"7:00pm" ,"11:00pm" ]}

string)
JSO N.parse (jso n!

ф Когда мы будем готовы преобразо­


Q Результатом будет копия на­ вать строку обратно в объект, мы пе­
шего оригинального объекта. редадим ее методу J S O N . p a r s e .

260 глава 6
общение с веб-службами

Краткий пример е использованием JS0N


Рассмотрим н рим ер н реобразования объекта в строковы й ф орм ат Ha самом деле есть
© JSON. Н ачнем с объекта, которы й будет вам нонятен, — m o v ie из еще ряд ограничений,
главы 4. Однако не все можно нреобразовать в данны й ф орм ат (на- "однако мы не с т а ­
нрим ер, методы ), зато ноддерж иваю тся все базовые тины , такие как нем беспокоиться
n u m b e r, s t r i n g , а также массивы. Д авайте создадим объект, а затем о ник сейчас.
нередадим его методу JS O N . s t r i n g i f у:
var plan9Movie = new Movie ("Plan 9 from Outer Space" ,"Cult Classic" , 2,
["3:00pm" , "7:00pm" , "11:00pm" ]);

Наил объект movie>« ук о м п л е к т о ва н- -%


ный» ст р о ка м и , числами и массивом. "
Раснолагая объектом, мы можем нреобразовать его в строко­
вы й ф орм ат JSON с номощью метода JS O N . s t r i n g i f y . П о­
{“title":"Plan 9 from Outer Space",“genre
смотрим, как это нроисходит... (вы мож ете вернуться к коду CUss iс“.Vat ing': 5 .“showt ime s*:
P3:OOpmV7:OOpmVn:OOpni-|J
m o v ie из главы 4 и добавить нриведенны й далее код в ниж ­
нюю часть своего сценария):

А вот р езульт ат : строковая


var jsonString = JSON. stringify (plan9Movie) ; версия объект а, отображаемая
alert(jsonString); в диалоговом окне alert.
Тенерь у нас имеется строка JSO N , нредставляю щ ая объект
m o v ie . Н а данны й момент мы можем взять эту строку и, на-
нрим ер, отнравить ее но нротоколу H TTP на сервер. Мы так­
JavaScript
же можем нолучать строку JSON с другого сервера. Донустим, JSON Movie is Plan 9 from Outer Space

сервер нрислал нам данную строку; как нреобразовать ее об­


ратно в объект, с которы м мы сможем что-нибудь сделать? Для 1
ok ")

этого нужно нросто воспользоваться «сестрой» метода JS O N .


s t r i n g i f y — J S O N .p a r s e . Д елается это так:
Ax da, т еперь мы используем
var jsoriMovieObject = JSON.parse(jsonString); <
это как настоящий о б ъ е к т ,
alert("JSON Movie is " + jsonMovieObject.title); обращаясь к его свойствам.

У меня новость !

ШTVPM Только что прибыли


специф икации! П еревер­
Введите данный URL-адрес. Что вы видите?
ните страницу!
h t t p ://search.twitter.сот/search.j son?q=hfhtml5

Примечание: браузер FirefoK предложит вам о т кры т ь


либо сокранить файл. Д л я от кры т ия можете использо­
ват ь TeKtEditj Блокнот или любой другой базовый т е к ­
стовый редактор.
обзор спецификаций mightygumball
Спецификации только что прибыли!

Т
Спецификации сервера Mighty Gumball
Спасибо, что согласились помочь!
Minify Gumball, Inc.
О т ч е т ы об уровне продаж, п ост уп аю щ ие от а в т о м а т о в
Там, где автомат для
продажи жевательной
для продажи жевательной резинки, собираются вм ест е
резинки никогда не пуст и доступны на нашем цент ральном сервере по адресу
наполовину

h t t p : //g u m b a ll. w ic k e d ly s m a r t. с о т /
В качестве ф о р м а т а для наших данных мы выбрали JSO N , и если
воспользоваться приведенным выше URL-адресом , то обратно
можно получит ь массив JSON -объ ект ов, кот орые выглядят так:
Название города; на данный м о м е н т
[ { "пате" :" C A M P B E L L " ^ ы т е с т и р у е м свои т орговы е а в -
"time": 1302212903099, т о м а т ы в Калифорнии-
" s a l e s " : 3} ,
В ремя поступления данного
от чет а в Миллисекундах .
{" n a m e " : " F R E S N O "
" time" : 1 3 0 2 2 1 2 9 0 3 1 0 0 , Количество проданной жвачки
" sales" : 2 } с м о м е н т а последнего от чет а.

Вт орой город, Фресно.


] А здесь будут другие города...

Введите данный URL-адрес в своем б р а у зер е , чтобы у в и д е т ь ,


Непре­ как в о т в е т п о с т у п а ю т значения. На экране должен появиться
один объект или более в массиве.
менно
сдел ш т е Вы также можете добавить п а р а м е т р la str e p o rttim e в конец
это URL-адреса, чтобы извлечь т олько о т ч е т ы , кот орые п о с т у ­
пили начиная с указанного врем ени . Например:
Просто
укажите
h t t p :/ / д ш п Ь а И .wickedlysmart.com/?lastreporttime=1302212903099 время
в Милли­
У нас сотни а в т о м а т о в по продаже жевательной резинки,
секундах
кот орые присы лаю т от чет ы прямо сейчас, п о эт о м у вы
должны у в и д е т ь , что обновление от чет ност и происходит
в среднем каждые S - 8 секунд. У ч т и т е , что эт о наш п р о и з ­
водственный с е р в е р , п о эт о м у мы просим вас п р е д в а р и т е л ь ­
но проводит ь локальное т ест ирование своего кода!
б ла го д а р и м , что согласились нам помочь! И п о м н и т е , что,
как говорит наш исполнительный директ ор, « а в т о м а т для
продажи жевательной резинки никогда не п у с т наполовину».
- Инженеры компании M ighty Gum ball

262 глава 6
общение с веб-службами

Пора за работу!
И так, мы нолучили специф икации от и нж енеров, а также
ноговорили с вами о X M L H ttpR equ est и JSON. Вы долж ны
быть уже готовы к тому, чтобы нереходить к нанисанию
кода и нерв о му зануску н рилож ения Mighty Gum ball.
Ранее мы с вами нанисали HTM L-разметку, но л ожив нача­
ло нашему веб-нриложению , и предусмотрели в н ей ссылку
на файл m i g h t y g u m b a l l . j s. Сейчас займемся нанисанием
кода, которы й будет в нем размещ аться. Н аномним, что
мы также оставили в HTM L-разметке место, где будем раз­
мещать данны е об уровне нродаж нрямо в < d iv > с i d в виде
« s a l e s » . Соединим все и наниш ем код.

Написание функции обработчика событий onload


У верены, что в данной нроцедуре для вас не будет ничего нового,
однако мы собираемся нанисать обработчик собы тий o n l o a d , ко­ Сначала проведем тестирова
то р ы й станет вы зы ваться носле н олной загрузки HTML; мы также Hue с использованием л о к а л ь­
предусмотрим ини ц ии рован ие Н ТТР-занроса для и звлечения дан­ ного файла (как и просили нас
ных об уровне нродаж. Когда данны е будут возвращ ены , мы нонро- инженеры из Mighty Gumball!),
сим XMLHttpRe q u e s t вызвать функцию u p d a t e s a l e s (нанисанием чтобы убедиться, что все
которой займемся чуть нозже): работает. Подробнее об эт ом
window.onload = function() { поговорим немного позже...
var url = "http://localhost/sales.json" ;
ф орм ируем XM LHttpRequest п у т е м созда-
var request = new XMLHttpRequest();
ния объект а, вызова метода open с испо ль-
request.o p e n ("GET" f u r l ); зованием нашего URL -адреса и последую щ е­
request.onload = function() { ^
--------- го присваивания свойства onload функции.
if (request.status == 200) { ^
' Проверяем, все ли в порядке,
updatesales(request.responseText);
а з а т е м ...
...когда загрузка данных б у ­
>; ^ --- дет завершена, произойдет
request.send(null); Наконец, от правляем запрос. вызов этой функции.

Ь
б уд ьте
Е с л и в ы используете Opera либо Internet Explorer 8
(или ниже), рекомендуем вам проводить тестиро­
вание с применением другого браузера. Об особен­
ностях поддержки Opera и старых версий Internet
o O H o j= > oJK H bi Explorer мы поговорим позже.

дальше ► 263
как проводить тестирование локально

Отображение данных об уровне продаЖ Жвачки


Тенерь нам необходимо нанисать обработчик u p d a te s a le s . О блегчим
задачу и нрибегнем к наиболее нростой реализации из возможных, но-
скольку всегда сможем улучшить ее нозже: Извлечем элем ент <div>, ко­
торый уже помещен в HTML,
function updateSales(responseText) { и будем использовать его для
размещения данных.
var salesDiv = document.getElementByld("sales")

salesDiv.innerHTML = responseText; 8 качестве содержимого <div>


< - задаем ст року responseText.
} О разборе этого содержимого
мы вскоре поговорим... А сна­
чала давайте проведем т е ­
Внимание, впереди объезд! ^ стирование.

П риш ло врем я нровести н овы й тест-драйв, однако сначала нам необ­


ходимо сделать, так сказать, небольш ой крю к но объездному нути. И н­
ж енеры из комнании Mighty G um ball нонросили нас нровести тести­
рование локально, нреж де чем задействовать их производственны й
сервер, что является разумной идеей. Однако для этого нам потребу­
ется, чтобы данны е располагались на сервере, благодаря чему
X M L H t t p R e q u e s t сможет иснользовать нротокол H TTP
для их извлечения.
О тносительно серверов у вас есть несколько альтернатив:
■ если ваша ком нания раснолагает серверами, достунны-
ми для тестирования, то иснользуйте именно их;
■ либо вы м ож ете нрибегнуть к но мощ и хостинговы х
сервисов вроде GoDaddy, D ream host или одной из множества других
комнаний, предлагаю щ их услуги хостинга;
■ наконец, вы мож ете установить сервер нрямо на своем компью тере.
В этом случае ваши URL-адреса будут выглядеть нрим ерно так:

h t t p : / / l o c a l h o s t / m i g h t y g u m b a l l . h tm l

файлы также м о гу т располагаться в подкаталоге:


н а п р и м ер , h ttp ://lo c a lh o s t/g u m b a ll/mightygumball.html

Н еобходимые советы и указатели вы найдете на следующей странице.


И м ейте в виду, что хостинговы е окруж ения довольно сильно отлича­
ю тся друг от друга, ноэтому мы не можем нривести здесь общее руко­
водство для всех них. И если у вас не окаж ется легкого доступа к тому
или иному серверу, установка собственного сервера локально на своем
ком нью тере мож ет оказаться наилучшим выходом!

264 глава 6
общение с веб-службами

Как установить собственный веб-сервер


Установка собственного локального сервера на своем ком нью тере будет зависеть
от тина иснользуемой вами онерац и онн ой системы. Н иж е нриведены советы но
установке сервера в онерационны х системах OS X (также назы ваем ой Mac OS X),
Windows и Linux. П рочие варианты вы найдете на следующей странице.

Mac OS X Windows

У становка в еб -сер в ер а в о п е р а ц и о н н о й си ­ И н стал л яц и я с о б с т в е н н о г о в еб -сер в ер а в о п е р а ­


ст ем е OS X осущ ествл яется д о в о л ь н о п р о с т о . ц и о н н о й си ст ем е W in d o w s стала п р о щ е, чем э т о
Щ ел к н и те > System P r eferen ces (Н а с т р о й ­ бы л о р аньш е, бл агодар я установщ ик у M icrosoft
ки си ст ем ы ), п о сл е ч е г о в ы б ер и т е S h a rin g W eb P latform In staller (такж е назы в аем ом у W eb
(С ов м ест н ы й д о ст у п ). Н а п а н ел и слева п р о ­ P I). Текущая в ер си я п о д д е р ж и в а е т с я о п е р а ц и о н ­
верьте, устан ов л ен ли ф л аж ок W eb S h a rin g ны м и си ст ем а м и W in d ow s 7, V ista SP2, Х Р SP3+,
(С ов м ест н ы й веб-доступ): Server 2 0 0 3 SP2+, Server 2 0 0 8 и Server 2 0 0 8 R2
и д о ст у п н а для загрузки п о а д р есу h t t p : // w w w .
Zi Web S haring
m ic r o so ft.c o m / w eb / d o w n lo a d s / p la tfo rm .a sp x .
А к ти ви ров ав п а р а м етр W eb S h a rin g (С о в м ест ­
В качестве альтернативы м о ж н о уст а н о в и т ь п р о ­
ны й веб-доступ ) (л и б о о н уж е м о ж е т бы ть ак­
грам м у с откры ты м и сх о д н ы м кодом W am pServer,
ти в и р о в а н н ы м ), вы у ви ди те и н ф о р м а ц и ю о
к о то р а я п оста в л я ется вм есте с A p a c h e , Р Н Р и
том , как пол учить д о ст у п к своем у л окал ьн ом у
M ySQL для р а зр а б о т к и в еб -п р и л о ж е н и й . О н а л е г ­
серверу. Вы дол ж н ы и м еть в о зм о ж н о с т ь и с­
ка в и н ста л л я ц и и и уп р а в л ен и и .
п ол ь зовать l o c a l h o s t в м ест о IP-адр еса (к о­
т о р ы й и м е е т т е н д е н ц и ю и зм ен я ться п р и и с ­ З а гр у зи ть W am pServer на св о й к о м п ь ю т ер м о ж н о
п о л ь зо в а н и и D H C P -м ар ш р ути затор а, в силу с сайта h t t p : / /w w w .w a m p se r v e r .c o m /е п / .
ч ег о l o c a l h o s t лучш е п о д о й д е т в ваш ем
С ущ ествую т такж е др уги е д о ст у п н ы е р еш ен и я
сл учае). П о ум ол ч ан и ю ваш и ф айлы будут за ­
с откры ты м и сх о д н ы м к одом , п о эт о м у у вас будет
груж аться из Ь и р ://1 о с а Ш о 8 1 /~ И М Я _ П О Л Ь -
б о л ь ш о й вы бор .
З О В А Т Е Л Я /, куда о н и в св о ю о ч е р е д ь загру­
ж аю тся и з папки И М Я _ П О Л Ь З О В А Т Е Л Я /
Sites, п о эт о м у вы, в е р о я т н о , за х о т и т е со зд а т ь
там подк атал ог для M ighty G u m b all.

ф а и а т с к и о дистрибутивы Linux
Взглянем в лицо фактам: вы уже знаете, что делать в данном случае. Мы угадали?
Apache обычно устанавливается по умолчанию, поэтому читайте документацию
к используемому вами дистрибутиву Linux.

дальше ► 265
установка собственного веб-сервера

Как установить собственный веб-сервер (продолжение)


Вы хотите разм естить свои файлы на настоящем сервере в И нтернете? П рекрасно, Объезд
но знайте, что в данном случае у вас будет только один выход —воспользоваться ус­
лугами хостинга. Ознакомьтесь с приведенны м и ниж е советами, и внеред!

Услуги х о ст и н га , предоставляемые сторонними организациями...

Е с л и в ы не хотите заниматься установкой собственного сервера, то всегда мож ете восполь­

зоваться удаленным сервером, однако вам придется разм естить свои HTML-, JavaScript- и
CSS-файлы, а также JSO N -файл на одном сервере (о том, почему это так важно, поговорим
позже), следуя приведенному здесь примеру.
Больш инство хостинговы х сервисов обеспечат вам FTP-доступ к папке, в которую вы смо­
ж ете поместить все свои файлы. Если у вас есть доступ к подобному серверу, то выгрузите
туда все файлы и подставьте имя данного сервера вместо lo c a l h o s t везде, где увидите его.

_________________ гхэ Г Т Т П f D h f h t m iS 5 3

Q chapterl
Q chapt*f2
п chapter3
Р~1 chapter4 Вы можете прибегнуть
D chapters
r~| Chapters к Т Р -п р о гр а м м е (н а п р и ­
р-i chapter7 м е р j Transit, Cyberduck
f~ | chapters
p i chapter9 или VJinSCP), для вы груз­
p~| chapter10 ки своих ф айлов, если не
х о т и т е использовать
FTP командной строки.
their stuff. (10 items)
your Stuff. (1 3 item s)

Мы составили список поставщ иков услуг хостинга на случай, если вам потребуется под­
сказка, однако их и так можно отыскать без особого труда; просто введите в поисковик
«веб-хостинг», и он выдаст вам массу вариантов. С оставленный нами список доступен по
адресу h ttp :/ / wickedlysm art.com /h fh tm l5 /h o s tin g /h o s tin g .h tm l. И дайте нам знать, если у
вас появится собственны й веб-сайт HTML5 в И нтернете, поскольку нам будет лю бопы тно
взглянуть на него!

---------------------------------------------------------------------------------------------------------------------------------

266 глава 6
общение с веб-службами

Возвращаемся к коду
Н а данны й момент мы нреднолагаем, что вы уже установили собственны й сервер, — это мож ет быть
сервер, вы полняю щ ийся на вашем локальном ком нью тере (как в наш ем случае), либо сервер, распола­
гаю щ ийся где-то в другом месте, и у вас есть к нему достун. И в том и в другом случае вы будете разм е­
щать свои HTML- и JavaScript-файлы на этом сервере, а затем укажете браузеру нуть к соответствующ е­
му HTM L-файлу. Вам также но требуется тестовы й ф айл с данны ми об уровне нродаж Mighty Gum ball,
ноэтому мы нредоставим вам нростой ф айл с такими данными, которы й вы сможете номестить н а свой
сервер. Д ля вашего н рилож ения он будет выглядеть так, будто ностунает с центрального сервера Mighty
Gum ball, обеснечиваю щ его обновление данны х ночти в реж им е реального времени, что даст вам воз­
мож ность протестировать свой код, не задействуя производственны й сервер Mighty Gum ball. Далее
но казано, как будет выглядеть данны й файл; он назы вается s a l e s . j son и вклю чен в код, иснользуемый
в этой книге и достунный в И н терн ете (вы мож ете и самостоятельно набрать его, если вам нравится
этот нроцесс):

[ { " паш е": ARTE S I A " , "t i me":1308774240669,"sales":8}, Ъудем использовать


sales.json для проведения
{ " п а ш е " : LOS ANGELES","time": 1 3 0 8 7 7 4 2 4 0 6 6 9 sales": 2 ) ,
тестирования, прежде
{ " п а ш е " : PASADENA","time": 1 3 0 8 7 7 4 2 4 0 6 6 9 sales":8},
^ чем обратимся к насто-
{ "паш е": STOCKTON","time": 1 3 0 8 7 7 4 2 4 0 6 6 9 sales": 2 ) , ящему производствен­
{ " п а ш е " : FRE S N O " ,"t ime": 1 3 0 8 7 7 4 2 4 0 6 6 9 sales":2}, ному серверу с данными
{ "паш е": SPRING VALLEY","time": 1 3 0 8 7 7 4 2 4 0 6 6 9 sales" :9}, об уровне продаж, п о ­
ст упаю щ их в режиме
{ " п а ш е " : E L V E R T A " t i m e " : 1 3 0 8 7 7 4 2 4 0 6 6 9 sales":5},
реального времени.
{ "паш е": SACRAMENTO" / ’t i me": 1 3 0 8 7 7 4 2 4 0 6 6 9 sales":7},
{ "паш е": SAN M A T E O " ,"time": 1 3 0 8 7 7 4 2 4 0 6 6 9 sales":1}]

Разместите данны й файл на своем сервере, носле чего


не забудьте обновить свой JavaScript, указав в нем URL- Г/- <
адрес этого файла. В наш ем случае он будет выглядеть как f ANGE L E S ' - M - » . . - . , , _________

h t t p : / / l o c a l h o s t / g u m b a l l / s a l e s . j so n:
URL в сво-
Полезно сначала пр от ест ир оват ь э т о т
V ем браузере, чтобы убедиться, что он работает. ('■«■**,‘SACRAXEJJTO* 111*40**9' ‘«W »5>,
window.onload = function() {
var url = "http://localhost/gumball/sales.json" ;
var request = new XMLHttpRequest () ; fib*
request.open ("GET" , u rl ) ; V_ Убедитесь, что здесь
request.onload = function() { указан правильный
URL-adpec.
if (request.status == 200) {
updateSales(request.responseText);
}
};
reques t .s e n d (nul1);

дальше ► 267
тестирование приложения mighty gumball версии 1

Давайте, наконец, проведем


jО.) |J», ijg
I
тестирование!
M ighty Gum ha]] Sales
Мы нроделали долгий нуть и, наконец, готовы не- |{*naxne*:*AJ:t TliSlA*t*tan!e*:lJ0Sn43406691pi*jej.*;S} <'] VUQS
A ^G a^\4m w ":J3087742«406& 9iT" iik s':2 } ,
реходить к тестированию нашего кода! < ТАЗАРРЛ'А'Лтте';13OT7742*P669,^iirat
<глга": ТЗГПХ:ЛТ1>?У‘."faint': --2}‘
Убедитесь, что ваши ф айлы HTM L, JavaScript, Гпате*«swung
VALLEY W i 1Ш7НЭШ№,<и»’Я). ^ “
JSON — и не забудьте о CSS — разм ещ ены на ис- i{ ’furftc": ’E L V E K T А’ *&ССИПI ЭОГГМВ Д В Д ,’nun’ J J ,
нользуемом вами сервере. Введите URL-адрес ва­ * ■ ' “SACRAMENTO",^rae'.' 1ШТ7^иоШ:±±\&'\7\ rrfiinier.’VA\
MATEO".'tijuc’.J ЭСЩ7743дабе9,'||1кл':] }|
шего HTM L-файла в браузере (в нашем случае это
h ttp : / /lo c a l h o s t / g u m b a ll /m ig h ty g u m b a ll.h tm l),
носле чего нажмите Назад...
t
Оформлено не слиш ком красиво,
зато видны требуемые данные.

П омнит е, что мы от правляли HTTP -запрос Т 7


для извлечения данных, содержащихся в sales.json,
Если у вас возникнут п р о­
которые за т е м просто сбросили в элем ент <div>
блемы, проверьте каждый
файл отдельно с исполь­
Похожеj все работает!
зованием браузера и уб е­
дитесь., что они доступны
Зат ем дважды проверьте
свои URL-адреса.

' Здорово! Да, пришлось потрудиться.


Нам потребовалось разобраться, как совер­
шать HTTP-запросы и устанавливать соб­
ственный сервер, но в итоге все получилось!
Я уже задумываюсь об отличных приложе­
ниях, которые смогу создать для использо­
вания всевозможных веб-служб, общаться
с которыми я теперь умею.

268 глава 6
общение с веб-службами

Производим впечатление на клиента...


Мы нрилож или массу усилий, чтобы в итоге нолучить работаю щ ее нрилож ение. Это зам ечательно, од­
нако наш клиент Mighty G um ball будет более внечатлен, если данное нрилож ение будет еще и выглядеть
хорош о. Н иж е ноказано, какого именно результата мы собираем ся добиться.

Что мы имеем Чего мы хотим


Л А О Mighty Gumball
jo] 1^] II I jnrypu-ng. |7Т7];о 1;^[88][ 4- |0hnp://lre*llw«/9um(Mll/roflftr!flyu^iMll.hEiT 6 | (О.- Cooglt

Mighty Gumball Sales Mighty Gumball Sales


[{ ’name’ :’ARTESIAVtime":1308774240G69t*sa]es*:8}r{*name*:’LOS
ARTESIA sold 8 gum baits
ANGELES"/time*: 1308774240669,*sales":2},
{"nan*":*PASADENA\*time":1308774240669,*sales":8}, LOS ANGELES sold 2 gum balls
{*tiame":’STOCKTON*.*lLme":1308774240669,“sales*:2}r
{ "name": ’FRESNO* ."time*: 1308774240669,*sales*:2},{ "name*:"SPRING PASADENA sold 8 gum balls
VALLEY" .time*: 1308774240669.*sales*:9>.
{ *name*:*ELVERTA’ ."time": 1308774240669,*sa3es*:3}, STOCKTON sold 2 gum balls
{ "name":"SACRAMENTO* ."time*: 1308774240669,*sales":7},{ "name*: "SAN
MATEO" ,*time*:1308774240669 .’sales’ : 1>] FRESNO sold 2 gum balls

SPRING VALLEY sold 0 gum balls

ELVERTA sold 5 gum balls

SACRAMENTO sold 7 gum balls

SAN m a te o sold l gum balls

т
Пока мы просто сбрасываем J S O N -массив п р я ­
мо в браузер. В некоторой степени э ф ф е к т и в ­
С Здесь мы использовали JSON -массив
и преврат или его в красиво от обра­
но, но р е з у л ь т а т получается не очень красивым. жаемые данные.
Какая жалость, ведь есть целая с т р у к т у р а
данных, которая только и ждет более э ф ф е к ­
тивного подхода к ее использованию!

Вот что тр е б у ется , чтобы о б е с п ечи ть более кр а си в о е о то б р аж е н и е д ан н ы х:

© Сначала нам нужно взять данные, полученные от объекта


XMLHttpRequest (которые представляют собой простую JSON-
строку), и преобразовать их в подлинный JavaScript-объект.

(2) Затем мы сможем пройтись по результирующему массиву и до­


бавить новые элементы в объектную модель документа (ЬОМ) —
по одному в случае с каждым элементом данных об уровне про­
даж в массиве.

дальше ► 269
добавление поддержки json

Дорабатываем код с целью использования JS0N


В ыполним описанные выше два шага и откорректируем наш код необходимым образом:

© Сначала нам нужно взять данные, полученные от объекта X M L H ttp R e q u e s t (кото­


рые представляют собой простую JS O N -строку), и преобразовать их в подлинный
JavaScript-объект.
Чтобы это сделать, обновим функцию u p d a t e S a l e s , первым делом удалив строку
кода, которая задает для < d i v > содержимое в виде строки r e s p o n s e T e x t , и преоб­
разуем r e s p o n s e T e x t из строки в ее JavaScript-эквиволент с помощью j s o n . p a r s e .

function updateSales(responseText) {

var salesDiv = document.getElementByld("sales");

aaleaDiv. innerUQML - reaponaeTexte; & Эта строка нам больше


не нужна.
var sales = JSON.parse(responseText);

}
Здесь мы б ерем о т в е т и и с п о л ь з у е м JSO N .p arse для
преобразования его в J a v a S c r i p t -о б ъ е к т (в данном случае
э т о б удет м ассив) и п р и с ва и ва е м его п е р е м е н н о й sales.

Теперь пройдемся по результирующему массиву и добавим новые элементы в объ­


ектную модель документа (DO M ) — по одному в случае с каждым элементом дан­
ных об уровне продаж в массиве. В нашем случае мы создадим новый < d i v > для
каждого элемента данных:
function updateSales(responseText) {
var salesDiv = document.getElementByld("sales");
var sales = JSON.parse(responseText); Совершаем ит ерацию no каждо­
for (var i = 0; i < s a les.length; i++) { м у э лем ент у данных в массиве.
var sale = sales[i]; Д ля каждого элем ент а данных
мы создаем <div> и присваива­
var div = document.createElement ("div") ем ему класс « sa leltem » (ис-
div. setAttribute ("class" , "saleltem") ; ' пользуемый CSS).
div.innerHTML = sale.name + + sale.sales + gumballs";
salesDiv. appendChild (div) ;
Задаем содержимое для элем ент а <div>
с помощ ью innerHTML, после чего добав­
ляем его в качестве дочернего элемент а
по отношению к salesDiv.

270 глава 6
общение с веб-службами

Заключительный этап... u_iJjo] ГаНГЩггтнгг-—^ УСи,Ы


и"

В ы уж е зн аете , к а к будет в ы гл я д е ть к о н е ч н ы й результат,


н о в се -та ки в н е с и т е о п и с а н н ы е в ы ш е и з м е н е н и я в с в о й
ко д . В з гл я н и т е более п р и с т а л ь н о на к о д , п р и в е д е н н ы й
н а п р е д ы д у щ е й с т р а н и ц е , и уб е д и те сь, ч т о в ы п о л н о с т ь ю
в н е м р а зо б р а л и с ь. З а те м п е р е за гр у з и те в е б -с тр а н и ц у
M ig h ty G u m b a ll.
Как видите, конечный
р е з у л ь т а т получился
т а к и м j как мы вам
и говорили!

Тестирование прошло удачно, и теперь


вы, ребята, готовы перейти к использо­
ванию действующего производственного
^ сервера Mighty Gumball. Удачи!

Переходим к использованию действующего сервера


И н ж е н е р ы и з M ig h ty G u m b a ll п р о с и л и на с п р е д в а р и т е л ь н о п р о в е с т и т е с т и ­
р о в а н и е л о к а л ь н о , ч т о м ы и сделали. Т е пе р ь м ы г о т о в ы п е р е х о д и т ь к т е с т и ­
р о в а н и ю с и с п о л ь з о в а н и е м р е а л ь н о го се р ве р а M ig h ty G u m b a ll. Н а э т о т раз
в м е сто и з в л е ч е н и я с т а т и ч е с к о го J S O N -ф айла д а н н ы х будем и з в л е ка ть J S O N -
ф айл, к о т о р ы й д и н а м и ч е с к и ге н е р и р у е т с я с е р в е р о м M ig h ty G u m b a ll. Н а м
п о тр е б у е тс я о б н о в и т ь U R L -адрес, и с п о л ь з у е м ы й о б ъ е к т о м X M L H ttpR e quest,
и и з м е н и т ь е го т а к и м о б р а зо м , ч т о б ы о н вел к се р в е р у M ig h ty G u m b a ll.

Д авайте сделаем это: URL-адрес сервера Mighty Gumball. Замените


прежний URL-адрес э т и м и сохраните. \
win d ow .onload = f u nction() { у_)
var url = "h t t p ://gumball.wickedlysmart.com" ;
var request = new XMLHttpRequest();
request.o p e n ("GET", url);
request.onload = function() {
if (request.status = 200) {
updateSales(request.responseText);
}
};
Эйджей, к о н т р о ­
request.send(null);
лер качества

дальше ► 271
проблема с mighty gumball

Тест-драйв с применением действующего сервера.


У б е д и те сь , ч т о в ы с о х р а н и л и и з м е н е н и я , ка с а ю щ и е с я
U R L -адреса, в своем ф айле m i g h t y g u m b a l l . j s на с е р ве р е ,
если х о т и т е п р о д о л ж а т ь и з в л е ка ть H T M L оттуда, л и б о
л о ка л ь н о на ж е с т к о м д и с ке , если и с п о л ь зу е те lo c a lh o s t.
В ы уж е зн а ете , ч т о делать дальш е: у к а ж и т е своем у б р а ­
узер у п уть к с о о тв е т с тв у ю щ е м у H T M L -файлу, п о сл е ч е го
у в и д и те , к а к будут п о с т у п а т ь о п е р а т и в н ы е , к р а с и в о
о ф о р м л е н н ы е , н а с т о я щ и е д а н н ы е о т т о р г о в ы х а в то м а ­
то в M ig h ty G u m b a ll п о всему м и р у !

Хьюстон, у нас
проблема! Идите скорее сюда,
мы вообще не можем получить
какие-либо данные об уровне продаж Это еще что?!
после того, как перешли к исполь­ Мь/ не видим вообще
зованию действующего сервера никаких данных!
Mighty Gumball!

Ой!
А все вы гл яд ело т а к х о р о ш о ; м ы уж е
п р е д с та в л я л и себе, к а к будем п о т я ­
ги в а ть м и н е р а л ьн ую воду « P e rrie r» и
о тм е ч а ть у с п е ш н о е за в е р ш е н и е еще л
о д н о г о п р о е к т а с M ig h ty G u m b a ll. Примечание для редактора:
А т е п е р ь все м о ж е т п о й т и н а с м а р ­ вообще-то мы представляли
ку. Л а д н о , н е б уде м и з л и ш н е д р а ­ себеj как будем обналичивать
м а ти зи р о в а ть си туа ц и ю , но в чем Жирный чек и от пр а в л ят ь вам
ж е в с е -т а ки дело? Ведь все д о л ж н о э т у книгу! А вм ест о этого
р а б о та ть ! нам т еперь придется допи­
сывать ее, рассказывая о т о м ,
С делайте гл у б о к и й вдох. Т ом у есть
л о г и ч е с к о е о б ъ я с н е н и е ...
как найти выход из очередной
непростой ситуации!

Эйджей, расстроенный контролер качества

272 глава 6
с веб-службами

Неожиданный поворот событий!


Мы вообщ е не в и д и м каких-либо данны х на странице
M ighty Gum ball. Все нрекрасно работало, но ка мы не
нереш ли к иснользованию действующего сер­
вера...
Удастся ли нам найти нричину нроблемы?
Удастся ли нам устранить ее?
О ставайтесь с нами... мы ответим на эти вонросы, а также...
Между тем ноны тайтесь самостоятельно разобраться в том,
что именно нош ло не так и как это можно исправить.

КЛЮЧЕВЫЕ
МОМЕНТЫ

■ Для извлечения HTML-файлов или данных с сервера XMLHttpRequest может применяться для извлечения
браузер отправляет НТТР-запрос. всевозможного текстового содержимого (например,
XML, JS0N и др.).
■ HTTP-ответ включает код ответа, который позволяет
узнать, произошли ли какие-либо ошибки при выпол­ XMLHttpRequest Level 2 является самой последней
нении запроса. версией X M L H ttpR equest, однако данный стандарт
все еще находится в разработке.
■ Код 2 0 0 в HTTP-ответе означает, что при выполнении
запроса не произошло никаких ошибок. Чтобы использовать XMLH ttpRequest, СООТВвТСТВу-
ющие файлы необходимо разместить на сервере,
■ Для отправки HTTP-запроса из JavaScript используется
с которого и будут запрашиваться данные. Вы можете
Объект X M LH ttpR equest.
установить локальный сервер на своем компьютере
■ Обработчик событий o n l o a d объекта XMLHttpRequest для проведения тестирования либо воспользоваться
обрабатывает получение ответа от сервера. хостинговыми сервисами.

■ JSON-ответ на X MLHttpRequest помещается в свой­ Свойство o n l o a d объекта X M L H t t p R e q u e s t не


ство r e s p o n s e T e x t объекта r e q u e s t . поддерживается старыми версиями браузеров, такими
как Internet Explorer 8 и ниже, а также Opera 10 и ниже.
■ Для преобразования строки r e s p o n s e T e x t В JS0N
В этом случае вы можете написать код для проверки
используется метод J S O N . p a r s e .
версии браузера и обеспечения альтернативы.
■ X M L H t t p R e q u e s t задействуется в приложениях
для обновления содержимого, (например, карт или
электронной почты) без необходимости перезагрузки
страницы.

дальше ► 273
З ф И М И та р в & е Э Д й & г» ч а с т ь г
Интервью недели:
Internet Explorer и «Вы сказали JSO N ?»?

Head First: Д обро нож аловать вновь на наше интервью , X M LH ttpR equest. Я хотел снросить у Вас на­
счет браузеров —Вы ноддерж иваетесь только их новейш им и версиями?
XMLHttpRequest: М еня не зря назы ваю т старожилом; браузеры ноддерж иваю т м еня с 2004 года.
Head First: Ч то ж, а как насчет м орального устаревания, Вас это не беснокоит?
XMLHttpRequest: Я объект, новая версия которого выходит каждые 10 лет или около того. В настоя­
щ ий момент нолны м ходом идет работа над м оей второй версией, назы ваемой X M LH ttpR equest Level 2.
Ф актически, больш инство соврем енны х браузеров уже ноддерж иваю т данную версию.
Head First: Это внечатляет. А в чем заклю чаю тся особенности версии Level 2?
XMLHttpRequest: П реж де всего в ноддерж ке большего количества тинов собы тий, благодаря чему вы
сможете, нанрим ер, отслеж ивать ход вы нолнения занроса и нисать более элегантны й код.
Head First: Говоря насчет браузерной ноддержки...
XMLHttpRequest: До этого мы сейчас дойдем... не торонитесь...
Head First: По слухам, вы и In tern et Explorer на самом деле не ладите друг с другом...
XMLHttpRequest: Вы что, шутите? Вся и стори я X M LH ttpR equest началась с In te rn e t Explorer.
Head First: А как насчет ActiveXObject и X D om ainRequest? Вам доводилось слышать эти имена?
XMLHttpRequest: Это мои нрозвища! Так меня назы ваю т в Microsoft! Да, я согласен, что наличие у меня
разны х им ен — не очень хорош о, однако нод ними подразумеваю тся инструменты , которы е реш аю т
одну и ту же задачу. Для улаживания данной ситуации Вам нотребуется лиш ь небольш ое количество
дополнительного кода, а с точки зрен и я носледних верси й браузера In tern et E xplorer от M icrosoft начи­
ная с версии 9 и выше все и так будет в норядке. Если это новость для Ваших читателей, то я с радостью
задержусь носле интервью , чтобы нозаботиться о том, чтобы их код был совместим с более старыми
версиям и In tern et Explorer.
Head First: М ило с Вашей стороны , но мы займемся этим вонросом как-нибудь нозж е в данной главе.
XMLHttpRequest: Эй, я хорош ий нарень и не стану бросать ваших читателей наедине с нроблемой.
Head First: Л овим Вас на слове. И еще один вонрос: В ы у н о м и н ал и ^ С Ж и говорили, что являетесь его
большим ноклонником. А что, JSO N P Вас вообщ е никак не беснокоит? По слухам, многие люди исноль-
зуют его вместо Вас.
XMLHttpRequest: Да, с номощью JSO N P вы, конечно же, сможете извлекать данны е, однако это всего
лиш ь ловкий халтурны й нрием. Я хочу сказать: задумайтесь о том витиеватом коде, которы й вам нри-
дется нанисать. И как насчет безонасности?
Head First: Я не слишком технически нодкован и знаю лишь, что люди говорят, будто он дает им воз­
мож ность обойти нроблемы, которы е Вы не нозволяете реш ить. Внрочем, наше время истекло.
XMLHttpRequest: Ч то ж, ну хотя бы в части «не слиш ком технически нодкован» Вы не ошиблись.

274 глава 6
общение с веб-службами

Свойство onload объекта XMLHttpRequest не поддер­


]}удьше живается устаревшими версиями браузеров, однако из
оС 1 Ц о |Э о Ж Н ь х этой ситуации есть простой выход.

Мы использовали request, onload для определения функции, вызываемой, когда завер­


шается извлечение запрошенных данных с сервера. Это возможность XMLHttpRequest
Level 2 (считайте ее «версией 2»). Версия XMLHttpRequest Level 2 остается все еще до­
вольно новой, то есть многие пользователи могут до сих пор использовать браузеры,
которые ее не поддерживают. В частности, Internet Explorer 8 (и ниже), а также Opera 10
(и ниже) поддерживают только XMLHttpRequest Level 1. Хорошая новость заключается в
том, что новые возможности ХМ LHttpRequest Level 2 являются расширениями, поэтому
вы сможете без проблем продолжить использовать именно возможности версии 1 во всех
браузерах; это всего лишь означает, что ваш код не будет отличаться особой элегант­
ностью. Вот код для использования XMLHttpRequest Level 1:

Большая часть кода


для использования
X M L H ttp R e q u e s t Level 3-
...Однако в ХМ LHttp Request Level П
нет свойства request.onload, п о ­
является такой же, как
э т о м у вместо него вам п р и ­
и раньше...
дется использовать свойство
function i n i t () onreadystatechange.
var url "h t t p ://localhost/gumball/sales.jison"
г

var request = new XMLHttpRequest();

request.onreadystatechange = function() {

if (request.readyState == 4 && request.status == 200) {

updateSales(request.responseText); З а т е м проверьте
readyState, чтобы
убедиться, что з а ­
грузка данных за в ер ­
};
шилась. Если значением
request.o p e n ("GET", url) readyState является 4,
то вы будете знат ь,
request.send(null); Вы также можете что загрузка закончена.
проводить проверку
f на предм ет других зн а ­
See остальное, no большей чений readyState и status
част и, является т аким же,
с и,елы-о выявления р а з ­
как и раньше.
личных ошибок.

дальше ► 275
выяснение, что пошло не так

Помните, как мы столкнулись с неожиданным


поворотом событий? Неполадки с приложением
Наш к о д нрекрасно работал, когда мы иснользовали свой локальны й сервер, но как только мы нереш лн
на действую щий сервер Mighty G um ball в И н терн ете, с наш им нрилож ением возникли неноладки!

Чего мы оЖцдали: Ч т о мы подучили:

Я О П Mighty Gumbtl n o n Mighty Gumball


•«j*■ О S3 + !^hWp://kKalta*t/»uft*all/mi9MY0umha«-htrr, С ](Q r Googlf ■*j 0 9 ] SS + j^Mrp://kxaltatf/0uir*aU/mightyi0umba«-htrr, Oooglf

Mighty Gumball Sales Mighty Gumball Sales


ARTESIA sold 8 gum balls

LOS ANGELES sold 2 gumballs

PASADENA sold 8 gumballs

STOCKTON sold 2 gumballs

FRESNO sold 2 gumballs

SPRING VALLEY sold 9 gumballs

ELVERTA sold 5 gumballs

SACRAMENTO sold 7 gumballs

SAN MATEO sold 1 gumballs

В о т как в итоге выглядит наша страница А вот как в итоге выглядит наш а стра­
но еле того, как мы вы нолнили код и из­ ниц а но еле того, как мы вы нолнили код
влекли данны е об уровне нродаж со сво­ и извлекли данны е об уровне нродаж с
его локального сервера, иснользуя адрес сервера Mighty Gum ball, используя адрес
http: / /lo c a lh o st / gum ball / sales.json. http: / / gum ball.wickedlysm art.com .

Что Же делать дальше?!


Пожалуй, дальше мы будем делать то же,
что и всегда, — соберем всех членов ко­
манды и быстро все обсудим. Мы уверены,
что все вместе (включая вымыш ленны х
нерсонаж ей) мы сможем вы яснить нричи-
ну нроблемы! Фрэнк? Джим? Джо? Где вы Эйджей, довольно
все? А, вот где —н а следующей странице... сильно расстроенный
контролер качества

276 глава 6
общение с веб-службами

Д ж им: URL-адрес правильный?


Ф рэнк: Да, правильны й, я уже вводил его в браузере,
чтобы убедиться в том, что увижу ожидаемые нами
данные об уровне продаж, и все нормально работало.
Не понимаю...
Д ж о: Я заглянул в консоль JavaScript в браузере
C hrom e и увидел что-то об управлении доступом и ис­
точниках или доменах.
Ф рэнк: Хм?

f Ребята, где вы были,


когда мы занимались проектом S+arbuzz \
Coffee? Если помните, у нас была проблема 1
с аналогичным поведением. Держу пари, что на
сДж им этот раз вы столкнулись с междоменными пробле
мами, поскольку запрашиваете данные с сервера,
отличного от того, с которого исходит ваша страни
ца. Браузер рассматривает все это как проблему
безопасности. /

Хм, а нельзя ли освежить в нашей


памяти то, как браузер подходит
к вопросам безопасности?

Джуды

дальше ► 277
обзор браузерной политики безопасности

Что за браузерная политика безопасности?


Да, с наш ей стороны было стыдно налететь на такую «корягу», — достаточно лишь
нодумать о том, в какое нолож ение нри этом мы ставим вас, читателей, —но Джуди
нрава, браузер задействует нолитику безонасности в случае с НТТР-занросами с ис­
пользованием X M L H ttpR e quest, которая мож ет вызы вать нроблемы.
Так что это за нолитика такая? Это браузерная нолитика, которая подразумевает, что
вы не сможете извлечь данны е из домена, отличного от домена, из которого стра­
ниц а загружается как таковая. Донустим, вы создали сайт DaddyW arBucksBank.
com и кто-то взломал вашу систему и внедрил JavaScript-код, которы й собира­
ет персональны е данны е пользователей и делает с ним и всевозмож ны е инте­
ресны е вещ и, установив соединение с сервером HackersN eedM oreM oney.com .
Звучит скверно, не так ли? Ч тобы номеш ать нодобным вещам, браузеры п реп ят­
ствуют соверш ению с иснользованием X M L H ttpR e quest НТТР-занросов в домены,
отличные от исходного домена, из которого загружается ваша страница.
П осмотрим , какое новедение можно считать нриемлемы м в случае с JavaScript-
кодом, а какое нет.

Приемлемое поведение 6 случае J a v a S c r i p t - кода

Сначала пользователь (посредством браузера) совершает запрос HTML-страницы


(и, конечно же, любых ассоциированных с ней JavaScript- и CSS-файлов):

Сервер
успешно
Ваш браузер о т ­ возвращает
правляет запрос запраш ива­
страницы из ем ую вами
doodD om ain.com . страницу.

Браузер GoodDomain.com

Странице требуются некоторые данные из GoodDomain.com, поэтому она запра-


шивает их с использованием XMLHttpRequest:

располагаются в одном и т ом же^домене. jf-fc


Сервер
Г успешно воз­
вращает
запрошенные
данные.

Браузер GoodDomain.com

278 глава 6
общение с веб-службами

Неприемлемое поведение 6 случае JavaS cript-kog a:


Тенерь носмотрим, что нроизойдет, когда ваша страница, располагаю щ аяся в G oodD om ain.com ,
ноны тается занросить данны е с использованием X M L H ttpR eq uest из BadD om ain.com .

Как и ранее, браузер совершает запрос страницы, которая располагается в GoodDomain.com.


Сюда могут входить JavaScript- и CSS-файлы, также располагающиеся в GoodDomain.com.

Сервер
Ваш браузер о т ­ успешно
правляет запрос возвращает
страницы из запраш ива­
QoodDomain.com. ем ую вами
страницу.

Браузер GoodDomain.com

Однако на этот раз у нас имеется код, которому требуются данные из другого источника, то есть
из BadDomain.com. Посмотрим, что произойдет, когда страница запросит эти данные с использо­
ванием XMLHttpRequest::
Браузер видит, что
Ваша с т р а н и ­ это запрос в домен,
ца использует отличный от т ого ,
XMLHttpRequest в кот ором р асп о­
для попытки лагается ст раница,
запроса данных, и п р е п я т с т в у е т его
располагающихся совершению. То есть
в BadPomain.com в запросе будет о т ­
казано.
Браузер GoodDomain.com

Сервер BadPomain.com т ак и не
увидит запрос; полит ика безопас­
ности вашего браузера во с п р еп ят ­
с т ву е т его совершению прежде, BadDomain.com
чем это могло бы случиться.

дальше ► 279
обзор имеющихся вариантов

Да уж, славно потрудились —


написали столько кода, а он так и не будет
работать? Л нельзя ли просто скопировать наши
—i файлы на сервер Mighty Gumball?

Обычно ответ на подобный вопрос бывает


утвердительным. Допустим, вы являетесь раз­
работчиком, работаю щ им над кодом для Mighty
G um ball, а в этом случае у вас, скорее всего, будет
доступ к серверу данной компании (или к людям,
которы е могут произвести разверты вание ф ай ­
лов на соответствующ ем сервере за вас), где вы
сможете разм естить все свои файлы и избежать
лю бых междоменных проблем. Однако в данном
случае (хоть нам и н еп риятно разруш ать вашу
По крайней мере веру в правдоподобность излагаемой ситуации)
не в рамках Ь\од вы на самом деле поработаете на Mighty Gumball,
жета, выделенного а являетесь читателями книги, и мы не можем
нам редактором! дать возмож ность ты сячам людей заниматься
копированием своих файлов на сервер Mighty
Gumball.
Так к чему же мы приш ли? К тупиковой ситуации?
Нет, у нас есть несколько вариантов, как можно
ностунить в данном случае. Взглянем на них...
общение с веб-службами

Какие у нас варианты?


Будем честны: все это время мы знали, что м еж источниковы й занрос X M L H ttpR e quest н отерн ит неудачу.
Однако, как уже отмечалось ранее, нри создании н рилож ений вы зачастую будете раснолагать досту-
ном к соответствующему серверу, так что это не станет нроблем ой (а нри создании нрилож ений, в зна­
чительной стенени зависящ их от ваших собственных данных, иснользование X M L H ttpR e quest обычно
оказы вается онтимальны м выбором).
Однако в данны й момент мы можем услышать от вас следующее: «Все это, конечно, здорово, но как, на­
конец, заставить наш код работать?». Ч то ж, есть два снособа сделать этот

Способ 1: использовать уже размещенные нами на сервере файлы.

Мы уже разм естили для вас файлы на нашем сервере но адресу:


h t t p : //g u m b a ll .w ic k e d ly s m a r t. с о т / g u m b a ll/g u m b a ll .h tm l

П роведите тестирование, введя данны й URL в своем браузере, что


но зв о лит увидеть в действии код, которы й вы набирали до сих нор.

Способ 2: использовать другой подход к извлечению данных.

X M L H ttp R e q u est является отличным инструментом для извлечения данны х в ваши нрилож ения,
если эти данны е располагаю тся в том же домене, что и нрилож ения. Но вдруг вам нотребуется
извлечь данны е из стороннего источника? Ч то делать, если вам нонадобятся данны е, которы е
мож ет дать, нанрим ер, Google или Twitter? В нодобных ситуациях неред нами встает нроблема,
которую нужно реш ить путем ноиска иного нодхода к извлечению данных.
О казы вается, есть другой нодход, которы й основан на JSON и известен как JSO N P (JSON with
P adding —JSO N P с нодкладкой; согласны, звучит странно, однако ноговорим об этом чуть ноз-
же). Н адевайте свой реактивны й ранец, носкольку снособ его работы немного «с другой нлане-
ты», если вы нонимаете, что мы имеем в виду.

дальше ► 281
знакомство с jsonp

Д ж о: Н епременно! А что это такое?


Д ж им : Похоже, что другой нодход к но лучению данных
от веб-служб для нередачи в наши нрилож ения.
Фрэнк: О т меня здесь не будет толку, носкольку я всего
лишь дизайнер.
Д ж им : Фрэнк, я думаю, что все не так уж и плохо. Я бы­
стро п роверил с номощью Google, что такое JSONP, и уз­
нал, что это, по сути, снособ заставить тег <script> вынол-
нять работу по извлечению данных.
Джо: А разве так можно?
Джим: К онечно можно — многие крунные сервисы нод-
держ иваю т такой нодход, нанрим ер Twitter.
Фрэик: Все это нохож е на какой-то халтурны й нри ем.
Джо: Да, и я о том же. Я имею в виду, как иснользование
тега <script> м ож ет быть нриемлемы м нодходом к извле­
чению данных? Я даже нонять не могу, как он вообщ е сра­
ботает.
Джим: Я сам еще далеко не нолностью в этом разобрался.
Но здесь можно рассуждать так: когда мы иснользуем эле­
мент <script>, он извлекает код для нас, ведь так?
Джо: Да, это так...
Джим: А что, если мы номестим данны е в этот код?
Джо: П роцесс ношел, все закрутилось-завертелось...
Фрэик: Да, можно сказать, как хомяки в колесе...

282 глава 6
общение с веб-службами

Присаживайся,
Кузнечик. Зачастую то,
чему я учу, ты уже, в сущ­
ности, знаешь...

Гуру HTML5: ...и этот как раз один из таких случаев. Кузнечик,
взгляни на этот код:
Что он делает?
Данным
Веб-разработчик: Если произвести код ра спо­
его оценку, предполагая при этом, лагается
что он выполняется в браузере, то данный код выведет диа­ по э т о ­
логовое ОКНО a l e r t С ТеКС ТО М "woof". м у URL-
Гуру: Да, верно. Создай свой собственный простой HTML- адресу.
файл и помести в него < s c r i p t > , расположив данный элемент
в <body>, как показано далее:

< s c r i p t s r c = " h t t p : / / w i c k e d l y s m a r t . c o m / h f h t m l 5 / c h a p t e r б/ d o g . j s ">


< /sc rip t>

Гуру: Что он делает?


Веб-разработчик: Загружает страницу, которая загружает с
сервера wickedlysmart.com JavaScript-код, содержащийся в
файле d o g . j s и вызывающий функцию a l e r t , в результате
чего браузер выводит диалоговое окно alert с текстом "w oof".
Гуру: Получается, что JavaScript-фойл, загружаемый из
другого домена, может вызывать функцию в твоем браузере?
Веб-разработчик: Теперь, когда вы так выразились, да, Гуру,
я полагаю, что именно так все и происходит. Как только
файл d o g . j s , находящийся на сервере wickedlysmart.com,
подвергается извлечению, он вызывает функцию a l e r t
в моем браузере.
Гуру: По адресу http://wickedlysmart.com/hfhtml5/chapter5/
dog2.js располагается еще один файл со следующим
JavaScript-кодом:

anim alsays("dog", "w oof");

Гуру: Что он делает?

дальше ► 283
гуру дает урок по jsonp

Веб-разработчик: Он схож с кодом из файла d o g . j s , однако в данном случае вызову будет под­
вергаться функция a n i m a ls a y s . Кроме того, функция обладает не одним, а двумя аргументами: тип
животного и звук, который оно издает.
Гуру: Напиши функцию a n i m a ls a y s и добавь ее в элемент < s c r i p t > в < h e a d > твоего HTML-файла
над элементом < s c r i p t > , указывающим на wickedlysmart.com.
Веб-разработчик: Вот так?

f u n c t i o n a n i m a l S a y s ( t y p e , so u n d ) {
a l e r t ( t y p e + " says " + s o u n d );
}

Гуру: Очень хорошо, ты делаешь успехи. А теперь измени ссылку своего другого < s c r i p t > , того,
который указывает на d o g . j s , чтобы он стал указывать на d o g 2 . j s , и перезагрузи страницу в браузере.
Веб-разработчик: У меня на экране появилось диалоговое окно a l e r t с сообщением " d o g s a y s w o o f" .
Гуру: Теперь переключись на http://wickedlysmart.com/hfhtml6/chapter5/cat2.js, измени ссылку
своего < s c r i p t > , чтобы он стал указывать на c a t 2 . j s , и посмотри, что будет.

a n i m a l S a y s ( " c a t " , "m eow ");

Веб-разработчик: На экране появилось диалоговое окно a l e r t с сообщением " c a t s a y s m e o w ".


Гуру: Получается, что JavaScript-файл, загружаемый из другого домена, может не только вызывать
любую функцию в твоем коде, какая ему будет необходима, но и передавать нам любые данные,
какие ему потребуется?
Веб-разработчик: Вообще-то я не вижу никаких данных, только два аргумента.
Гуру: А разве аргументы не являются данными? Что, если внести изменение, в результате чего
аргументы станут выглядеть так:

v a r anim al = { " ty p e " : "cat", "sound": "meow"}; cat 3.js


an im alS a y s(a n im a l);

Веб-разработчик: Теперь функции a n i m a ls a y s передается один аргумент, который является объ­


ектом. Хм, несомненно, в моих глазах этот объект начинает становиться похожим на данные.
Гуру: Ты можешь переписать функцию a n i m a ls a y s таким образом, чтобы она использовала новый
объект?
Веб-разработчик: Попробую...

284 глава 6
общение с веб-службами

Веб-разработчик: Вот так?

fu n c tio n anim alsay s(an im al) {


a l e r t ( a n i m a l . type + " says " + a n im a l. so u n d );
}

Гуру: Очень хорошо. Измени ссылку на http://wickedlysmart.com/hf html5/chapter6/dog3.js и про­


веди тест. Сделай то же самое с использованием http://wickedlysmart.com/hf html5/chapter6/cat3.js.
Веб-разработчик: Да, оба варианта работают, как и ожидалось в случае с моей новой функцией.
Гуру: А что, если изменить имя animalSays на updateSales?
Веб-разработчик: Гуру, я не понимаю, какая может быть связь между животными и уровнями про­
даж жевательной резинки?
Гуру: Давай поработаем сообща. Что, если мы переименуем dog3.js, присвоив ему имя sales.js,
и перепишем код следующим образом:

v a r s a l e s = [ { " n a m e " : "A R T E S IA " , " t i m e " : 130 8 774240 6 69, " s a l e s 8} ,
{"name":"LOS ANGELES", "time":1308 774240669,"sales":2}];
u p d ateS ale s (sales) ;

Веб-разработчик: Кажется, я начинаю понимать. Мы передаем данные посредством JavaScript-файла,


HO КОТОрыЙ ССЫЛаеМСЯ, ВМеСТО ТОГО, Ч Т О б ы СаМИМ ИЗВЛекаТЬ И Х С ИСПОЛЬЗОВаНИеМ X M L H t t p R e q u e s t .

Гуру: Да. Однако ты должен уметь видеть главное за массой второстепенных деталей. Разве при
этом их извлечение осуществляется не из другого домена? А это X M L H t t p R e q u e s t запрещает.
Веб-разработчик: Кажется, так оно и есть. Действительно похоже на какое-то волшебство.
Гуру: Здесь нет никакого волшебства, поскольку элемент <script> всегда так работал. Ответ все вре­
мя был рядом. Теперь поразмышляй над тем, как все это функционирует, чтобы закрепить материал.
Веб-разработчик: Да, учитель. «Закрепить материал»... знаете, эта фраза звучит для меня так зна­
комо, но в то же время как-то непривычно.

Использование JavaScript для извлечения данных является тем, с чем вам необхо­
димо слиться воедино. Возьмите лист бумаги или используйте внутреннюю сторо­
ну обложки этой книги. Нарисуйте сервер, на котором располагаются ваши HTML- и
JavaScript-фэйлы. Также изобразите сервер в другом домене, где размещаются фай­
лы dog3 .js и cat3 .js. Затем проделайте все шаги, которые браузер предприни­
мает для извлечения и использования объекта в каждом из файлов. После того как
вы во всем разберетесь, мы снова проделаем эти шаги вместе.

дальше ► 285
обзор jsonp

Знакомство с JSONP
Вы, вероятно, уже ноняли, что JSO N P нредетавляет собой еноеоб извлечения JSON-
объектов с использованием тега < s c r i p t > . Это также еноеоб и звлечения данны х (онять-
таки, в ф орм е JSO N -объектов), нозволяю щ ий избеж ать нроблем безонасности, связан­
ны х с н олитикой одного источника, которы е мы видели в случае с X M L H ttpR equest.
Н а н ротяж ени и следующих нескольких страниц мы с вами ношагово нройдем ся но тому,
как работает JSONP:
г Браузер

/^p\ Мы включили
элемент < s c r i p t >
в свою H TM L-разметку.
Источником для этого
<body>
оау^ элемента выступает
< h l > M i g h t y Gumball Sales</ URL веб-службы, кото­
< d i v id*" sales ••>
рая будет обеспечивать
для нас J S O N -данные
</diV> ,/ V, U Wickedlysmart.com/" X / script об уровне продаж жева­
<script src="h t t p ://gumball.wicke
тельной резинки.
</body>
</html> _____ ____

Когда браузер
сталкивается
с элементом <script>
на странице, он отправ­
( Т \ ТJ S O N -ответ посту­ ляет HTTP-запрос по
пает в форме строки, URL-адресу источника.
которую браузер разбирает
и интерпретирует. Л ю ­
бые типы данных преоб­
разуются в подлинный
JavaScript-объект и значе­
ния, а любой код подвер­
гается выполнению.

Помнит е, что на данный *


м о м е н т это всего лишь
строковое представление
/ j N Сервер воспринимает данный
объекта*
запрос как HTTP-запрос и отправ­
ляет в ответ на него JS O N . Веб-служба

286 глава 6
общение с веб-службами

Что означает буква Р в аббревиатуре JS0NP?


П ервое, что вам необходимо знать о JSONP, —это то, что у него глуное и не очень нонятное имя: JSON
with P adding (JSONP с нодкладкой). Если бы мы давали ему имя, то назы вали бы его как-то вроде JSON
with Callback (JSONP с функцией обратного вы зова), либо «извлеки мне JSO N -данные и вы нолни код,
когда вернеш ь их», либо нросто как-то но-другому вместо JSO N with Padding.
Однако все, что здесь подразумевается нод Padding, —это оберты вание JSO N -данных в вызов функции,
нрежде чем они ностунают в ответ н а занрос. Вот как все это работает:
Браузер
&
/ 7 \ Как и ранее, мы
по о -— включили элемент
<«.doctype html>
Chtml lang="en">
< s c r i p t > . Источником
для этого элемента
<body>
<hl>Mighty Gumball Sales</h >
выступает URL веб­
<div id="sales"> службы, которая будет
обеспечивать для нас
J S O N -данные .
</body>

Как и раньше, ког-


да браузер стал­
кивается с элементом
/ Т \ На этот раз, когда J S O N -
< s c r i p t > на странице,
ответ подвергается разбору
он отправляет НТТР-
и интерпретации, он уже обернут
запрос по URL-адресу
в вызов функции. Поэтому про­
источника.
исходит вызов данной функции
и создание объекта из J S O N -
строки, которая ей была передана.

На э т о т раз J S O N -
данные будут обернуты Л/
в вызов функции.
updateSales
f o \ Как и ранее, сервер воспринимает данный
запрос как обычный запрос и отправляет
в ответ на него J S O N -строку, о дн ако ... здесь
имеется небольшое отличие.

Прежде чем сервер отправляет обратно J S O N -


строку, он предварительно обертывает ее в Веб-служба
вызов функции, например в вызов функции
u p d ateS ale s.

дальше ► 287
разбираемся с функциями обратного вызова

Я понимаю, как использовать тег <script> для того, чтобы


заставить браузер извлекать JavaScript, и как сервер может по­
мещать свои данные в этот JavaScript. Но как быть с именем
функции? Откуда веб-служба знает имя нужной функции? Напри­
мер, откуда веб-службе Mighty Gumball известно, что необходимо
вызывать именно updateSales? Вдруг у меня имеется другая служба
О и я хочу вызывать, допустим, функцию updateScore, или a lert,
или какую-то другую?

Веб-службы позволяют указывать имя требуемой функции


обратного вызова.
О бы чно веб-службы позволяю т указывать имя необходимой вам
функции. Хоть мы и не говорили этого, но Mighty G um ball нре-
доставляет такую возможность. Когда вы будете указывать со­
ответствующ ий URL-адрес, добавьте в его конец параметр, как
показано дальше:
h t t p ://gumball.wickedlysmart.com/?callback=updateSales
-------
u , n, л А здесь мы добавили URL-
Ооычныи URL -адрес.
па р а м е т р c a l l b a c k который
который мы уже и с ­
указывает, что при генериро­
пользовали раньше.
вании JavaScript должна исп оль­
зоваться функция updateSales.

В результате Mighty G um ball будет иснользовать u p d a t e S a l e s


для оберты вания объекта в ф орм ате JSO N до того, как отнрав-
лять его обратно вам. В случае с веб-службами данны й нара­
метр обычно назы вается c a l l b a c k , однако для нодстраховки
вам все же следует изучить документацию к иснользуемой вами
веб-службе.

ШТУРМ
Введите данные URL-адреса: что вы видите в ответ?
http://search.twitter.сот/search.j son?q=hfhtml5&callback=myCallback

h t t p ://search.twitter.com/search.j son?q=hfhtml5&callback=justDoIt

h t t p ://search.twi tter.com/search.j son?q=hfhtml5&callback=updateTweets

Примечание: браузер Firefox предложит вам от к ры т ь либо сохранить файл. Д л я от кры т ия


вы можете использовать T extEdit, Блокнот или любой другой базовый текстовый редактор.

288 глава 6
общение с веб-службами

Ребята, у нас все получилось. Нам при­


шлось немного повозиться, чтобы разобраться с
использованием элемента < s c r i p t > при обращении
к веб-службе, однако теперь такой подход кажет­
ся едва ли не более простым, чем использование
XMLHttpRequest.

Д ж им : Ч то ж, почти.
Д ж о: Думаю, это дает нам возмож ность избавиться от части кода.
Ф рэнк: Я готов придать веб-нриложению красивы й внеш ний вид,
когда вы закончите.
Д ж им : Д ж о, а что ты думаешь?
Д ж о: В случае с X M L H ttpR e quest мы извлекали строку. Но нри ис­
пользовании JSO N P тег < s c r i p t > обеснечивает разбор и оценку
возвращ аемого кода, поэтому когда мы нолучим данны е, они уже
будут представлять собой JavaScript-объект.
Д ж им : Да, все верно, а в случае с X M L H ttpR eq uest мы иснользова-
ли J S O N . p a r s e для преобразования строки в объект. Получается,
что теперь мы можем избавиться от этого кода?
Д ж о: Да. Это мое мнение, которого я нридерж иваю сь.
Джим: Ч то еще?
Джо: Ч то ж, очевидно, что нам нотребуется вставить элемент
< scrip t> .

Джим: Как раз это меня и интересовало. Где мы его разместим?


Джо: Браузер будет онределять, когда он будет загружаться, а нам
необходимо, чтобы сначала загружалась страница, чтобы мы
могли обновить объектную модель документа (DOM) н ри вы зо­
ве u p d a t e s a l e s . Единственны й выход, как мне кажется, в данном
случае заклю чается в разм ещ ении < s c r i p t > в ниж ней части стра­
ницы , в <body> HTM L-документа.
Джим: Да, нохоже, это здравая мысль. Н ам следует но дробнее на
н ей остановиться. Но сначала давайте нроверим ее н а нрактике.
Джо: Я хочу, чтобы наш код, наконец, заработал! Д авайте им зай­
мемся!
Ф рэи к: Ребята, вам лучше носнеш ить, но скольку, готов снорить,
Джуди уже наш ла свой снособ заставить все работать.

дальше ► 289
план повторной реализации

Обновление кода Веб-прилоЖения Mighty Gumball


П ора обновить к о д нашего н рилож ени я Mighty G um ball с использовани­
ем JSONP. Помимо удаления существующего кода, связанного с вы зовом
X M L H ttpR eq uest, все остальные изм енения будут незначительны м и.

Вот что нам потребуется сделать:

Удалить КОД X M L H ttp R e q u e st.

(2 ) Удостовериться, ЧТО функция u p d a t e S a l e s


будет готова к приему объекта, а не строки
(как было В случае С X M L H ttp R e q u e st).

Добавить элемент < s c r i p t > для выполне­


ния работы по извлечению данных.

^ Весь код в нашей функции o n l o a d является связанным с X M L H ttp R e q u e st,


поэтому мы можем просто удалить его. Сохраним функцию o n l o a d на слу­
чай, если она пригодится нам немного позже. А пока она ничего не будет
делать. Откройте свой файл m i g h t y g u m b a i i . j s и внесите следующие из­
менения:

window.onload = function() {
v a r u r l = "h t t p : / /g u m b a ll. wi c k e d ly s m a r t. com " т g данный МОЛЛент бяМ HCofixo-
var request = new XMLIIttpRequest () ; димо просто удалит ь весь код,
имеющийся в этой функции.
reque st.open (ивВФм , url);
reque st.onload = function ()— f-
if— (reque st.status == 200)— {-
updateflales(request.responseText);
t

reques t .sen d (nul1);

290 глава 6
общение с веб-службами

(2 ) Как вы помните, когда мм используем элемент < s c r i p t > , мм говорим браузе­


ру, что нужно извлечь JavaScript, в результате чего браузер извлекает его, а за­
тем проводит его разбор и оценку. Это означает, что к моменту, когда он дойдет
до вашей функции u p d a t e S a l e s , JS O N будет представлять собой уже не стро­
ку, а полноценнмй JavaScript-объект. Когда мм использовали X M L H ttp R e q u e s t,
даннме возвращались в форме строки. На даннмй момент функция u p d a t e S a l e s
предполагает, что будет получать строку, поэтому давайте внесем здесь измене­
ние, чтобм она обрабатмвала объект, а не строку:

Удаляем responseText и п е р е ­
function up date Oale s(resp onseText) писываем ст року с использо­
function updateSales(sales) { ванием парам ет ра sales.
var salesDiv = document.getElementByld("sales")
var sale s = JOON.p arse (re sp onseTex t ) ; ^ ------
К роме т ого, мы можем
for (var i = 0; i < s a les.length; i++) { удалит ь вызов JSON.parse.
var sale = sales[i];
var div = document.createElement ("div") ;
div. setAttribute ("class" , "saleltem") ;
div.innerHTML = sale.name + " sold " + sale.sales + gumballs";
salesDiv. appendChiId (div) ;

} t А вот и р езульт ат : т еперь у нас


имеет ся функция, готовая к обработке
наших данных.

И наконец, добавляем элемент < s c r i p t > для вмполнения работм по извле­


чению даннмх.

< !d o c ty p e h tm l>
< h tm l la n g = " e n " >
<head>
< t itle > M ig h tY G u m b a ll< /title > Это ссылка на веб-службу
<m eta c h a r s e t = " u t f - 8 "> Mighty Gumball. Мы исп оль­
< s c r i p t s rc = " m ig h ty g u m b a ll.j s " X / s c r i p t > зуем п а рам ет р callback и
< l i n k r e l = " s t y l e s h e e t " h r e f= " m ig h ty g u m b a ll. c s s " >
указываем имя нашей ф у н к ­
ции updateSales, в силу чего
< /h e a d >
веб-служба будет оберт ы ­
<body> вать J S O N -данные в вызов
< h l> M ig h ty G um ball S a le s < /h l> функции updateSales
< d iv i d = " s a l e s ">
</div>
< script src="http:/ /gumball.wickedly smart.com/?callback=updateS ales" X / scrip t>
</body>
</html>

дальше ► 291
тестирование кода с jsonp

Тест-драйв нового кода с JS0NP


Когда вы внесете все изм енения, настунит время нровести тест-драйв. П ерезагрузите
m ig h ty g u m b all. htm l в своем браузере. Тенерь вы загружаете данны е об уровне нродаж
ж евательной рези н ки автоматами Mighty Gum ball, иснользуя свое веб-нриложение и
JSONP. Внешне страница долж на но лучиться такой же, как и нри извлечении данных
об уровне продаж из локального ф ай­
ла, но вы будете знать, что в данном n n n Mightycumbaii
Случае используется соверш енно Дру- f ^ I II +
гой способ извлечения и нф орм ации. , „
* F Mighty Gumball Sales
IMPERIAL sold 4 gumballs

в о т что вы увидите при SAN FRANCISCO sold 5 gumballs


перезагрузке страницы
CHINO HILLS sold 8 gumballs
Mighty Gumball Вы будете
наблюдать разные города STANFORD sold 3 gumballs

и уровни продаж, посколь­ CARSON sold 9 gumballs


ку на экран с т а н у т выво­
GOLETA sold 6 gumballs
диться реальные данные.
BRADLEY sold 5 gumballs

CAPAY sold 7 gumballs

LANCASTER sold 8 gumballs

SAN QUENTIN sold 5 gumballs

Да! Исполнительному ди­


ректору Mighty Gumball
это должно понравиться! Теперь
можно и отдохнуть.

292 глава 6
А мне кажется, что JSONP
является одной большой бре­
шью в безопасности!

Данный подход не менее безопасен, чем использо­


вание <script> для загрузки JavaScript.
Это нравда: если вы соверш аете JSO N P-запрос, обращ а­
ясь к вредоносной веб-службе, то ответ мож ет содерж ать
JavaScript-код, которого вы не ожидаете, и браузер вы-
нолнит его.
Все это ничем не отличается от добавления JavaScript
нутем связы вания с библиотеками, размещ аемыми на
других серверах. Всякий раз, когда вы осущ ествляете
связы вание с JavaScript-библиотекой (например, с от­
носящ ейся к <head> вашего документа) либо используе­
те JSONP, вам необходимо быть уверенными в том, что
вы доверяете данной службе. А если вы пиш ете веб-
нрилож ение, которое станет задействовать аутентиф и­
кацию н ри реш ении вопроса о том, давать ли доступ кон­
кретному нользователю к чувствительным данным, то
наилучшим выходом для вас, вероятно, будет вообщ е не
иснользовать сторон н ие библиотеки или JSO N -данные,
размещ аемы е на других серверах.
Поэтому осторож но нодходите к выбору веб-служб, к ко­
торы м собираетесь подклю чаться. Если вы иснользуете
API-интерф ейс, такой как Google, Twitter, Facebook, или
одну из множ ества других ш ироко известны х веб-служб,
то мож ете быть уверены в их безонасности. В н ротивном
случае рекомендуется нроявлять осторож ность. В нашем
случае мы знакомы с инж енерам и из ком нании Mighty
G um ball и знаем, что они никогда не стали бы внедрять
что-либо вредоносное в свои JSO N -данные, в силу чего
вы мож ете быть уверенны м и в их безонасности.
Беседау камина
У ч а с т н и к и : X M L H ttp R e q u e st an d JS O N P
Сегодня мы станем свидетелями разговора двух популярных
способов извлечения данных в случае с браузерами.

X M L H ttp R e q u e st: JSO N P :


Н е хочу Вас обидеть, но не являетесь ли вы халтурным
приемом? Я имею в виду, что Ваше назначение заклю­
чается в извлечении кода, а люди используют Вас для
соверш ения запросов данных. Халтурным? Я бы назвал себя замечательным. Ведь я
могу использоваться для извлечения как кода, так и
данны х. Какая н еобходим ость в том, чтобы делать все
это двумя разными способами?
Н о все, что Вы делаете, —это вбрасы вание данны х вме­
сте с кодом. И вообщ е вы никак не позволяете со в ер ­
шать запросы напрямую из JavaScript-кода; Вы вынуж­
даете лю дей использовать HTM L-элемент < s c r i p t > .
Э то приводит Ваших пользователей в замеш ательство.
Э й, но ведь такой п о д х о д р а б о т ает и дает людям в о з­
можность писать код, который позволяет получать JSO N -
данные от сервисов вроде Twitter, G oogle и других. Как та­
кое возм ож но при использовании Вас, XM LH ttpRequest,
учитывая налагаемые Вами огр ан и чен и я с целью о б е ­
спечения безопасности? Я имею в виду, что Вы все еще
цепляетесь за прош лое, за XML
Э й, XML по-прежнему ш ироко используется, и не сто­
ит умалять его значение. А извлекать JSO N -данные
мож но и с помощью меня без проблем .
К онечно м ож но, если кому-то нравится постоян но за­
ниматься п р еобр азованием результатов с помощью
Я позволяю контролировать, какие им енно данны е JS O N .parse.
будут подвергаться р азбору и преобразованию в
JavaScript-объекты. А в случае с Вами это п р ои сходи т в
отнош ении всех данных.
А в этом как раз и заключается преимущ ество — к мо­
менту, когда данны е дойдут до м оих пользователей, все
они будут разобраны и преобразованы . П ой м ите, я Вас
очень уважаю, Вы стояли у истоков целого подхода к
написанию прилож ени й, но проблем а в том, что Вы
навязываете слишком много ограничений. В совр ем ен ­
ном мире веб-служб людям требуется возм ож ность со ­
вершать запросы и в другие дом ены .
Что ж, мож но воспользоваться халтурным прием ом
вроде JSO N with P ad d in g (ну и глупое ж е название)
либо правильным сп особом , то есть X M LH ttpR equest,
и «расти» вместе с ним по м ере его эволю ции. В конце
концов, люди работаю т над тем, чтобы сделать меня
бол ее гибким, но в то ж е время безопасны м .
Л ю ди, н есом н ен н о, работаю т над вашим улучшением,
однако у м оих пользователей имею тся реальные п о­
т р ебн ости уже сегодня, — они не могут ждать, пока бу­
дут устранены все ваши м еж дом енны е проблемы .

294 глава 6
общение с веб-службами

X M L H ttp R e q u e st: JSO N P :


И ничего глупого в слове P adding в названии JSONP
нет, поскольку он о всего лишь означает, что когда
пользователь соверш ает запрос веб-службы, он при
этом также просит ее добавить небольш ой преф икс,
наприм ер, " u p d a t e S a l e s ()", к результату. А Вас как
иногда называют? Ajax? Разве это не название средства
чистки для ванн?
У меня нет ничего общ его с названием Ajax, поэтом у
не надо задавать мне такие вопросы ! К стати, Вы ни
разу не говорили о том, насколько Вы безопасны .
Программистам постоянно приходится проявлять о ст о­
р ож ность. Если вы извлекаете код с другого сервера, то
долж ны знать, что дел аете. Н о ответ в данном случае
не д о л ж ен н р о ст о ограничиваться ф р а зо й «этого не
следует делать».
Я могу лишь сказать, что если вам не требуется извле­
кать чужие данны е, которы е м ож ет дать, наприм ер,
Twitter или G oogle, и вы создаете свою собственную
веб-службу и клиента, то вы бирайте меня. Я о б е с п е ­
чиваю бол ее высокий уровень б езоп асн ости и бол ее
прост в использовании. Алло? Никто не создает службы, которы е не исполь­
зуют внеш ние данны е. Слышали когда-нибудь термин
«мэшап»?
Да, да, знаю я об этом смеш ивании данны х, извлекае­
мых с различны х сто р о н н и х веб-ресурсов.
Э й, я, по крайней м ере, обладаю стабильной пов се­
м естной поддерж кой и терпеть не могу, когда п р и хо­
дится писать код X M L H ttpR equ est, которы й см ож ет
работать в стары х браузерах.
Да ладно, не так уж и много кода нужно, чтобы о б е ­
спечить поддерж ку меня версиями вплоть до Internet
Explorer 5.
Ха-ха, а в случае со м ной для этого вообщ е не потребу­
ется НИ К АК О ГО кода. Лишь п р остой HTM L-тег.
Что ж, однако, это ещ е не все. П робовали ли Вы ког-
да-нибудь делать нечто повторяю щ ееся, то есть когда
требуется извлекать что-либо снова и снова? В каче­
стве прим ера мож но привести пр ил ож ени е Mighty
G um ball, над которы м сейчас идет работа. Как разра­
ботчики смогут обесп еч и ть такую функциональность,
используя Вас?
Э й, все не настолько плохо. Нужно просто добавить
новы й элем ент < s c r i p t > в объектную модель доку­
мента (DOM ) для соверш ения ещ е одного запроса.
М не кажется, Ваши читатели, услышав только что ска­
занн ое Вами, переспросят: «Что, простите?»

H E A D F IR S T :
Благодарю , ребята! Боюсь, наше врем я истекло!

дальше ► 295
jsonp-упражнение для ума

Вы немного не доработали приложение. Я думал,


что увижу постоянно обновляющийся поток данных
об уровне продаж, поступающий от наших автоматов
для продажи жевательной резинки. Конечно, я могу
нажать кнопку Refresh (Обновить) в браузере, но ведь
получается, что я смогу увидеть самые свежие отчеты
только в том случае, если сам вручную нажму кнопку
обновления. Это не то, чего я хотел!

М 9 *Г 9 *9 Й
ШТУРМ
Он прав, нам необходимо подкорректировать приложение, чтобы оно обновляло
отображаемые данные, используя новые сведения об уровне продаж, через регу­
лярные интервалы времени (например, каждые 10 секунд). На данный момент у
нас в странице имеется элемент <script>, который инициирует отправку запроса
на сервер только один раз. Вы можете придумать какой-нибудь способ так исполь­
зовать JSON, чтобы обеспечивалось непрерывное извлечение отчетов с новыми
данными об уровне продаж?

Подсказка: используя объектную модель документа (РОМ),


мы можем вставить новый элемент <script> в страницу.
Поможет ли это?

296 глава 6
общение с веб-службами
Ребята, как я только что узнала,
исполнительный директор Mighty Gumball
не совсем доволен вашей первой версией
приложения?

Джим: Да, он хочет, чтобы отображ аемы е на странице данны е обнов­


лялись ненреры вно.
Джуди: В этом есть смысл. Я имею в виду, что большим преимуще­
ством веб-нрилож ения является то, что его не нужно обновлять с но-
мощью кнонки Refresh (О бновить) как обычную веб-страницу.
Джо: Внолне справедливое требование. К роме того, мы уже знаем,
как зам енять старые данны е об уровне нродаж новы ми на странице,
иснользуя DO М. Но мы нока не уверены в том, как именно следует об­
рабаты вать JSO N P-часть.
Джуди: Н е забы вайте, что вы также мож ете иснользовать объектную
модель документа в сочетании с элементом <script>. Другими слова­
ми, вы мож ете создавать новы й элемент <script> в DOM всякий раз,
когда необходимо извлечь дополнительны е данные.
Джим: Что-то я не очень нонял. Н ельзя ли новторить?
Джо: Кажется, я разобрался. Н а данны й момент мы статически раз­
мещаем элемент <script> в HTM L-разметке, нросто набрав его там.
Вместо этого мы могли бы создавать новы й элемент <script> с исполь­
зованием JavaScript-кода и добавлять его в DOM. Единственное, в чем
я здесь не уверен, — станет ли браузер еще раз извлекать данны е, ког­
да мы создадим новы й элемент <script>?
Джуди: К онечно, станет.
Джим: Ясно, то есть мы будем создавать новы й элемент <script> каж­
ды й раз, когда нам будет необходимо, чтобы браузер вы нолнил для
нас JSO N P-онерацию.
Джуди: Правильно! П охоже, что и ты во всем разобрался. А знает
ли кто-нибудь из вас, как сделать так, чтобы это происходило снова
и снова?
Джим: Мы еще не дошли до этого, мы нока что размыш ляем о JSONP.
Джуди: Вам уже все известно о функциях обработчиков собы тий
вроде onload или onclick. Вы мож ете установить тайм ер для вызова
функции обработчика через заданны й интервал врем ени с использо­
ванием метода setlnterval в JavaScript.
Джо: Д авайте именно так и ностуним и сделаем JSO N P динам иче­
ским, чтобы как можно скорее нредставить исполнительному дирек­
тору Mighty G um ball долж ны м образом работаю щ ее нрилож ение.
Джим: О, это все, что нотребуется сделать? Тогда не будем медлить!

дальше ► 297
делаем jso np динамическим

ДорабатыВаем приложение Mighty Gumball


Как видите, нам нридется вы нолнить немного дополнительной работы , однако она не будет слишком
сложной. По сути, мы нанисали нервую версию нашего н рилож ения таким образом, что оно извлекает
отчеты об уровне нродаж с сервера Mighty G um ball и отображ ает их только один раз. Это наше уну-
щ ение, носкольку ночти все соврем енны е веб-нрилож ения долж ны ненреры вно осуществлять м онито­
ринг данны х и обновлять отображ аемы е на странице сведения (ночти) в реж име реального времени.

Вот что нам потребуется сделать:

© М м удалим JSONP-элемент < s c r i p t > из HTM L-страницм


Mighty Gumball, поскольку больше не будем его использовать.

Нам потребуется задать обработчик для обработки совершения


© JSO NP-запроса каждме несколько секунд. Прислушаемся к со­
вету Джуди и воспользуемся JavaScript-методом s e t i n t e r v a l .

Затем необходимо реализовать наш JSONP-код в обработчике,


© чтобм каждмй раз, когда будет происходить его вмзов, он со­
вершал запрос с целью извлечения отчетов с самими свежими
данными об уровне продаж с сервера Mighty Gumball.

Шаг 1: удаляем элемент < script> . . .


Мы собираем ся иснользовать новы й н о д х о д к инициированию JSONP-
занросов, ноэтому давайте удалим элемент < s c r ip t> из HTM L-разметки.

<! doc type html>


<h tml 1 ang=11e n 11>
<head>
<title>Mighty Gumball</title>
<meta charset="utf-8">
< script src="mightygumball.j s " X / s c r i p t >
<link rel="stylesheet" href="mightyguinball.css">
</head>

^ S L i g h t y Gumball Sales</hl> ^ У д а л и т е данны й эл е м е н т из своего


<div id="sales"> H T M L -ф а й л а .
</div> T
<script src="http://gumball.wickedlysmart.com/?callback=update 3ale s 11></script>
</body>
</html>

298 глава 6
общение с веб-службами

Шаг 2: Время для установки таймера


И так, мы стремимся к тому, чтобы вместо и звлечения отчетов об уровне н ро­
даж только один раз эта нроцедура осуществлялась врем я от врем ени, скажем,
каждые 3 секунды. Это мож ет оказаться слишком часто или редко в зависимо­
сти от конкретного нрилож ения, однако в случае с Mighty G um ball мы начнем
с интервала 3 секунды.
Н ам нотребуется функция, которую мы сможем вы зы вать каждые 3 секун­
ды. И, как говорила Джуди, для этого мы мож ем воснользоваться методом
setlnterval, которы й имеется в объекте window:

s e tln te r v a l(h a n d le R e fr e s h , 3000);

М етод s e tln te r v a l
приним ает одра-
Наила функция обра­
ботчика, кот орую мы
г
Наше значение интервала вр е м е ­
ни, выраженное в миллисекундах.
б о т ч и к и зн а ч е н и е определим чут ь позже. 3 ООО миллисекунд = 3 секунды.
и нт ер ва ла врем ени.

Таким образом, каждые 3000 миллисекунд JavaScript будет вызы вать обработчик —в данном
случае функцию h a n d l e R e f r e s h . Д авайте наниш ем нростой обработчик и протестируем его:

При каждом вызове данного обработчика


function handleRefresh() { (а происходить это будет каждые 3 се­
alert("I’m alive"); кунды) на экран будет выводиться диало-
говое окно alert с сообщением «I'm alive».

Тенерь нам нотребуется код для задания вы зова s e t l n t e r v a l , которы й мы добавим в функ­
цию o n l o a d , чтобы он нроисходил сразу но еле того, как страница нолностью загрузится:

Это наша прежняя функция onload,


window.onload = function() { в которой ничего не осталось после
setlnterval (handleRefresh, 3000) ; того, как МЫ удалили из нее код
) X M L H ttp R e q u e s t.

't ! е ш Г ° 7 М Н&0бК0диМ0 с Э е л а ^ - эт о д о б а в и т ь н а ш вы зов


к о т о р ы й в КТ о Т Т вЬ'П° Л н е н ш ^ з а п у с т и т т айм ер
к о т о р ы й , в сво ю о ч е р ед ь, с т а н е т и н и ц и и р о в а т ь с я кажды, ч а
« в ы зы в а т ь н а ш у ф у НКЦию h a n d le R e fr e s h

П роведем тест-драйв, а затем, когда убедимся, что все работает (то есть когда мы увидим,
что обработчик вы зы вается каждые 3 секунды), реализуем JSO N P-код.

дальше ► 299
тестирование интервального таймера

Tecm-драйб таймера
Э т о будет весело. Убедитесь, что вы набрали функцию h andleRef resh, а также внес­
ли изм енения в обработчик onload. С охраните все, а затем загрузите код в своем
браузере. В результате вы долж ны увидеть ноток откры ваю щ ихся диалоговы х окон
alert, остановить которы й сможете, лиш ь закрыв окно браузера!

------------------------------------------------------------------ 1

h ttp ://lo c a lh o s t
Cm alive

С OK 3

Л
4 Вот что мы получим!
Возьми в руку карандаш

Теперь, когда вы знаете, что такое setlnterval (не говоря уже


о XMLHttpRequest и JSONP), задумайтесь над тем, для чего еще
вы могли бы использовать их в других веб-приложениях. Напишите
свои ответы здесь.

Д ля проверки и обновления показателей хода


выполнения задачи с выводом их на экран.

Д л я проверки на п редм ет новых к ом м ент ари ев,


размещаемых пользователями.

Д л я обновления карты пользователя в случае


появления поблизости его друзей.

300 глава 6
общение с веб-службами

Шаг 3: повторная реализация JS0NP


Мы но-нрежнему х о т и м иснользовать JSO P для и звлечения данных, однако нам необходим снособ
делать это нри каждом вызове обработчика h a n d le R e f re s h , а не только во врем я загрузки страницы.
И менно здесь на сцену выходит объектная модель документа. Ее зам ечательная особенность заклю ча­
ется в том, что мы можем вставлять элементы в DOM в любой момент, даже элементы < s c r i p t >. Таким
образом, мы долж ны иметь возмож ность вставлять новы й элемент < s c r ip t > всякий раз, когда захотим
соверш ить JSO N P-вызов. Д авайте наниш ем соответствую щ ий код, воснользовавш ись всеми наш ими
знаниям и о DOM и JSONP.

Сначала зададим URL-адрес JS0NP


Это будет тот же самый URL-адрес, который мы использовали с нашим предыдущим эле­
ментом < s c r i p t > . Здесь мы присвоим его переменной для последующего использования.
Удалите a l e r t из своего обработчика и добавьте вот этот код:
Снова возвращаемся к нашей
функции handleRefresh.. Задаем UIZL-adpec JSONP и п р и -
^ сваиваем его переменной urli
function handleRefresh () {
var url = "http://gumball.wickedly smart.com? callback=updateS ales " ;
}

Далее создадим новый элемент < script>


На этот раз вместо имеющегося элемента < s c r i p t > в составе нашей HTML-разметки, мы
будем создавать такой элемент с использованием JavaScript. Нам потребуется создать
элемент < s c r i p t > , а затем задать соответствующие значения для его атрибутов s c r и id :

function handleRefresh () {
var url = "http://gumball.wickedly smart.com? callback=updateS ales " ;
Сначала мы создаем но ­
вый элем ент <scnpt>...
var newScriptElement = document.createElenient (" script")
newScriptElement.setAttribute (" src" , url) ;
...а за т е м присваиваем его
а т р иб ут у scr значение
newScriptElement.setAt tribute ("id" , "jsonp") ; виде URL-адреса JSONP.

r Мы также присвоим
Метод setA ttrib u te может показаться вам ч е м -т о данному элем ент у <script>
новым (мы лишь мимоходом упоминали его ранее), иден т и ф и ка т ор , чтобы
однако несложно понять, что он делает . Данный его можно было без труда
м ет од позволяет задавать значения для ат рибут ов найти позже, что, как вы
HTML-элем ент ов (например, для scr и id), а также увидите, нам и п о т р е б у ­
для множества других, включая class, href и m. д. ется сделать.

дальше ► 301
вставка jsonp в dom

Как мы будем Вставлять элемент < script> 6 DOM??


Мы ночти д о с т и г л и цели, осталось только н роизвести вставку нашего нового элем ента <script>.
Как только мы сделаем это, браузер увидит его и нреднрим ет соответствующ ие действия, что нри-
ведет к соверш ению JSO N P-вызова. Вставка элем ента <script> требует небольш ого планирования
и предусмотрительности; давайте но смотрим, как все это работает:

Начнем с объектной модели докумен­


та где отсутствует элемент <script>
с id в виде "j sonp" (на данный мо-
© В коде нам потребуется извле­
кать ссылку на элемент <head>.

Затем мы вставим новый элемент


X © <script> в элемент <head>.

П осле того как мы вставим <script>, браузер увидит этот новы й элемент в объектной модели до­
кумента (DOM) и отнравится извлекать то, что раснолож ено но URL-адресу, которы й задан в каче­
стве зн ачен ия атрибута scr. Однако у нас также имеется второй вариант иснользования. Взглянем
на него.
/Cpv Теперь, за исключением време-
данном случае мы снова будем из­
ни, когда происходит первый
влекать ссылку на элемент <head>.
вызов handleRefresh, у нас уже будет
иметься элемент <script> с id
в виде "jsonp" в DОМ.

title meta script link

script id--"jsonp" src^'httpV/gumbollwi;


На этот раз мы заменим существующий элемент нашим новым
элементом вместо того, чтобы добавлять новый <script>
г
в объектную /модель документа. Да, можно было бы добавить новый
<script>, то есть браузер инициировал бы JSONP-вызов, однако
со временем у нас бы накопилась огромная коллекция элемен­
тов <script> в DOM, а это уже может сказаться на производитель­
ности. Поэтому замена элемента будет оптимальным выбором.

302 глава 6
общение с веб-службами

Теперь напишем код для вставки < script> в DOM


Теперь, когда вы знаете необходимые шаги, давайте взглянем на код. Здесь мы тоже выполним два
шага: сначала покажем вам код для добавления нового <script>, а затем продемонстрируем код
для замены <script>:
function handleRefresh() {
var url = "http://gumball.wickedlysmart.com?callback=updateSales" ;
Сначала мы будем извле-
var newScriptElement = document.createElement (" script") ; кать ссылку на элем ент
<script>. 8 случае его о т ­
newScriptElement.setAttribute("src", url);
сут ст вия будет возвращено
newScriptElement.setAttribute("id", "j sonp"); null. О брат ит е внимание,
что мы рассчитываем на
var oldScriptElement = document.getElementByld("jsonp") то, что он будет и м е т ь id
со значением «jsonp».
var head = document.getElementsByTagName("head")[0];
if (oldScriptElement == null) {
Д алее будем извлекать
head.appendChild(newScriptElement);
ссылку на элем ент <head>,
} используя новый м ет од
объекта document. О т о м ,
Теперь, когда у нас есть ссылка на элем ент <head>, мы п р о ­ как он работ ает , мы п о ­
веряем, имеется ли т а м уже элем ент <script>, и если он о т ­ говорим позже, а пока
с у т с т в у е т (о чем будет свидетельст вовать возврат зн а ­ просто знайт е, что он
чения null при попытке извлечь на него ссылку), мы добавим извлекает ссылку на э л е ­
новый элем ент <script> в <head>. м е н т <head>.

Итак, взглянем на код для замены элемента <script> в случае, если вы­
ясняется, что таковой уже существует. Мы рассмотрим только условный
оператор if, в котором сосредоточен весь новый код:

Наил условный оператор, который, как вы пом нит е, п р о -


веряет, сущ ест вует ли уже элем ент <script> в РОМ.

if (oldScriptElement == null) {
head.appendChiId(newS criptElement);
} else {
head.replaceChild(newScriptElement, oldScriptElement);
}

\ Если в <head> уже имеет ся элем ент <scnpt>, мы просто заменяем его.
Мы используем м ет од replaceChild в отношении <head> и передаем ему
new ScriptE lem ent и oldScriptElement для выполнения данной процедуры.
Через несколько мгновений мы подробнее поговорим об эт ом методе.

дальше ► 303
подробнее о дополнительных методах для работы с dom

g e t^e in e n b ^y X a g ^a K ie п о д у в е л и ч и те л ь н ы м с т е к л ° м ________________

Это было ваше нервое знакомство с методом g e tE le m e n tsB yT a g N a m e , ноэтому быстро ис­
следуем его нодробнее. О н нодобен методу g e tD o c u m e n tB y ld за исклю чением того, что
возвращ ает массив элементов, соответствующ их определенному имени тега.

getElem entsByTagNam e возвращает все элем е н т ы , с о о т -


е т ст вую щ и е данному т е г у , которые им ею т ся в DOM

\
var arrayOfHeadElements = document.getElementsByTagName ("head" ) ;

3 данном случае он возвращает


массив элементов <head>.

Получив массив, можно извлечь н ервы й его элемент, иснользуя индекс 0:


£ Л Возвращает первый элем ент
var head = arrayOfHeadElements [0] ; <kead> в Массиве (и т а м ОН должен
быть единственным, не т ак ли?).
А сейчас давайте объединим обе эти строки следующим образом:

var head = document.getElementsByTagName ("head") [0];

Извлекаем массив, а за т е м используем индекс в нем для и звле­


чения первого элем ент а, причем делаем все это за один подход.
В нриведенном н рим ере кода мы ностоянно иснользуем н ервы й элемент <head>, однако
вы мож ете нрим енять метод ge tE le m e n tsB yT a g N a m e в случае с любыми тегами: <р>, < d iv >
и т. д. П ри этом вы обычно будете нолучать обратно более одного из соответствующ их
элементов, которы е имею тся в массиве.

Гер1асе(Ти1с1 по д у в е л и ч и те л ь н ы м с т е к л ° м ____________________________

Взглянем также на метод r e p la c e C h i I d , носко льку вы не встречали его раньш е. Д анны й ме­
тод следует вызы вать но отнош ению к элементу, в котором вы хотите зам енить дочерни й
элемент, нередав ему ссылки на н овы й и стары й дочерние элементы. М етод r e p la c e C h ild
нросто зам еняет стары й д очерни й элем ент новым.

Метод replaceChild дает ук а за - Элемент <script>,


ние э лем ент у <head> зам енит ь один Наш новый который уже и м е -
из его дочерних элементов с именем элем ент ется на странице.
oldScn'ptElement новым элем ент ом <scnpt>.
с именем new S cnp tE lem en t. ^

head.replaceChild(newScriptElement, oldScriptElement) ;

304 глава 6
общение с веб-службами
Часш°
Задаваем ы е
В сЩ роСъх

1 3 : п о „ , „ е н „ ь , ________ „ Как можно узнать параметры веб-службы? И то, поддер­


вместо того, чтобы заменять элемент <script> целиком? живает ли она JSON и JSONP?

0 : Если вы лишь замените значение атрибута s c r элемента 0 : В случае большинства веб-служб публикуется общий API-
< s c r ip t > новым URL-адресом, браузер не будет рассматривать интерфейс, который включает способы доступа к конкретной службе,
его как новый элемент < s c r i p t > и, следовательно, не станет а также описание всего того, что можно сделать с ее помощью.
совершать запрос для извлечения JSONP. Чтобы заставить бра­ Если вы используете коммерческий API-интерфейс, то вам может
узер выполнить запрос, необходимо создать абсолютно новый потребоваться получить соответствующую документацию напрямую
элемент < s c r ip t > . Данная методика называется скриптовой от поставщика. Информацию относительно большей части общих
инъекцией. API-интерфейсов вам, скорее всего, удастся найти в Интернете,
используя поисковик либо зайдя в раздел для разработчиков на
^ 3 * Что происходит со старым дочерним элементом, когда я сайте соответствующей организации. Вы также можете посетить,
заменяю его новым? например, сайт programtheweb.com, где документируются API-
интерфейсы, список которых постоянно увеличивается.

Q j Он удаляется из объектной модели документа (DOM). А что


произойдет дальше, будет уже зависеть от вас: если у вас по- Очевидно, что XMLHttpRequest старше HTML5, а как насчет

прежнему имеется ссылка на него, сохраненная в находящейся JSON и JSONP? Являются ли они частью HTML5? Нужен ли мне
где-то переменной, то вы сможете продолжить использовать его HTML5, чтобы использовать их?
(любым путем, который будет иметь смысл). Если же у вас ее нет, то
среда выполнения JavaScript в конце концов регенерирует (освобо­ 0 : Мы бы назвали JSON и JSONP современниками HTML5.
дит) память, которую занимает данный элемент в вашем браузере. Ни один из них пока не определен спецификацией HTML5, од­
нако они активно используются HTML5-пpилoжeниями и играют
А что, если в HTML-файле будет более одного элемента важнейшую роль в процессе создания веб-приложений. Таким
<head>? В случае с вашим кодом, по-видимому, предполага­ образом, несмотря на то что мы говорим HTML = Язык разметки +
ется, что там будет только один элемент <head>, поскольку API-интерфейсы JavaScript + CSS, JSON и JSONP также являются
вы используете индекс 0 в массиве, возвращаемом методом весомой частью данной картины (равно как и запросы с использо­
getElementsByTag? ванием HTTP И X M LH ttpR e q u e s t).

0 : По определению HTML-файл включает только один элемент ^ J Продолжают ли люди использовать XML? Или в настоящее
<head>. Следует отметить, что, конечно же, кто-то может включить время везде уже господствует JSON?
и два таких элемента в HTML-файл. В этом случае получаемые ре­
зультаты могут варьироваться (так и будет, если вы не произведете 0 : В компьютерной индустрии существует одна прописная истина,
валидацию своего HTML!), но браузер, как обычно, постарается согласно которой ничто никогда не умирает. При этом также следует
приложить максимум усилий, чтобы сделать все правильно (а что отметить, что JSON в настоящее время набирает обороты, в силу
именно считается правильным, зависит от браузера). чего создание многих новых веб-служб осуществлялся именно с
его помощью. Вы часто будете сталкиваться с тем, что многие
Можно ли остановить интервальный таймер после его веб-службы поддерживают разнообразные форматы, включая
запуска? XML, JSON и массу других (например, RSS). Преимуществом JSON
является то, что он основан непосредственно на JavaScript, a JSONP
позволяет избежать междоменных проблем.
0 : Конечно, можно. Метод s e t l n t e r v a l возвращает значение
id , которое идентифицирует таймер. Сохранив данное значение
i d в переменной, вы сможете в любой момент передать его методу
c l e a r i n t e r v a l для остановки таймера. Закрытие браузера
также останавливает таймер.

дальше ► 305
разбираемся с кэшем браузера

Чуть не забыли сказать: берегитесь


опасного кэша браузера
Мы н о ч т и г о т о в ы нерей ти к тестированию , однако сначала нужно нозабо-
титься об одной небольш ой детали, которая относится к нроблемам тина
«если вы никогда не делали этого нрежде, то как вы вообщ е узнаете, что вам
необходимо с этим снравиться».
У больш инства браузеров имеется лю боны тная особенность: если вы извлекаете данны е, м ногократно
иснользуя один и тот же URL-адрес (как наш JSO N P-занрос), то браузер в конце концов нроизведет их
кэш ирование в целях новы ш ения нроизводительности, и вы будете снова и снова нолучать обратно
один и тот же кэш ированны й файл (или данны е). А это не то, что нам нужно.
К счастью, существует нростое и старое, как И нтернет, «лекарство» от этого. Все, что нам нотребуется
сделать, —это обеснечить добавление случайного числа в конец URL-адреса. Благодаря этой хитрости
мы заставим браузер думать, что неред ним новы й URL, которы й он никогда не видел нрежде. О ткор­
ректируем наш код, изменив приводившуюся ранее строку с URL-адресом:

Аанный код вы найдете в верхней часты И зм енит е приводившееся


своей функции handleRefresh. раньше объявление url, чтобы
оно стало выглядеть так.

var url = "http://gumball.wickedlysmart.com/?callback=updateSales" +


"&random=" + (new Date()).getTime();

Добавляем новый, «ф и кт и вн ы й » Создаем новый объект Date и используем


п а р а м е т р в конец URL-адреса. мет од getT im e объекта Date для извлечения
Веб-сервер будет игнорировать значения времени в миллисекундах, после чего
его, однако данного па рам ет ра добавляем это значение в конец URL-адреса,
окажется достаточно для т ого,
чтобы обхит рит ь браузер.

Благодаря этому новому коду сгенерированны й URL-адрес будет выглядеть нрим ерно так:

Эта часть уже должна быть вам знакома... д gom п а р ам е т р random.

http://gumball.wickedlysmart.com?callback=updateSales&random=1309217501707

У *
Эта часть будет каждый раз изменяться
для предотвращения кэширования.

Зам ените объявление н ерем ен ной url в своей функции handleRefresh нредставленны м
здесь кодом, но еле чего вы будете готовы к нроведению тест-драйва!

306 глава 6
общение с веб-службами

Еще раз проводим тест-драйв


Итак, на этот раз мы, несом ненно, все предусмотрели. Все должно быть
нолностью готово. Убедитесь, что вы добавили весь код, приводивш ийся Гу5АМ
с момента носледнего тест-драйва, и перезагрузите страницу. П рекрасно, Mighty Gumball

тен ерь мы видим, как данны е н епреры вно обновляются!


M ig h ty G um ball
Постойте-ка... вы видите то LOS GATOS sold 2 gumbalfs
же, что и мы? Что это еще Дубликат ы! [ COURTLAftio sofd 3 gumbaJ|s
за дубликаты? Это нехорошо. C O U R T U N D sold 3 gumballs
Хм. Может быть, извлечение
FRESNO sold 5 gumballs
происходит слишком быстро
COURTLANd sold 3 gumballs
и мы получаем отчеты , к о ­
FRESNO sold 5 gumbalfs
торые уже извлекались ранее?
FRESNO sold 5 gumballs

Как избавиться о т дубликатов отчетов об уровне прода>к


Е с л и в ы снова взглянете на специф икации сервера Mighty Gum ball,
приводивш иеся на с. 262, то увидите, что в URL-адресе занроса мы
можем указать парам етр lastreporttime, как показано далее:

Просто у к а -
Вы также можете добавить п а р а м е т р lastreporttim e в к о - время
н е ц U R L -адреса, чтобы извлечь только от чет ы , которые в миллисекундах,
по ст упили начиная с указанного времени. Например: oQnj f QQ
h t t p : / / gUnba 1 1 . Wic3cedly sma r t .conl/ ?1a s t r e p o J:t t i Iae=1302212903099

Это, конечно, здорово, но как узнать врем я ностунления носледнего отчета, которы й
мы извлекали? Д авайте еще раз взглянем на ф орм ат вывода отчетов об уровне нродаж:

[{"name":"LOS ANGELES","time":1309208126092,"sales":2},
{"name":"PASADENA","time":1309208128219,"sales":8}, У каждого от чет а об уровне
{"name":"DAVIS CREEK","time":1309214414505,"sales":8} продаж имеет ся время его
. . .] поступления.

дальше ► 307
использование параметра веб-службы

Я понял, к чему вы клоните; то есть


мы можем отслеживать время поступления
q / последнего отчета, а затем использовать его,
когда будем совершать следующий запрос, чтобы
сервер не возвращал нам отчеты, которые мы уже
V
получали?

Вы все правильно поняли.


Чтобы отслеживать время поступления последнего отчета, нам нотребует­
ся внести ряд дополнений в функцию updateSales, в которой нроисходит
вся обработка данных об уровне продаж. Однако сначала нам нужно будет
объявить переменную, в которой будет размещ аться значение времени по­
ступления самого последнего отчета: Поместит е дан-
Значение времени ный код в g
не м о ж е т быть м е т - ^
v a r la s tR e p o r tT im e = 0 ; нуЛЯ, поэтому I ЭлЯ J a v a S ^ a°

начала просто зада- ^


дим здесь значение О. ф ункции

Тенерь извлечем значение врем ени ностунления самого ноеледнего отчета


об уровне нродаж в u pdateSales :
function updateSales(sales) {
var salesDiv = document.getElementByld(Msales");
for (var i = 0; i < sales.length; i++) {
var sale = sales[i];
var div = document.createElement("div");
d i v . s e t A t t r i b u t e ( Mc l a s s " , Ms a le lt e m " ) ;
div.innerHTML = sale.name + M sold M + sale.sales +
M gumballs";
salesDiv.appendChi 1d (div) ;
}
if ( s a l e s . le n g t h > 0) {
la s tR e p o r tT im e = s a l e s [ s a l e s . l e n g t h - 1 ] . t i m e ;

}
Нам необходимо убедиться
Если вы взглянете на массив sales, то у в и ­ в Н АЛ И Ч И И массива; в случае
дите, что самый свежий о т ч ет о прода­ о т с ут ст ви я новых отчетов
жах является последним в эт о м массиве. о продажах будет возвращен
Поэтому здесь мы присваиваем его нашей пустой массив и наш код сгене
переменной lastReportTime. р и р у е т исключение.

308 глава 6
общение с веб-службами

Обновление URL-agpeca JSON с целью включения lastreporttime


Тенерь, когда мы отслеж иваем врем я ностунления носледнего отчета об уровне нро-
даж, нам необходимо удостовериться в том, что мы отнравляем его на сервер Mighty
G um ball как часть JSO N -занроса. Д ля этого отредактируем функцию hand l e R e f r e s h
и добавим нарам етр занроса last report time:
Разбиваем URL-адрес на не­
function handleRefresh () {
сколько ст рок, которые кон-
var url = "http://gumball.wickedlysmart.com" + S ' к ат енируем друг с другом...
"?callback=updateSales" +
"&lastreporttime=" + lastReportTime + ...а вот п а рам е т р lastreporttime
"&random=" + (new Date()).getTime(); со своим новым значением.
var newScriptElement = document.createElement("script");
newScriptElement.setAttribute("src", url);
newScriptElement.setAttribute("id", "j sonp");
var oldScriptElement = document.getElementByld("jsonp");
var head = document.getElementsByTagName("head")[0];
if (oldScriptElement == null) {
head.appendChiId(newS criptElement);
}
else {
head. replaceChild (newScriptElement, oldScriptElement)
}

Тест-драйв lastReportTime
П роведем тестирование нарам етра занроса last reporttime и посмо
трим, реш ает ли он нашу нроблему с дубликатами отчетов об уровне про
даж. Убедитесь, что вы набрали весь нриведенны й чуть выше новы й код
перезагрузите страницу и щ елкните на кнонке Refresh (О бновить).
А О О _ ИЦМуСииМ»__________ | у

ГлИЗС+З
Mighty Gumball Sales
LOS ANGELES sold 3 gumballs
Отлично! Теперь мы
LOS ANGELES sold 9 gumballs
ATWATER sold 8 gumballs
будем получат ь т о л ь ­
FARMINGTON sold 1 gumboils
ко новые отчеты о
F A R M IN G T O N sold 1 gumballs продажах, то есть все
GARDEN GROVE sold 3 gumballs дубликаты исчезнут!

дальше ► 309
Вы превзошли самих себя! Приложение
работает замечательно — теперь я могу
быть в курсе уровня продаж как сидя за своим рабочим
столом, так и находясь в пути. Я начинаю думать, что в
подобных веб-приложениях действительно что-то есть.
Только представьте, сколько всего мы сможем сделать,
используя автоматы для продажи жевательной резинки
в сочетании с J S O N и всеми этими
A P I-интерсрейсами HTML5!!
общение с веб-службами

КЛЮЧЕВЫЕ
"МОМЕНТЫ

■ XMLHttpRequest не позволяет запрашивать ■ Указывайте функцию обратного вызова в качестве


данные с сервера, отличного от того, с которого за­ параметра URL запроса в JSONP-запросе.
гружаются ваши HTML- и JavaScript-файлы. Такова
■ JSO NP не является более (или менее) безо­
браузерная политика безопасности, призванная
пасным подходом, чем связывание с JavaScript-
предотвращать доступ вредоносного JavaScript-KOfla
библиотеками с помощью элемента <script>.
к вашим веб-страницам и файлам cookie пользо­
Всегда проявляйте осторожность при связывании
вателей.
со сторонними JavaScript-библиотеками.
■ Альтернативой XMLHttpRequest для доступа
■ Указывайте элемент <script> для совершения
к данным, имеющимся у веб-служб, является JSONP.
JSO NP-запроса путем внедрения его непосред­
■ Используйте XMLHttpRequest, если ваши ственно в свой HTML либо посредством добавления
HTML- и JavaScript-файлы размещаются на том же элемента <script> в объектную модель докумен­
компьютере, что и ваши данные. та (DOM) с использованием JavaScript.

■ Используйте JSONP, если вам требуется доступ ■ Добавляйте случайное число в конец своего URL-
к данным, имеющимся у веб-службы на удаленном адреса JSONP-запроса, если многократно исполь­
сервере (при этом предполагается, что эта веб­ зуете этот URL для совершения запросов, чтобы
служба будет поддерживать JSON Р). Веб-служба — браузер не кэшировал ответ.
это веб-интерфейс API, доступ к которому осущест­
■ Метод replaceChild заменяет один элемент
вляется по протоколу HTTP.
другим в DOM.
■ JSONP представляет собой способ извлечения
■ set Interval — это таймер, который вызывает
данных с использованием элемента <script>.
функции через заданный интервал времени. Вы мо­
■ JSONP — это JSON-данные, обернутые в JavaScript; жете использовать setlnterval для отправки
обычно JSON-данные обертываются в вызов функ­ повторяющихся JSONP-запросов на сервер с целью
ции. извлечения новых данных.

■ Функция, в вызов которой обернуты JSON-данные,


в случае с JSONP называется функцией обрат­
ного вызова.

дальше ► 311
U I M L 5 - K f ° CCBopA
Здорово, в этой главе вы научили свое веб-нриложение общ аться с веб-службами!
П ора заставить ноработать левое нолуш арие мозга для закрепления материала.

По горизонтали По вертикали
4. Шаблон использования XMLHttpRequest для извлечения данных 1. В середине данной главы нас подстерегал один из них.
ссерверов иногда называют . 2. JSONP означает JSON with__________ .
7. Гуру учила Кузнечика тому, что аргументы функций также являются 3. JSONP использует__________ .
5.Формат, который, как мы все полагали, «спасет» мир.
8.__________ представляет собой новейшую модель автомата 6.__________ ,работающий контролером качества, был расстроен,
для продажи жевательной резинки Mighty Gumball с поддержкой под­ когда запрос, отправленный на производственный сервер Mighty
ключения кИнтернету. Gumball, потерпел неудачу.
10. Одно из прозвищ XMLHttpRequest в Microsoft. 8. Локальный сервер легко установить в операционной системе
13. Мы допустили_________ ,сначала углубившись на 25 страниц
в главу и только затем рассказав вам о браузерной политике безо­ 9. У _________ имеется веб-служба JSONP.
пасности. 11. Используемые JSONP типы объектов.
15. XMLHttpRequest высмеял слово_______ в названии JSONP. 12. Компания Mighty Gumball проводит тестирование модели торгового
автомата MG2200 в__________ .
14. напомнила Фрэнку,Джиму иДжо о междоменных проблемах,
возникающих В случае С XMLHttpRequest.
312 глава 6
общение с веб-службами

Специальное сообщение
из главы 7 ...

Пока в вашей памяти еще свежи


знания о JSONP, мы хотели бы;
чтобы вы помогли нам кое с чем
в главе, посвященной элементу
v . canvas.

Мы работаем с АР1-интерсреисом
JSONP T w itte r и создаем службу, ко­
торая дает пользователям возможность
размещать на футболках любые твиты.

Мы любим говорить: «Если


вы — поклонник T w itte r,
то закажите футболку с от­
печатанным на ней твитом».

Оснобятел&ница
Tw/eetS^i rt.com

дальш е ► 313
решение кроссворда

314 глава 6
7 р аскр ы в аем б се^е х у д о ж н и к а

% т

Элемент canvas *
Да, разметка — это, конечно,
здорово, но ничто не сравнится
с тем, когда собственными руками
раскрашиваешь что-либо свежими,
аккуратными пикселами.

HTML больше не является просто языком «разметки». Благодаря


новому НТМ1_5-элементу canvas у вас появилась возможность собственноруч­
но создавать пикселы , манипулировать ими и уничтожать их. В этой главе мы
й- Ладно,
воспользуемся элементом canvas, чтобы раскрыть таящегося в вас художни- ^
ка — больше никаких разговоров о HTML, когда речь идет чисто о семантике « уИичто-
и отсутствуют представления; используя canvas, мы начнем раскрашивать и жать»
рисовать красками. Теперь все будет опираться на представления. Вы узнаете, Mblj в03~
, МОЖНОJ
как вставлять элемент canvas в свои страницы, как рисовать текст и графиче-
немного
ские изображения (естественно, используя JavaScript) и даже как быть в случае перебор -
с браузерами, не поддерживающими данный элемент. ^ щили.
Как стало известно, на самом деле элементы <canvas> и <video> дела­
ю т нечто большее, чем просто делят друг с другом одни и те же веб­
страницы... Об этих любопытных подробностях мы поговорим позже.
новый стартап tweetshirt

Наш новый cmapman: TweetShirt


Наш девиз звучит так: «Если вы поклоппик Твиттера, по сите фут­
болки TweetShirt».
В копце копцов, чтобы пазы ваться журпалистом, нужпо стре­
миться к тому, чтобы паписаппое вами ону бликовали, а лучшее
место для печати п а футболке — область груди! По крайпей
мере, в этом заклю чается суть коммерческого п ризы ва паше-
го стартапа, которого мы будем придерж иваться.
Ч тобы успешпо полож ить пачало даппому стартану, пам
потребуется веб-приложепие, позволяю щ ее клиептам соз­
давать пользовательский дизайп футболок, отраж аю щ ий
одип из их педавпих твитов.

t
Вероятно, вы подумали: « А зна е т е, это неплохая идея». Что ж , в т аком случае мы
с вами успешно положим начало данному с т а р т а п у , создав к концу главы полност ью
готовое к работе веб-приложение. А если вы р еш ит е использовать его для зараба­
тывания денег, мы не ст анем заявлять права на и нт е л ле к т уа л ь н ую собственность,
но хот я бы вышлите нам бесплатную футболку!

Мы любим говорить:
«Если вы поклонник Твит­
тера, закажите футболку
с отпечатанным твитом».

Нам требуется соответствующее


веб-приложение, которое даст пользо­
вателям возможность создавать классные
представления их любимых твитов.

Нам также необходимо обе­


спечить его работоспособность
на различных устройствах. Наши клиенты
пользуются Твиттером, находясь в дороге,
и они смогут создавать дизайн футболок
в пути, причем в режиме реального
времени!

Основательница
Т\л/ е et S Кir t ’-со w

316 глава 7
раскрываем в себе художника

Взгляд на «оригинал-макет»
П роведя исчерпывающ ую итеративную разработку и обш ирпое тестирование с участием
фокус-группы, мы создали оригипал-макет (процесс его создапия по-другому пазы вается
пачальпы м визуальпым проектированием ), па которы й сейчас и взгляпем.
Это наш ст арт ап. Сначала мы
все нарисовали на са лф ет ке, сидя
болки в Starbuzz Coffee.
Д изайн

Наше веб-приложение
должно по возмож­
ности выглядеть,
как данная с т р а н и ­
ца! Д р у ги м и словами,
мы х о т и м показывать
дизайн ф утболки и
предоставлять п о л ь ­
зоват елю возмож­
ность интерактивно
изменят ь его с п о ­
мощ ью элемент ов
управления.

А вот как v
должен вы гля- \
деть интерфейс \
пользователя.
S elect background c o lo r JVK/teJ* ]

Пользователь сможет выбирать Circles o r Squares? jarcies | ; j


цвет фона (Select background
color), круги или квадраты для Select text color. fdlackJ^J
отображения на фоновой по верх­
ности (Circles or Squares?), цвет Peek a tweet:
т екст а (Select t e x t color) и т в и т
|p V g w e w j
(Peek a tweet).

дальше ► 317
обзор требований

М 9 * Г 9 * 9 Й _____________________________________________________________________________________________________________________________________________________________________________________

Ш ТУРМ
Взгляните еще раз на требования, приведенные на предыдущей странице. Как вы считаете,
можно ли их выполнить, используя HTML5? А помните, что одно из требований заключает­
ся в обеспечении работоспособности вашего сайта на как можно на большем количестве
устройств различного формата и размера?
Ознакомьтесь с приведенными ниже возможностями (а затем выберите наилучший ответ).

□ Можно просто использовать технологию Flash, поскольку она работает в боль­


шинстве браузеров.
□ Можно обратить свой взор на HTML5 и посмотреть, есть ли какие-нибудь но­
вые технологии, которые могут помочь (подсказка: есть одна такая технология
под названием canvas).
j | Можно написать пользовательское приложение для каждого устройства, бла­
годаря чему вы будете знать, какое именно качество взаимодействие обеспе­
чите для своих пользователей.
□ Можно задействовать вычислительную обработку изображений на стороне
сервера, а затем доставлять их в браузер.

Часш°
ЧаДаВаеМые
В опросы

А серьезно, почему бы в данной ситуации не использо­ Мне нравится идея генерирования изображений на сторо­
вать Flash или не прибегнуть к написанию пользовательского не сервера. Таким образом, я смогу написать один блок кода,
приложения? который вместе с генерируемыми изображениями сможет
работать на всех устройствах. Я немного знаю РНР, так что
0 : Flash является замечательной технологией и вы, несомненно, эта задача должна быть мне по плечу.
можете использовать именно ее. Однако в настоящее время инду­
стрия движется по направлению к HTML5, и на момент написания
0 : Это еще один путь, по которому вы можете пойти, однако
данной книги у вас могли бы возникнуть проблемы с выполнением
его недостаток заключается в том, что если у вас будет огромное
Flash-приложений на всех устройствах, включая очень популярные.
множество пользователей, вам придется беспокоиться о масштаби­
Написание пользовательского приложения является отличным
ровании используемых для генерирования изображений серверов,
выходом, если вам требуется обеспечить для пользователей вза­
чтобы они смогли удовлетворить предъявляемые требования
имодействие, полностью заточенное под конкретное устройство.
(в противопоставлении с тем, когда клиент каждого из пользовате­
Имейте в виду, что разработка пользовательского приложения для
множества разных устройств — дело затратное. лей сам будет генерировать предварительный просмотр футболки).
Вы также сможете обеспечить более интерактивное и цельное
В случае с HTML5 вы получаете отличную поддержку со стороны
взаимодействие, если предпочтете написать соответствующий
браузеров как для мобильных, так и для настольных устройств
код для браузера.
и зачастую можете создавать приложения, используя всего одно
технологическое решение. Как? Что ж, мы рады, что вы об этом спросили...

318 глава 7
раскрываем в себе художника

Заглянем к ребятам из команды TweetShirt...

LiuV
Вы уже ознакомились с требованиями, а также с базовым проектировани­
ем взаимодействия пользователя с приложением. Пришло время перейти
к сложной части — реализации всего этого на практике. Давайте прислуша­
емся к разговору и узнаем, как обстоят дела...

Джо: Я думал, что все будет просто, пока пе увидел эти ф оповы е круги.
Фрэнк: Ч то ты хочеш ь этим сказать? Ведь это всего лиш ь изображ епие...
Джудн: Нет, пет, осповательпица TweetShirt хочет, чтобы разм ещ епие кру- Я -ч
гов происходило случайпым образом, благодаря чему располож ение кругов, ^ фрэнк> Л
к примеру, па м оей футболке будут отличаться от располож ения кругов па w А* 0
твоей. То же самое и с квадратами.
Фрэнк: Все пормальпо, поскольку рапы не мы делали это, геперируя изобра­
ж епие п а сторопе сервера.
Джо: Да, я зпаю, по такой подход был пе очепь разумпым; помпите, как пам
приходилось платить ком папии Am azon за пользовапие серверами?
Фрэнк: Да. Но это пе беда.
Джо: В лю бом случае, пам пеобходимо, чтобы все работало очепь быстро,
то есть пе было пикаких долгих «рейсов» обратпо па сервер. Поэтому давай­
те будем делать все па сторопе клиепта, если это возможпо.
Джудн: Ребята, я думаю, что это возможпо, я тут смотрю па canvas в HTML5.
Фрэнк: Я всего лиш ь дизайпер, поэтому разъяспи мпе, что это такое.
Джудн: Ф рэпк, ты, должпо быть, уже слышал о canvas —это повы й элемепт
в HTM L5, которы й п озволяет создавать поддерживающую рисовапие об­
ласть для 2 Б-фигур, текста и растровы х изображ епий.
Фрэнк: Все это похож е па тег <img>. Мы просто помещ аем его в страпицу
с указапием ш ирипы и высоты, а браузер делает все остальпое.
Джудн: Н еплохое сравпепие, мы действительно определяем ш ирину и вы­
соту для canvas, одпако в даппом случае все рисуемое в canvas будет зави­
сеть от JavaScript-кода.
Джо: А где здесь в дело вступает разметка? М ожпо ли сказать canvas
па JavaScript: «Даппый элемепт <hl> пеобходимо разм естить вот здесь».
Джудн: Нет, после того как ты помещ аеш ь canvas в страпицу, ты оставляеш ь
мир разм етки позади; па JavaScript мы размещ аем точки, липии, коптуры,
и зображ епия и текст. Это пизкоуровпевы й API-иптерфейс.
Джо: Ч то ж, если оп сможет справиться со всеми этим и размещ аемы ми слу­
чайпы м образом кругами, то оп мепя устраивает. Ладпо, хватит разговоров,
давайте взгляпем па пего!

дальше ► 319
добавление canvas к странице

Как добавить canvas в свою веб-страницу


Ф рэпк был прав в том, что canvas песколько схож с элемептом <img>. Д обавлепие canvas
осущ ествляется следующим образом:
Элемент canvas п ред­ А т р и б у т w idth опреде­ Аналогичным образом height
ст а вл яе м собой обычный ляет количество пикселов определяет верт икальную об­
HTML-э лем ент , в нача­ по горизонтали, которое л аст ь веб-страницы, кот орую
ле которого располага­ canvas будет заним ат ь будет за ним ат ь элем ент canvas
ется открывающий тег на веб-странице. (в данном случае — 2-00 пикселов)-
<canvas>.
I
Ccanvas id=MlookwhatIdrewM width="600
К
height=lf200"></canvas>

v. I I
Мь/ добавили id для иден­ Здесь для w idth
Закрывающий тег
тификации canvasj а как мы задали значе­
его использовать, вы ние (оОО пикселов.
увидите чут ь позже...

Браузер выделит пространство па веб-страпице для canvas согласпо указаппым зпачепиям


width и height.
В данном случае значением
w idth является (оОО> а зн а -
Аевая верхняя " чением height — 2-00.
позиция canvas.
Ъудем использо­
ват ь э т у точку, L&ok ID'rw
чтобы о т м е р ят ь
все остальное
в canvas (в чем вы
вскоре убедитесь)
Высота canvas (в н а ­
шем случае она равна
2.00 пикселам).
/ I
Вокруг canvas
имеется неболь­
шое п р о с т р а н ­
ство, п р ед с т а в­ Ширина canvas (<ЬОО пикселов)
ляющее собой поле Ваш повседневный
по умолчанию I—Может об т е­
элемент а <body>. к а т ь canvas. Элемент
canvas является т аким
же, как и любой другой
элем ент (например,
im age и т. п..).

320 глава 7
раскрываем в себе художника

Tecm-драйв вашего нового canvas


П риш ло врем я задействовать даппы й элемепт па ваш ей веб-страпице. Н аберите приве-
деппы й пиж е код и сохрапите его в повом файле, а затем загрузите в своем браузере.

< ! d o c ty p e h tm l>
< h tm l la n g = " e n " >
<head> Напечатайте данный код
< t i t l e > L o o k W hat I D r e w < / t i t l e > и п р о т е с т и р у й т е его.
< m eta c h a r s e t = " u t f - 8 ">
< /h e a d >
<body>

< ca n va s id = " lo o k w h a t I d r e w " w id t h = " 6 0 0 " h e i g h t = " 2 0 0 " > < /c a n v a s >

< /b o d y >
< / h tm l>

В чем дело? Моя


страница пуста!

Вот что видит она...

...вероятно, то же са ­
мое увидите и вы!

Мы нарисовали эти
линии, чтобы объяс­
нить, как именно canvas
вставляется в с т р а н и ­
цу, и сделали это лишь
в целях иллюстрирования.
На самом деле их т а м не
будет (если только вы их

сами не нарисуете).
Переверните страницу,
чтобы узн ат ь больше...

дальше ► 321
добавление css для canvas

Как увидеть свой canvas


П ока вы пе парпсуете что-пибудь в элемепте c a n v a s , вы его пе увидите. О п просто является простран ­
ством в окпе браузера, в котором вы мож ете рисовать. Рисовапием в c a n v a s мы займемся очепь скоро,
а па даппы й момепт пам требуются доказательства того, что c a n v a s действительно присутствует в па­
ш ей страпице.
Существует другой способ увидеть ca n v a s ... Если мы прим епим CSS для стилизации элем епта < c a n v a s> ,
чтобы стала видимой его рамка, то сможем увидеть его па страпице. Задействуем простой стиль, кото­
ры й добавляет черную рамку ш и ри пой 1 пиксел для ca n v a s .
< ! d o c ty p e h tm l>
< h tm l la n g = " e n " >
<head>
< t i t l e > L o o k W hat I D r e w < / t i t l e >
<m eta c h a r s e t = " u t f - 8 ">
< s t y le >
Mы добавили ст иль для canvas,
ca n va s { который просто р и су ет черную
b o rd e r: lp x s o lid b la c k ; границу толщиной пиксел, к о т о ­
р у ю можно видеть на странице.
< /s ty le >
< /h e a d >
<body>
< ca n va s id = " lo o k w h a t I d r e w " w id t h = " 6 0 0 " h e i g h t = " 2 0 0 "> < /c a n v a s >
< /b o d y >
< / h tm l> ooo Look What I Drew

Так намного лучше!


Теперь мы видим
canvas. Д а льш е сде­
лаем с ним кое-чт о
интересное...

322 глава 7
раскрываем в себе художника

Часш°
^адаВ аеМ ы е
В опросы

На каждую страницу может приходиться только один Можно ли использовать CSS для задания ширины и высо­
canvas? ты canvas вместо атрибутов width и height в случае с данным
элементом?

0 : Нет, вы можете вставлять в страницу столько элементов


canvas, сколько вам потребуется (либо то количество, с которым 0 : Да, можно, однако здесь все будет работать немного по-
сможет справиться браузер или ваши пользователи). Просто при­ другому, чем вы могли бы ожидать. По умолчанию элемент canvas
свойте всем им уникальные id , и вы сможете рисовать в каждом из имеет ширину 300 пикселов и высоту 150 пикселов. Если вы не за­
них как в отдельном canvas. Вскоре вы увидите, как использовать дадите атрибуты w id t h и h e ig h t в теге < c a n v a s >, то элемент
i d элемента canvas. получит размеры по умолчанию. Если вы затем зададите размеры,
используя CSS, допустим, 600 х 200 пикселов, то c a n v a s раз­
Является ли canvas прозрачным? мером 300 х 150 пикселов подвергнется масштабированию в
В соответствии с этими новыми параметрами, равно как и все, что
будет в нем нарисовано. Это сродни масштабированию изобра­
0 : По умолчанию c a n v a s является прозрачным. Вы можете
жения путем задания для него новых ширины и высоты, которые
рисовать в элементе ca n va s, заполняя его цветными пикселами.
больше или меньше, чем реальные ширина и высота этого изо­
Как именно это делается, вы узнаете позже в данной главе.
бражения. А при увеличении на изображении будет наблюдаться
пикселизация, не так ли?
Если canvas прозрачен, то это означает, что я могу раз­
Тоже самое происходит и в случае с c a n va s. Элемент ca n va s
местить его поверх другого элемента, чтобы, например, на­
шириной 300 пикселов, масштабируемый до ширины 600 пикселов,
рисовать что-нибудь на изображении или еще на чем-либо,
будет включать прежнее количество пикселов, но растянутых вдвое,
имеющемся на странице, ведь так?
из-за чего все станет выглядеть несколько неуклюже. Однако
если вы задействуете атрибуты w id t h и h e i g h t в < c a n v a s >,
0 : Все верно! Это одна из замечательных особенностей canvas. то сможете задать для ca n v a s размеры, которые будут больше
Он позволяет добавлять графику в любую часть веб-страницы. (или меньше), чем 300 х 150 пикселов, и все создаваемое в этом
c a n v a s будет отрисовываться нормально. Таким образом, мы
рекомендуем задавать атрибуты тега w i d t h и h e i g h t и не
прибегать к CSS для настройки данных свойств, если только вы
действительно не хотите масштабировать ca n va s.

Ш ТУРМ
Возможно, вы обратили внимание на то, что наш элемент canvas
не включал никакого содержимого. Если поместить текст между тега­
ми, то что, по вашему мнению, будет делать браузер, когда страница
загрузится?

° #) < / canvas> I

дальше ► 323
рисование в canvas

Рисование в элементе canvas


Н а даппы й момепт у пас имеется нустой элемепт canvas. Н е будем
медлить, постараемся обрести вдохповепие как JavaScript-писатели
и поместим в паш canvas прямоугольпик с черп ой заливкой. П ред­
варительно пам потребуется реш ить, где имеппо оп будет распола­
гаться и пасколько большим мы его сделаем. Как пасчет того, чтобы
его м естополож епие было х = 1 0 и у = 1 0 пикселов, а вы сота и ш ирипа
равпялась 1 0 0 пикселам? Так и поступим.
А теперь взгляпем па код, которы й пам будет для этого пеобходим:
— Сначала идет с т а н -
дартный HTMLS.
< ! d o c ty p e h tm l>
< h tm l la n g = " e n " >
<head>
Наша C SS -рам ка
< t i t l e > L o o k W hat I D r e w < / t i t l e > остается на месте.
<m eta c h a r s e t = " u t f - 8 " />
< s t y le > г 0т наш обработчик
13
Д л я рисования
c a n va s { b o rd e r: lp x s o lid b la c k ; } onload; рисовать мы в canvas нам п о ­
< /s ty le > начнем п о е м полной т ребует ся ссылка
< s c r ip t > загрузки страницы на него. Воспользуемся
w in d o w .o n lo a d = f u n c t i o n () { g etE lem en tB yld , чтобы
извлечь ее из РОМ.
v a r canvas d o c u m e n t. g e tE le m e n tB y ld ( - t s h ir t C a n v a s »> ;
это инт ересно, нам я н°
v a r c o n te x t = canvas . g e tC o n te x t ("2 d ") ; рисовать...

c o n t e x t . f i l l R e c t (1 0 , 1 0 , 1 0 0 , 1 0 0 ) ; ^ “ " И спользуем конт екст 2 d для рисова-


А ' Т ния прямоугольника с заливкой в canvas.
Эти числа являются Здесь у нас также им ею т ся
позицией х, у
}; ширина и высота (в пикселах),
< /s c r ip t>
Любопытно то, что м ет од fillRect
< /h e a d > не п рини м ает цвет заливки... Подробнее
<body> об э т о м мы поговорим чут ь позже.
< ca n va s w id t h = " 6 0 0 " h e ig h t = " 2 0 0 " id = " t s h ir t C a n v a s " > < / c a n v a s >
< /b o d y >
< / h tm l>
И не будем забывать о нашем элем ент е canvas.
Здесь мы определяем canvas шириной (ЬОО и вы­
сотой ZOO пикселов, с id в виде "tshirtCanvas".

324 глава 7
раскрываем в себе художника

Небольшой mecm-драйВ canvas...


Н аберите приведеппы й чуть выше код (либо мож ете взять его с h ttp :/ / w ickedlysm art.com /hfhtm l5)
и загрузите его в своем браузере. Если вы используете соврем еппы й браузер, то долж пы увидеть
п рим ерпо то же, что и мы:

Вот наш прямоугольник с размерами гоо * гОО пик


селов, имею щий позицию Ю , 1 0 в canvas.

А вот наш canvas шириной 6 о о


и высотой ZOO пикселов с черной
рамкой толщиной 1 пиксел.

Более пристальный Взгляд на код


Э то был отличпый пеболы ной тестовы й прогоп, одпако давайте пы рпем пемпого глубже.

В паш ей разм етке мы определили canvas и присвоили ему идентиф икатор, используя
тег <canvas>. П ервое, что пам пеобходимо сделать, чтобы пачать рисовать в даппом
canvas, —это извлечь ссылку п а объект canvas в объектпой модели докумепта (DOM).
Как обычпо, мы делаем это с помощью метода getElementByld:

var canvas = document.getElementByld("tshirtCanvas");

дальше ► 325
обзор работы кода canvas

Мы располагаем ссылкой па элемепт canvas, присвоепп ой п ерем еп пой canvas. Далее


пам нужпо разобраться с частью «протокола», которому пеобходимо следовать, прежде
чем мы сможем п ерей ти к рисовапию в canvas. Н ам нужпо сказать canvas, чтобы оп
предоставил пам коптекст для рисовапия. А в даппом случае пам требуется имеппо коп-
текст 2 d. Коптекст, возвращ аемы й canvas, п рисваивается п ерем еп пой c o n te x t:

var context = canvas .getContext( ff2 d ff) ;


Это часть « прот окола», которому
~ нам необходимо следовать, прежде
чем мы сможем п р и с т у п и т ь к ри со ­
ванию в canvas.
Теперь, имея в руках объект context, мы можем использовать его для рисовапия в canvas,
для чего вы зы ваем метод f i l l R e c t . Д аппы й метод создает прямоугольпик, беря за пача-
ло позицию х, у со зпачепиям и соответствеппо 1 0 , 1 0 , при этом оп будет иметь ширину
и высоту 1 0 0 пикселов.

О б ра т ит е внимание, что мы вызываем м е ­


тод fillRect в отношении c o n tex t, а не canvas.

j
context.fillRect(10, 10, 100, 100);

ч Проведите т е ст , и вы увидите, как п о ­


явится черный прямоугольник. Попробуйте
изм енит ь значения х, у, а также ширину
и высоту и п осм от ри т е, что будет.

Ш ТУРМ
Можете ли вы придумать способ использовать элемент canvas,
если ваш браузер поддерживает его, а при отсутствии поддерж­
ки просто выводить сообщение, например: Hey, you, yes
you, upgrade your browser! ! (Эй, вы, да, вы, обно­
вите свой браузер! !)?

326 глава 7
4acm< раскрываем в себе художника

^аД аВ аеМ ы е
BoTLj=>otbl
I ) ; Откуда c a n va s знает, что к прямоугольнику
Ж Л Т1ля- любознательных ---------------
следует применять именно черную заливку?

! В случае c a n v a s черный является цветом


О
по умолчанию. Конечно же, можно изменить это, Интересно, а как предусмотреть в коде проверку
воспользовавшись свойством f i l l s t y l e , в чем
на предмет того, поддерживает браузер canvas
вы вскоре убедитесь.
или нет?

А если мне потребуется нарисовать контур Это, конечно же, можно сделать, однако отметим, что все
прямоугольника, а не фигуру с заливкой? это время предполагалось, что наш браузер поддерживает
canvas. Но в любом производственном коде вам будет необ­
0 : Чтобы нарисовать только контур прямоуголь­ ходимо позаботиться о проведении проверки, чтобы убедиться
ника, вместо f i l l R e c t следует воспользоваться в наличии такой поддержки.
функцией s tr o k e R e c t . Подробнее об обводке
Все, что вам потребуется сделать, — это проверить, при­
мы поговорим позже в этой главе.
су тс тв у е т ли метод getContext в с о о тв е т с тв у ю ­
щем объекте canvas (который возвращается методом
Что такое контекст 2d и почему нельзя рисо­
getElementByld):
вать сразу в canvas?
Сначала мы извлекаем ссылку
I canvas представляет собой графическую об­ на элем ент canvas в ст ранице.
0
ласть, отображаемую на веб-странице, c o n te x t — v a r canvas = ^
это объект, ассоциированный с c a n va s, который d o c u m e n t .g e t E l e m e n t B y l d ("tshirtCanvas") ;
определяет набор свойств и методов, используемых if (canvas.getContext) {
для рисования в can va s. Вы можете даже сохра­ // под д е р ж к а canvas имеется
нять состояние c o n te x t, а затем восстанавливать } else {
его позже, что иногда бывает кстати. В оставшейся // и з в и н и т е , A P I -интерфейс canvas
части этой главы вы познакомитесь с множеством не поддер ж и в а е т с я
свойств и методов объекта c o n te x t. }
Элемент canvas создавался с расчетом на поддерж­ З а т е м проверяем п р и сут ст вие метода
ку более одного интерфейса — 2d, 3d и пр., о ко­ getContext. О б р ат и т е внимание: мы не вызываем
торых мы даже еще не задумывались. Используя егоj а просто см о т р и м , есть ли у него значение.
c o n te x t , можно работать с разными интерфей­
сами в пределах одного элемента canvas. Нельзя
рисовать сразу в can va s, поскольку необходимо Если вы захотите проводить проверку на предмет поддержки
будет указать, какой интерфейс вы используете, canvas без необходимости заранее иметь canvas в своей
выбрав c o n t e x t . разметке, то можете создавать элемент c a n v a s «на лету»,
используя все методики, которые вам уже известны. Например:
Означает ли это, что существует также кон­ var canvas =
текст 3d?
d o c u m e n t .c r e a t e E l e m e n t ("canvas") ;

Q : Пока еще нет. Существует ряд конкурирую­ He забудьте заглянуть в приложение (в конце книги), где име­
щих перспективных стандартов, но не похоже, что ется информация о библиотеке с открытым исходным кодом,
какому-либо из них уже удалось стать лидером. которую вы сможете использовать для проведения последова­
Не упускайте из виду данный момент; между тем тельного тестирования на предмет поддержки всевозможной
взгляните на библиотеку WebGL, а также на библи­ функциональности в HTML5.
отеки, которые ее используют, например SpiderGL,
SceneJS и three.js.

дальше ► 327
canvas и internet explorer

Когда я провожу тест


в In te rn e t Explorer, то ничего
не вижу там, где должен быть
canvas. В чем тут дело?

Internet Explorer поддерживает canvas только


с версии 9 и выше, поэтому вы должны преду­
смотреть в коде своей страницы вывод соот­
ветствующего сообщения для пользователей.
Дело обстоит следующим образом: если вам дей­
ствительно требуется обеспечить поддержку фупк-
циональности canvas в браузере In tern et Explorer
(версии ниж е 9), то вы мож ете прибегнуть к про­
екту ExplorerCanvas или иному похожему инстру­
менту и использовать его как плагип, обеспечива­
ющий данную функциональность.
Теперь предположим, что вы реш или уведомлять
своих пользователей о том, что опи упускают заме­
чательное содерж имое вашего canvas. П осмотрим,
как это сделать...

И, возможноj вы также посо­


ве т уе т е им обновить браузер
Internet Explorer до версии <?/

328 глава 7
раскрываем в себе художника

Выходим достойно из проблемной ситуации


И так, возможпо возппкповеппе ситуации, когда пользователь реш ит зайти па ваш сайт,
по его браузер пе будет поддерж ивать элемепт canvas. Н е хотели бы вы в этом случае вы­
вести для пего сообщ епие о том, что ему следует обповить браузер? Вот код, которы й для
этого потребуется:
Мы используем типичны й,
заурядный элем ент canvas.
/
< can v as id = " a w e so m e c o n te n t" >
Hey you, y es YOU, u p g ra d e y o u r b ro w s e r!
< /c a n v a s > Сообщение, которое будет выводиться

\ для пользователей, чьи браузеры не под-


д е р х и в а ю т canvas.
Как это работает? Всякий раз, когда браузер видит пезпаком ы й элемепт, оп по умолча-
пию вы водит лю бой содерж ащ ийся в пем текст. Таким образом, когда браузеры, пе под­
держиваю щ ие элемепт <canvas>, столкнутся с пим, опи выведут п а э к р а п сообщ епие Неу,
you, yes YOU, upgrade your b r o w s e r ! ! (эй, вы, да, ВЫ, обновите свой браузер!!).
А поддерж иваю щ ие даппы й элемепт браузеры будут просто и гнори ровать лю бой текст
между тегами <can v a s > и пе стапут выводить его па экрап.

Г За то, что все это


делается т ак легко,
мы должны побла­
Hey y o u , ye s годарить парней
YOU, upgrade (и девушек), за н и м а ­
y o u r b r o w s e r !!
ющихся разработкой
ст андартов HTMLS!

Как вы уже зпаете, другой способ выхода из ситуации, когда браузеры пе поддерж ива­
ю т canvas, заклю чается в использовапии JavaScript с целью вы яспепия того, зпаком ли
браузеру даппы й элемепт. Такой подход обеспечивает пемпого большую гибкость в обе­
спечении для пользователей ипого взаимодействия в случае, если их браузеры пе будут
поддерж ивать canvas; паприм ер, вы сможете перенаправить их па другую страпицу или
взамеп вы вести па экрап какое-то изображ епие.

дальше ► 329
обзор плана реализации

Теперь, когда мы знаем, как создавать


прямоугольники, можно использовать
аналогичный подход для создания квадратов
в canvas, не так ли? Нам необходимо понять,
как размещать их на футболке случайным об­
разом, с заливкой цветом, выбранным поль­
зователем.

Фрэнк: Да, конечно, но нам также потребуется интерф ей с


пользователя, с помощью которого люди смогут выбирать
пеобходимы е им варианты . Я имею в виду, что у нас есть
макет, по его нужно реализовать.
Джудн: Ты прав, Фрэнк. Д вигаться дальше без интерф ей са
пе им еет смысла.
Джо: О н, вероятно, будет представлять собой простой
HTML?
Фрэнк: Да, похоже. Однако если исходить из того, что мы
пы таемся все сделать на стороне клиента, то как оно будет
работать? Н априм ер, куда будет отправляться форма? Я не
увереп, что понимаю, как все это станет слаж енно функци­
онировать.
Джо: Ф рэнк, мы можем просто вы зы вать JavaScript-функ-
цию, когда пользователь паж мет кпопку Preview (П редва­
ри тельны й просм отр), а затем отображ ать дизайп футбол­
ки в элемепте canvas.
Фрэнк: Звучит разумпо, по как мы получим доступ к зпаче-
пиям ф ормы , если все опи будут располагаться па сторопе
клиепта?
Джудн: Тем же путем, каким мы всегда получаем доступ
к объектпой модели докумепта (DOM); мы можем восполь­
зоваться docum ent. getE lem entB yld для и звлечепия зпаче-
п ий формы .
Вам уже доводилось делать это рапее.
Фрэнк: Ч то ж, ребята, отступать пам пекуда.
Джо: Ладпо, давайте вместе пош агово во всем разберемся.
Н ачпем с рассм отрения общ ей картипы .

330 глава 7
раскрываем в себе художника

TweetShirt: общая картина


П реж де чем мы приступим к серьезпой работе по реализации задумаппого,
давайте взгляпем па общую картипу. Мы собираемся создать веб-приложепие,
используя элемент c a n v a s п а р а д у с элемептам и ф ормы , которы е будут играть
роль и п тер ф ей са пользователя, а всю работу за кадром будут вы полпять
JavaScript и API-интерфейс Canvas.
Вот как все будет выглядеть:

JavaScript будем о т вечат ь


за извлечение введенных п о л ь ­ а пхп HTML- будет о\мве
зоват елем данных из формы
и рисование посредством canvas и простои фор
A P I-интерф ейса Canvas.
1 *1 *л ог Ж с>
I
и ш

JS
Это canvas
чдля дизайна

фмтболки.

S elect background color: ^ M(?i будем и с п о л ь


L з овать JavaScript
Circles o r Squares? ic'trcles 1*1 ъАЯ рисования
, Z Z T e canvas графики
S elect te x t color: ^ ^ т §олки.

Peek, a tw e e t:
Щелчок на кнопке Preview
интерф ейс п о л ь -^
(Предварительный п р о ­
зователя, который
см от р) будет вызывать
n 0 cyvnu явл яется
JavaScript для выполне­
э л е м е н т о м form.
ния со от вет ст вую щ их
действий и генерирования
предварительного п р о ­
В определенный м о м е н т нам пот ребует ся под­
см от ра футболки.
держка со стороны сервера для торговли ф у т б о л ­
ками через И н т ер не т , но мы реш или ост авит ь
э т у часть работы вам (ее придется выполнить,
когда вы будете организовывать собственный
ст артап). Не забудьте присла т ь нам бесплатную
футболку. А если вы, как основатели ст а р т а п а ,
возьмете нас в долю, то это будет еще лучиле!

дальше ► 331
СТАНЬ браузером

КЛ1°Чаетгк:*г Б Л1°М, Чцю&ы сыГ^агщ» |^оЛь браузера

^деЛаБ зщо, сравните БаШ интерфейс с лри—


БеДенныМ на 1^едыдущей ог^аниДе, Чцюёы
узнать, Бее Ли Бы г^аБиЛьНо сделали.
< f огш>
<р>
< l a b e l f o r = " b a c k g r o u n d C o lo r " > S e le c t b a c k g ro u n d c o l o r : < / la b e l >
< s e le c t id = " b a c k g r o u n d C o lo r " >
< o p t io n v a lu e = " w h it e " s e le c t e d = " s e le c t e d " > W h it e < / o p t io n >
< o p t io n v a lu e = " b la c k " > B la c k < / o p t io n >
< / s e le c t >
< /p >
<p>
< l a b e l f o r = " s h a p e " > C ir c le s o r s q u a r e s ? < /la b e l>
< s e le c t id = " s h a p e " >
< o p t io n v a lu e = " n o n e " s e l e c t e d = " s e le c t e d " > N e it h e r < / o p t io n >
< o p t io n v a l u e = " c i r c l e s " > C i r c l e s < / o p t i o n >
< o p t io n v a lu e = " s q u a r e s " > S q u a r e s < /o p tio n >
< / s e le c t >
< /p >

< l a b e l f o r = " f o r e g r o u n d C o lo r " > S e le c t t e x t c o l o r : < / la b e l >


< s e le c t i d = " f o r e g r o u n d C o lo r ">
< o p t io n v a lu e = " b la c k " s e le c t e d = " s e le c t e d " > B la c k < / o p t io n >
< o p t io n v a lu e = " w h it e " > W h it e < / o p t io n >
< / s e le c t >
< /p >
<p>
< l a b e l f o r = " t w e e t s " > P ic k a t w e e t : < / la b e l >
< s e le c t id = " t w e e t s " >
< / s e le c t >
< /p >
<p>
< in p u t t y p e = " b u t t o n " id = " p r e v ie w B u t t o n " v a lu e = " P r e v ie w " >
< /p >
< /fo r m >

332 глава 7
раскрываем в себе художника

Результ ат рендеринга вашего —\


интерфейса изобразите здесь.
Нарисуйте, как будет вы гля- ▼
деть веб-страница с элем е н ­
т а м и формы слева.

СТАНЬ 6рду>ером еще pa)


Теперь, к°гда у Бас есть ингоер^ейс, вЬх—
Представьте, что вы ис­ полните при«еденные здесь Ja V a ^ t-
пользует е э т о т и н т е р ­
и н ап иШ и те Значение ДЛЯ
фейс для выбора вариантов
для своей футболки. к а ж д о го э л е м е н т а и н т е р ф е й с а .
(V u оШБешы Бы см°же:те
г^оВ е^ш рь в реш ении к д а н н о ^
у п р а ж н е н и е В Конце ГЛаБы.

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " b a c k g r o u n d C o lo r " ) ;
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;
v a r b g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " s h a p e " ) ;
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;
v a r shape = s e l e c t O b j [ i n d e x ] . v a l u e ;

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " f o r e g r o u n d C o lo r " ) ;
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;
v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

дальше ► 333
написание html

Сначала напишем необходимый HTML


Х ватит разговоров! Д авайте займемся создапием пашего прилож епия. П реж де чем мы сможем сделать
что-то еще, пам потребуется п ростая HTM L-страпица. О бповите свой файл index.html, чтобы его со­
держ имое выглядело следующим образом:
£ Д д, это славный H TM LS-
< !doctype html> совместимый файл!
<html lang="en">

<head> О б ра т ит е внимание,
что мы изменили з а ­
<title>TweetS h i r t < / t i t l e >
головок на T weetshirt.
<meta c h a r s e t = " u t f - 8 " />

<style>

canvas {border: lpx solid black;}


Поместим весь
</style> Ja va Script-код в о т д е л ь ­
<script s r c = " t w e e t s h i r t .js"></script>
ный файл, чтобы им было
немного легче управлять.
</head>

<body> Д вот наш canvas1


.
< h l > TweetShirt</hl>

<canvas width="600" height="200" i d = " t s h i r t C a n v a s "> Мы также


предусмот рели
<p>Please upgrade your browser to use T w e e t s h i r t !</p>
небольшое сооб-
</canvas> щение для п о л ь ­
<form>

Это fo rm , в кот ором будут


содержаться все элементы
\ зоват елейj к о т о ­
рые п р им еняю т
устаревшие
версии браузеров.
</f orm> управления для приложения
</body> T w eetshirt. Об э т ом мы пого­
ворим на следующей странице...
</html>

WTVPM
Что еще вам необходимо знать для того, чтобы заменить CSS-рамку в сво­
ем canvas рамкой, нарисованной в canvas с помощью JavaScript? Какую
методику вы предпочли бы (CSS или JavaScript) и почему?

334 глава 7
раскрываем в себе художника

Теперь добаВим < fo r m >


Итак, добавим и и тер ф ей с пользователя, чтобы мы могли приступить к паписапию кода для создапия
дизайпа футболок. Вы уже сталкивались с этим кодом рапыне, одпако па этот раз мы добавили ряд аппо-
таций, чтобы все было попятпо (пабирая код, обязательпо обратите па пих впимапие):

^ Весь э т о т код будет разм ещ ат ься между тегами


<form > £ Указа* ™ м и на предыдущей странице.
<Р >
< la b e l fo r = " b a c k g r o u n d C o lo r " > S e le c t b a c k g ro u n d c o l o r : < / la b e l >
< s e le c t id = " b a c k g r o u n d C o lo r " >
< o p t io n v a lu e = " w h it e " s e le c t e d = " s e le c t e d " > W h it e < / o p t io n >
< o p t io n v a lu e = " b la c k " > B la c k < / o p t io n > ^
< / s e le c t > Здесь пользователь будет выбирать ц cm
< / Р> --------------- фона для дизайна футболки. На выбор
<Р> дается черный (Ыаск\ либо бельш (white)
< la b e l f o r = " s h a p e " > C ir c le s o r s q u a r e s ? < /la b e l>
цвет. Вы можете добавить сюда другие
< s e le c t id = " s h a p e " >
цвета по своему усмотрению .
< o p t io n v a lu e = " n o n e " s e l e c t e d = " s e le c t e d " > N e it h e r < / o p t io n >
< o p t io n v a l u e = " c i r c l e s " > c i r c l e s < / o p t i o n > ^ Здесь мы задействуем еще один
C o p tio n v a lu e = " s q u a re s " > S q u a re s < /o p tio n > ^ э л е м е н т управления, позволяю -
< / s e le c t > выбирать круги (circles) или
квадраты (squares) для конф игу-
</&> рирования дизайна. Пользователь
<Р> также сможет выбрать в а р и -
< la b e l f o r = " f o r e g r o u n d C o lo r " > S e le c t t e x t c o l o r : < / la b e l > ант none (нет) — фон не будет
< s e le c t id = " f o r e g r o u n d C o lo r "> содержать никаких фигур.
< o p t io n v a lu e = " b la c k " s e le c t e d = " s e le c t e d " > B la c k < / o p t io n >
< o p t io n v a lu e = " w h it e " > W h it e < / o p t io n > Еще один элемент управления
< /s e le c t> select, на э т о т раз - для вы-
< /Р> бора цвета текста. О пя т ь ^
<р > т а к и , на выбор дается черный
< l a b e l f o r = " tw e e t s " > P ic k a t w e e t : < / l a b e l > ( b l a c k ) л и б о белый (white

< s e le c t i d - tw e e ts " > ) ^ ^ B o m где будут размещ ат ься все твиты. А почему здесь пусто?
< / s e le c t > А х да, мы же будем заполнят ь данный элем ент позже (подсказка:
</ р > нам необходимо, чтобы т вит ы извлекались непосредственно из
<р> Т ви т т ер а , ведь это же веб-приложение, не т ак ли?!).
< in p u t t y p e = " b u t t o n " id = " p r e v ie w B u t t o n " v a lu e = " P r e v ie w " >

< /fo r m > &CAU @ам доводилось ст алкиват ься с элем ент ам и g конце добавляем кнопку
fo r m , то вы, вероятно, обратили внимание, что дАЯ предварительного п р о -
здесь form не им еет ат ри б ут а action (а это озна- см от ра футболки,
ч ает , что при щелчке на кнопке Preview (Предвари­
тельный просм от р) ничего не произойдет). Со всем
э т и м мы разберемся через несколько мгновений...

дальше ► 335
добавление javascript

Пришло время добавить JavaScript для вычислений


Разметка — это, копечпо, хорош о, одпако имеппо JavaScript будет объедипять все веб-приложепие
TweetShirt. Мы разм естим необходимы й код в файле tweet s h i r t .j s. Н ачать мы собираем ся с размещ е­
н ия произвольны х квадратов п а футболке, по прежде пе обходимо активировать кпопку Preview (П ред­
варительны й просм отр), чтобы п ри ее паж атии происходил вызов JavaScript-фупкции.
Создайте файл tweetskirt.js
и добавьте в него данный код.
Сначала будет и з ­

window, onload = function ()


2 { ^
влекаться элемент
previewButton.
var but t o n = d o c u m e n t .g e t E l e m e n t B y l d ("p r e v i e w B u t t o n " );
b utton. o n c l i c k = p r e v i e w H a n d l e r ;

t Добавьте обработчик событий click для данной кнопхи,


«ри на ней (и д » к ■
но сенсор ном экране м об и м н о го у е ш p c u c m U ) п р т с х
дил вызов функции previewHandler.

Таким образом, когда кпопка Preview (П редварительны й просм отр) будет пажата, п роизой дет вызов
фупкции previewHandler. И здесь самое врем я обповить canvas с целью представить футболку, пад ди-
зайпом которой трудится пользователь. Приступим к паписапию p r e v i e w H a n d l e r :
Сначала извлекаем элем ент
function prev i e w H a n d l e r () { ^ запрашиваем его
c a n v a s
и

к онт екст рисования /-&•


var canvas = d o c u m e n t .g e t E l e m e n t B y l d (" t s h i r t C a n v a s ");
var context = canvas .getContext ("2d") ; ~rpneVb наМ необходимо узнать^ка
/ '''к ч Л ^ р в « интерфейсе
й ель Первым делом извле
var selectObj = d o c u m e n t .g e t ElementByld (" s h a p e " ) ; г^ОЛЬЗО am - a.^n "ска&е".
каем элем ент с id б Сиге ьп у
var index = s e l e c t O b j .s e l e c t e d l n d e x ; j
var shape = selectObj [index] .value; Г ^ З ат ем 8b^C^eMj какой элемент был вы-
_J оран (квадраты или круги), для чего извле -
индекс выбранного элем ент а и при —
If (shape == squares ) { сваиваем его значение переменной Фаре.
for (var squares = 0; squares < 20; squares++) {
draw Square (can v as, c o n te x t) ; „ X ,^д,лл
4 И если значением shape будет
«squares»,
К/\.\s\щ J нам пот ребует
I ся на
рисовать некоторое количество
квадратов. Ка к насчет 2-0 шт ук?

Что касается рисования каждого квадрата , мы будем полагаться


Обо а Т ЩиЮ dmw54uare>в т о р у ю нам предст оит написать
J ак
т L и7 context.
c Z ^ 7 Hm‘позже 7
Чуть п7 е3мм - '
уви ди т е , как мы их используем.

336 глава 7
раскрываем в себе художника
Часш°
^адаВ аеМ ы е
В о Ц р о С ьх
• Как именно работает selected Index?

0 : Свойство selectedlndex элемента управления формы начинается с 0). Вероятно, вам потребуется не только индекс,
select возвращает номер параметра, выбранного пользовате­ но и значение параметра с этим индексом (в нашем случае —
лем в раскрывающемся списке. Каждый список параметров преоб­ "doughnut"). Чтобы извлечь данное значение, сначала нужно
разуется в массив, при этом все объекты в массиве располагаются воспользоваться индексом для извлечения элемента массива; в
по порядку. Допустим, у вас имеется список выбора, включающий результате обратно вы получите объект параметра. Чтобы из­
следующие варианты: "pizza", "doughnut" и "granola влечь значение этого объекта, необходимо прибегнуть к свойству
bar". Если вы выберете «doughnut», то selectedlndex value, которое возвращает строку в атрибуте value параметра.
вернет 1 (не забывайте, что нумерация в JavaScript-MaccnBe

развлечения с магнитами
Воспользуйтесь своими псевдомагическими способностями программиста для размещения в нуж­
ной последовательности приведенных ниже табличек. Вам нужно написать псевдокод для функции
drawSquare. Данная функция принимает canvas и context и рисует в canvas один квадрат про­
извольного размера. Проверьте свои ответы в конце главы, прежде чем двинетесь дальше.

Одну из табличек мы уже р а з ­


м е ст и ли в нужном месте.
function drawSquare ( c o n te x t ) {

Расположите здесь
таблички с псевдоко­
дом в нужной после­
довательности!

"lightblue" являемся ц ве­


т о м квадратов в нашем
н а рисовать квадрат, и м е ю щ и й
дизайнерском оригинал-
х, у w
позицию и ширину
] макете.

в ы ч ислить п р о и з в о л ь н у ю п о з и ц и ю У
для к в а д р а т а в н у т р и canvas задать для fillstyle значение " l i g h t b lU ie j

в ы ч ислить п р о и з в о л ь н у ю по з и ц и ю X
для к в а д р а т а в н у т р и c a n v a s

дальше ► 337
реализация квадратов

Написание функции drawSquare


Теперь, когда вы разобрались в приведеппом выше псевдокоде, давайте восполь­
зуемся тем, что вы уже зпаете, для паписапия d ra w S q u a re : Мы используем M ath.randomQ с целью
Наша функция, у которой имею т ся генерирования случайных чисел для ш и ­
два па рам ет ра — canvas и context. рины и позиции х, у квадрата. Волге
подробно об э т о м мы поговорим через
несколько мгновений...
f u n c t i o n d ra w S q u a re (c a n v a s , c o n t e x t S — Мы выбрали 4 0 как наибольшее зн а ­
Здесь нам v a r w = M a th , f l o o r (M a th , ra n d o m () чение размеров квадратов, поэт ом у
требуется ( они не будут слишком большими.
п р о и з­ Координаты х и у
У var x M a th , f l o o r (M a th , ra n d o m () * c a n v a s . w i d t h ) ;
вольная базируются на ш и -
ширина рине и высоте canvas.
и позиция \ v a r у = M a th , f l o o r (M a th , ra n d o m () c a n v a s .h e ig h t) ; Мы выбираем с л у ­
X, у для чайное число между о
квадрата. и значением ширины
c o n te x t. f i l l S t y l e = " lig h t b lu e ” Применим к квадра­ и высоты с о о т в е т ­
c o n t e x t . f i l l R e c t ( x , У, w, w) ; т а м красивую с в е т ­ ственно.
л о -си н ю ю заливку в книге «И зучаем
с помощ ью метода HTML, XHTML и CSS»
c n n T H£Lij P, UCyeM Сам квадрат fillStyle, на который имеется полезная
п °мощ ью fillRect. более прист ально глава, посвященная
взглянем чут ь позже.. работе с цветами
(если вам пот ргбу
е т с я освежить знания
Как мы реш или, какие числа будем умпожать па зпачепия, геперируем ые м данному вопросу)-
M a th , random , чтобы получить зп ачеп ия ш ирипы и позиции х, у пашего ква­
драта? В случае с ш и ри пой прямоугольпика мы вы бирали зпачепие 4 0 , так
как опо обеспечивает пеболы ной разм ер отпосительпо разм еров ca n v a s . П о­
В своем коде вы
скольку это квадрат, мы вы брали апалогичпое зпачепие для высоты. Мы так­
можете свободно
же вы брали ш ирипу и высоту ca n va s в качестве осповы для зп ачеп ий пози ­
указат ь значение,
ции х, у, чтобы паш квадрат пе выходил за грапицы c a n v a s .
отличное от 4 0!

Ширина canvas

Ширина и высота
л
Координаты X и у квадрата (не забы­
предназначены для вайте, что в с л у ­ В ы со ка
левого верхнего чае с квадратом canvas
угла квадрата. эти значения будут
одинаковыми).

J
338 глава 7
раскрываем в себе художника

Время для mecm-драйВа! В П О Twccdh rt

И так, затратив столько сил п а создапие кода,


давайте, пакопец, протестируем его. О ткрой ­
те свой TweetShirt-файл in d e x .h tm l в браузере.
Щ елкпите па кпопке Preview (П редварительны й
просм отр), после чего вы долж пы увидеть п рои з­
вольны е сипие квадраты.
Sskct background coloc: ( \'Aiw ; ’
Вот что мы видим: ^ ^
Circlcs or jqiiWCi"* I 5сцаге»МН
Отлично, все Salad Ия! а й н л ' is nr*
выглядит так,
.Pick a tweet: I
как нам нужно!

Постойте-ка, ведь если


продолжать нажимать кнопку
Preview (Предварительный про­
смотр), квадратов будет становиться
все БОЛЬШЕ. А это не то, что нам
нужно!

Qiwctcliwt * V-
С # I S>lo cs.lho s«/~ B *th,H e ad.Fir*t.W T V L... jJ ☆ | B j И -$г Л

Г^
Он прав, у нас воз­
никла небольшая
проблема. Щ елкнит е Scloct background co lo r f w »№н»|
на кнопке Preview
Circles or squares? j i: j
(Предварительный
Sclotl LCXt colon ' BLfclc
просм от р) несколько
раз подряд — и вы Fick a tweet; [ Щ

увидите нечто п о ­
добное.

дальше ► 339
корректировка кода для квадратов

Почему мы видим старые и новые квадраты,


когда нанимаем кнопку Preview?
Вообще-то получается класспый эффект... по это пе то,
что пам пужпо. Нам пеобходимо, чтобы повы е квадраты
заменяли стары е каждый раз, когда мы щ елкаем па кпопке
Preview (П редварительны й просм отр) (точпо так же пам
потребуется, чтобы п овы й твит замепял стары й).
О сповпой м омепт здесь заклю чается в том, что пужпо пом-
пить, что мы папосим пикселы в элемепте canvas. Когда
вы паж имаете кпопку Preview (П редварительны й про­
смотр), вы берете canvas и рисуете в пем квадраты. П ри
этом поверх всего, что уже им еется в canvas, просто будут
папоситься повы е пикселы!
Вы уже зпаете все пеобходимое для того, чтобы исправить
ситуацию прямо сейчас. Вот что мы сделаем:

ф Будем извлекать выбранный цвет фона из объекта "backgroundcoior".

© Будем осуществлять заливку фона canvas соответствующим цветом, используя


filistyle и filiRect каждый раз перед тем, как начать рисование квадратов.

Возьми в руку карандаш


Чтобы при каж д ом нажатии кн о п ки Preview (П редварительны й просм отр) мы
наблюдали в ca n v a s тол ько новые квадраты, потребуется залить фон c a n va s
цветом, вы бранны м пользователем в меню " b a c k g ro u n d c o io r " . Сначала реа­
лизуем ф ункцию для заливки ca n va s вы бранны м цветом. Ниже приведен код,
в котор ом вам необходим о устранить пробелы. Сверьте свои ответы с реш е­
нием д ан н ого упр аж н е н ия в конце главы, прежде чем двинетесь дальше.

fu n c t io n f illB a c k g r o u n d C o lo r ( c a n v a s , c o n t e x t ) {

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " ____
Подсказка: т о, ч т о вы no
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; черпнете из выбранного
параметра, будет строкой
v a r b g C o lo r = s e l e c t O b j . o p t i o n s [ i n d e x ] . v a l u e ;
со значением цвета, кот орую
вы сможете использовать
c o n te x t. f i l l S t y l e = _________________ ;
т о чно т а к же, как "И д Ш и е
c o n t e x t . f i l i R e c t (0 , 0 , _______________ , ________ для заливки квадратов.
, Подсказка: мы х о т и м за ли т ь ВЕСЬ
canvas соо т вет ст в ую щ и м ц в е т о м .1

340 глава 7
раскрываем в себе художника

Добавление вызова fillBackgroundColor


У вас имеется фупкция f i l lB a c k g r o u n d C o lo r , готовая к работе; теперь пам просто пужпо убедиться, что
ее вызов будет осущ ествляться из p r e v ie w H a n d le r . Ее вызов будет происходить в самом пачале, благо­
даря чему мы получим аккуратпы й чисты й ф оп, прежде чем пачпем добавлять что-либо в c a n v a s .

f u n c t i o n p r e v ie w H a n d le r () {
v a r c a n va s = d o c u m e n t. g e tE le m e n tB y ld ( " t s h i r t C a n v a s '
v a r c o n te x t = c a n v a s . g e tC o n te x t( " 2 d " ) ; Добавляем вызов fillBackgroundColor
fillBackgroundColor(canvas, context); до создания квадратов, поэт ом у
то, что было нарисовано ранее,
v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " s h a p e " ) ; окажется скры ты м под слоем з а ­
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ; ливки, и мы получим чистый фон
v a r shape = s e l e c t O b j [ i n d e x ] . v a l u e ; для рисования новых квадратов.

if (shape == " s q u a r e s " ) {


fo r ( v a r s q u a re s = 0 ; s q u a re s < 2 0 ; s q u a re s + + )
d ra w S q u a re (c a n v a s , c o n te x t);
}

Быстрый тест-драйв: убедимся, что наше новея


функция fillBackgroundColor работает...
Добавьте п овы й код в файл t w e e t s h i r t .j s, перезагру­
зите страпицу в браузере, вы берите цвет фопа, а также
Squares (Квадраты) в мепю Circles or squares? (Круги
или квадраты?), после чего пажмите кпопку Preview
(П редварительны й просм отр). Затем щ елкпите па пей
спова. И при каждом следующем щ елчке па кпопке вы
долж пы будете видеть только повы е квадраты. Теперь при каждом нажа­
тии кнопки Preview (Пред-
варительный п р о см о т р )
Ш ТУРМ мы будем видеть только
новые квадраты.
Подсчитайте количество квадратов при нескольких нажатиях
кнопки Preview (Предварительный просмотр). Наблюдалось
ли хоть раз менее 20 квадратов? Такое вполне может быть.

Почему так происходит? Что можно сделать для устранения


этой проблемы? (Вы же не хотите обманывать своих клиентов,
не давая им их честные 20 квадратов, не так ли?)

дальше ► 341
обзор свойства fill style

J a V a ^c iij4 —с в о й с т в о у в е л и ч и те л ь н ы м о п е к л °м

л > Б олее приетальпо взгляпем па свойство fillStyle, поскольку вы впервы е с пим столкпу-
лись. О по является свойством context, которое содерж ит определеппое зпачепие цвета
для того, что вы рисуете в canvas. л
£ 3йЭйем мы значение цвета.
ы сможете использовать т е же ф о р ­
Но в отличие от filiRect, fillStyle
К ак и fi'HRect^ м а т ы цвет ов, что и в CS5. У вас будет
является свойством, а не м е ­
с б о й с т б о л л f illS ty le
тодом. Поэтому мы задаем для как иТ ЛЬ30вать ™ ена,
мы управляем п о - hghtblue, либо значения вроде #ccccff
него значение , а не вызываем его. или п
средством c o n t e xt . •gb(o 173, 231). Попробуйте!
J.
^ c o n te x t.f illS t y le = " lig h tb lu e " ;
t
О б ра т ит е внимание, ч т о , в о т ­
личие о т CSS >значение необходи­
мо заклю чат ь в кавычки , если вы
не используете переменную.
Часш°
^адаВ аеМ ы е
В сЩ роСъх

Я ожидал, что мы будем задавать Почему значение цвета следует за­ Ладно, я сдаюсь. Почему мы иногда
f t
цвет фона квадратов и canvas путем ключать в кавычки, в то время как в CSS наблюдаем менее 20 квадратов?
передачи значения цвета методу filiRect. со значениями свойств так поступать не
Я не могу понять, как работает свойство нужно? 0:
\J * Позиция х, у и ширина квадратов яв-
ляются произвольными. Одни квадраты
fillStyle. Как оно влияет на то, что делает
filiRect?

0 : Отличный вопрос. В данном случае


О ! Что ж, CSS является языком, отличным могут перекрыв
от JavaScript, и не ожидает, что вы будете
использовать кавычки. Если вы не заключите со значениями соответственно 599, 199,
Квадрат так

все немного по-другому, чем вы привыкли значение цвета в кавычки, то JavaScript ре- из-за чего вы сможете увидеть только один
думать. Как вы помните, c o n t e x t пред­ шит, что имя этого цвета является перемен- его пиксел (поскольку остальная часть этого
ставляет собой объект, управляющий до­ ной, а не строкой, и попытается использовать квадрата будет лежать вне canvas). Одни
ступом к canvas. Используя fillStyle значение переменной вместо имени цвета, квадраты могут иметь ширину 1 пиксел,
и filiRect, вы сначала задаете свойство, Допустим, у вас имеется переменная а другие - даже 0 пикселов, так как метод
которое говорит элементу canvas следую­ fgColor = " b l a c k ”. Вы могли бы напи- M ath, r a n d o m может возвращать значе-
щее: «Все, что будет нарисовано в сать context.fillStyle = fgColor, ние 0. Либо вы можете сгенерировать два
тебе далее, должно иметь данный и это сработало бы, поскольку значением квадрата с абсолютно одинаковыми раз-
цвет». Таким образом, все, к чему вы ста­ f gcolor является “b l a c k ”. меРами и местоположением.
нете применять заливку цветом (например, Однако в случае с нашим приложением все
Однако c o n t e x t .fillStyle = black
с помощью filiRect) после задания свой­ ” это является произвольным, поэтому мы и
не сработает, так как black не является пе-
ства fillStyle, будет иметь данный цвет, считаем, что все в порядке. А в ином случае
ременной (если только вы не определите его
пока вы снова не измените цвет, присвоив нам, возможно, пришлось бы позаботиться
как переменную, что может внести неболь­
fillStyle другое значение цвета. о том, чтобы такого не случалось.
шую путаницу). Вы узнаете, что допустили
эту ошибку, поскольку будет сгенерирована
JavaScript-ошибка и выведено сообщение
вроде Can't find variable: black
(He могу найти переменную: black)
(но не стоит беспокоиться, так как все мы
хотя бы раз допускали эту ошибку).
342 глава 7
раскрываем в себе художника

Тем временем, возвращаясь к TweetSbirt.com...

Неплохо, а знаешь, все это


уже начинает выглядеть так,
как того и хотел наш босс.

Д ж им : Я впечатлен тем, как мало кода потребо­


валось. Только представь, если мы бы делали все
это по-старому, на сторопе сервера, то до сих
пор возились бы с нашим сервером.
Фрэнк: Похоже, нам также представилась хоро­
шая возмож ность заняться создапием кругов в
процессе дизайна; в копце копцов, ведь их ри ­
сование будет осущ ествляться точпо так ж е, как
и квадратов.
Д ж им : Согласен, а где Джуди? Опа, вероятпо,
уже знает API-интерф ейс для рисовапия кругов.
Х отя с другой стороны , для этого пам, возможпо,
потребуется лиш ь вызы вать метод f i l l C i r c l e .
г
Джим Фрэнк: М пе кажется, так и есть! Кому пужпа эта
Джуди, если у пас есть метод f i l l C i r c l e !

дальше ► 343
знакомство с контурами и дугами

бы я пи делал, п ри вы зове fillCircle в canvas пичего пе появляется.


Д жудн: Ч то ж , дай-ка я взгляпу па твой метод f i l l C i r c l e .
Ф рэн к : Ч то ты имееш ь в виду под «моим методом»? Н ет у мепя пи-
какого своего метода, я использую метод пепосредствеппо из API-
и п терф ей са Canvas.
Д жудн: В API-иптерф ейсе Canvas пет метода f i l l C i r c l e .
Ф рэн к : А я предполагал, что есть, ведь существует же метод f i l l R e c t . . .
Д жудн: Теперь ты зпаеш ь, к чему могут привести предполож ения.
Запусти-ка браузер и введи следующий адрес, по которому всегда
можпо пайти ипф орм ацию отпосительпо соответствующ его API-
и птерф ейса: h t t p : / /d e v .w 3 .o r g /h tm l5 /2 d c o n te x t/.
...Так или ипаче, рисовапие круга —пемпого более слож пы й процесс,
чем вызов лиш ь одпого метода. Тебе спачала пужпо изучить, что пред­
ставляю т собой коптуры и дуги.
Д ж н м (входя в кабинет): Джуди, а Ф рэпк рассказал тебе о паш ей п ро­
блеме с рисовапием кругов?
Ф рэн к: Да, Джим, enoughway ithway ethay irclecay* Чтобы понять смысл этой
^ фразы, рекомендуем вам вос­
пользоваться услугам и сайта
piglatin.bavetta.com.

* Enough with the circle! — «Хватит ходить по кругу!». —Примеч. перев.

344 глава 7
раскрываем в себе художника

Черчение контуров
П реж де чем п ерей ти к кругам, пеобходимо п оговорить о коп-
турах и дугах. Д авайте пачпем с коптуров и парисуем пе­
сколысо треугольпиков. Если вам потребуется парисовать
треугольпик в c a n v a s , то зпайте, что метода f i l l T r i a n g l e пе
существует. Одпако треугольпик все же можпо парисовать,
спачала пачертив его контур, которы й затем нужпо будет обве­
сти, чтобы парисовать треугольпик в c a n v a s .
Ч то все это озпачает? Донустим, вы хотите очепь аккуратпо
парисовать что-то па холсте, для чего мож ете взять карапдаш
и пабросать едва зам етпы е очертап и я нужпой вам фигуры
(будем пазы вать их коптуром). Вы п ачертите их так легопько,
что едва сможете разглядеть эти липии. Затем, когда коптур
вас устроит, вы возьмете ручку (с толщ ипой стерж пя и цветом
ч ерп ил по своему выбору) и обведете коптур, чтобы все смог­
ли увидеть ваш треугольпик (или любую другую фигуру, кото­
рую вы пачерти ли карапдаш ом).
И меппо так осущ ествляется рисовапие произвольны х фигур
с помощью л ип и й в элемепте c a n v a s . Д авайте н а р и с у е м тр е
угольпик и посмотрим, как это работает. \Сарандаш, с
которого Mbi ЬудеМ
Используем метод begmPatW, ч е р т м то к о н т у р -
чтобы сказать canvas о т о м , что
£ начинаем чертить новый контур.
c o n t e x t . b e g in P a t h ( ) ;
c o n te x t.m o v e T o (1 0 0 , 150
Здесь мы о п у ­
/ скаем кончик
Используем метод moveTo карандаша в
для перемещения «карандаша т о ч к у с к оорди-
в определенную точку в canvas. на1ЛЛами X = Ю О
М о ж е т е счит ат ь, что мы и у = 150. Это
как бы опускаем кончик каран- 5 у Э е т первая
даила в данную точку. точка контура

Метод ИпеТо черт ит конт ур начиная


с текущего местоположения ко н ч и ка к а ­
рандаша и двигаясь к новой точке в canvas.
Начертите линию
4- от начальной точки
c o n t e x t . l i n e T o (2 5 0 , 7 5 );
до этой новой т оч­

Кончик
J
карандаша находился в точке с ко ^
ки с координатами
X = 2SO, у = 15.
ординатами х = Ю О и у = IS O , от которой
мы чертим конт ур , двигая инст румент
к т о ч к е с координатами х = 2-50, у - 7 5.

дальше ► 345
как рисовать с помощью контуров

У нас имеется одна сторона треугольника,


нужно начерт ит ь еще две. Д а ва йт е снова
воспользуемся мет одом hneTo и нарисуем
вт орую сторону: .

У Начертите вт орую
c o n t e x t . l in e T o (1 2 5 , 30) л и н и ю j двигая к а ­
рандаш от преды­
Ч ерт им линию от т екущ ей позиции дущей точки к н о ­
кончика карандаша ( z s o , 7 s), двигая его вой с координатами
к новой точке с координатами х = i Z s К = 125, у = за
У ~ 30. 8 р е зу л ь т а т е у нас получит ся
вторая сторона треугольника.

Мы почти достигли цели! Нам осталось лишь


начерт ит ь еще одну л и н и ю , чтобы заверш ит ь
А вот и наш т р е ­
треугольник. Д л я этого просто замкнем кон-
угольник! Но не забы­
т у р , воспользовавшись м ет одом closePath.
ва й т е, что это пока
лишь к о н т у р , п о ­
c o n t e x t . c lo s e P a t h ( ) ; эт о м у он будет все
еще не виден пользо­
вателям.
Метод closePath соединяет начальную точку
контура (Ю О , IS O ) с конечной (1 Z S , 30).

Urnak, у нас е с ть контур! U что теперь?


пражненне Теперь вы будете использовать этот контур для рисования линий и заливки своей
фигуры цветом, конечно же! Создайте простую НТМ1_5-страницу с элементом canvas
и наберите весь приводившийся чуть ранее код. Затем проведите тестирование.

c o n te x t.b e g in P a th ( ) ;
c o n te x t.m o v e T o (1 0 0 , 1 5 0 ); Вот код, приводившийся ранее.
c o n t e x t . l i n e T o (2 5 0 , 7 5 );
c o n t e x t . l i n e T o (125 , 3 0 ) ;
c o n t e x t . c lo s e P a t h ( ) ;

c o n t e x t . l in e W id t h = 5 ;

c o n t e x t . s t r o k e () ;

c o n te x t. f i l l S t y l e = "re d ";

c o n t e x t . f i l l () ;
А здесь приведен новый код. О п и ш и т е , что делает каждая
из этик ст р ок . Загрузит е страницу. Ваши ответы оказа-
лись правильными? Решение упражнения - в конце главы.

346 глава 7
раскрываем в себе художника

Просто, чтобы быть в курсе: я ду­


мала, мы будем пытаться нарисовать
круги. Какое отношение все эти конту­
ры имеют к созданию кругов?

Чтобы нарисовать круг, сначала нужно начертить


его контур.
Сейчас мы собираемся показать вам, как п ачерти ть коп-
тур круга. Научивш ись делать это, вы сможете создавать
любые круги, какие только захотите.
Н емпого дополпительпой ипф орм ац ии для вас. Вы уже
зпаете, как пачать черти ть коптур, пе так ли? Это, как
вы видели рапее, делается с помощью следующего кода:

c o n te x t.b e g in P a th ();

Н о мы пока пе говорили вам о том, что в объекте c o n te x t


имеется еще одип метод — arc:

c o n t e x t . a r c (1 5 0 , 1 50, 50, 0, 2 * M a th . P I , tru e ); ^

И что же on делает? Н а следующей страпице мы разъяс- \


пим вам детали. Н о, как вы сами могли догадаться, дап- I
пы й метод п озволяет черти ть коптур вдоль окружпости. J
Из уроков геометрии
вы наверняка пом нит е,
ч т о длина окружности
равна ZnR? Просто
ненадолго отложите
в подсознание данный
ню анс-

дальше ► 347
взгляд на метод arc

Подробное исследование метода arc


Взгляпем па метод a rc и изучим его парам етры .
context.arc(х, у , radius, startAngle, endAngle, direction)

Суть метода a rc заклю чается в том, что оп позволяет определять, как будет
ч ерти ться требуемый коптур вдоль окружпости. П осмотрим , как имеппо каж­
ды й из его парам етров содействует этому.

Х ,у П арам етры х и у определяю т,


где будет паходиться цептр
круга в вашем canvas.

Это позиция X, у центра


вашего круга.
Canvas

c o n te x t. a r c (х , у , r a d iu s ,

radius Д аппы й парам етр используется


для определепия 1 / 2 ш ирипы круга.

348 глава 7
раскрываем в себе художника

d ire c tio n П озволяет определять, как будет черти ться дуга:


в паправлепии против часовой стрелки или же
по часовой стрелке. Если зпачепием direction
является true, то рисовапие будет происходить
против часовой стрелки; если же false —по ча­
совой стрелке.

Если значением direction


tru e является true, дуга будет
черт ит ься прот и час
вой ст релки, а если false -
Iпо часовой стрелке.

false

s ta r tA n g le , e n d A n g le , d ir e c tio n )
Ниже приведен важный момент!
startAngle, Если зпачепием d irection Н е п р о п у скай те это. Углы могут изм еряться в от-
endAngle является true, дуга будет рицательпы х величипах (в паправлепии против
черти ться п ротив часовой часовой стрелки от оси X) либо в полож итель-
стрелки, ас* если j_*
false — пы х величипах (по часовой стрелке от оси X).
Конечная точка по часовой стрелке Это пе то же самое, что парам етр direction в
нашей дуги — случае с дугой! (Вы убедитесь в этом па следую­
щ ей страпице.)
Д у га , к о - Угол, от меряем ый в направлении
т о р у ю мы Ось X прот ив часовой ст релки от оси X,
это
х о т и м на Начальный угол будет и м ет ь о т рицат ельную
чер т и т ь между осью Х и н а - величину (н а при м ер, -35°).
угол
чальнои мочкой дуги
Конечный угол -
это угол между Начальная точка
осью X и конечной нашей дуги
точкой дуги.

Угол; от меряем ый в направле­


нии по часовой ст релке от оси X,
будет и м ет ь положительную
величину (например, 45°).

дальше ► 349
практикуемся в использовании метода arc

Небольшой пример использования метода arc


Чт о пам сейчас нужпо, так это хорош ий прим ер. Донустим, вы хотите п ачерти ть дугу па круге,

цеп тр которого им еет позицию х = 1 0 0 , у = 1 0 0 . П ри этом вам нужпо, чтобы ш ирипа круга
была 150 пикселов (то есть оп имел радиус 75 пикселов). А дуга, которую вы хотите пачертить,
будет составлять лиш ь 1 / 4 круга.
Ч ерт им дугу в направлении
прот ив часовой с т р ел к и .

’Это наила дуга.

Центр: х = Ю О ,
Начальный угол равен <9 °, а конеч-
у = гоо
Г ный составляет 270°.

К V— Следует о т м е т и т ь ,
что мы от м ер яем конеч­
ный угол в направлении
по часовой стрелке от
Н я м -н я м j радиус равен оси ™ э^ о м у величина
яблочный пирог! 7 5 пикселам. конечного угла будет п о -
ложительной.

Н апиш ем вызов метода arc, которы й будет рисовать пашу дугу:

Н ачпем с позиции х, у, которую им еет цеп тр круга: 100, 100.


context.arc (100 , 100, __, __ , ______________________ , );

Далее пам потребуется радиус круга, равп ы й 75 пикселам.

context.arc (100 , 100, 75, __, ______________________ , );

А что с паш ими пачальпы м и копечпы м углами? Н ачальпы й угол будет равеп
0° отпосительпо оси X. К опечпы й угол —это угол между осью X и копечпой
точкой паш ей дуги. Поскольку паша дуга является 90-градуспой, копечпы й К э т о й функции
угол будет равеп 270° (90° + 270° = 360°) (если бы мы изм еряли его в отрица- мы вернемся
тельпы х величипах, то есть в паправлепии против часовой стрелки, то ко- через несколько
п ечпы й угол был бы в итоге равеп -90°). ----------------------- мгновений. Она
просто преоб-
context, arc (100, 100, 75, 0, degree sToRadians (270) , ____ ) ; р азует градусы
тт ^ » (которые нам

О
Н акопец, поскольку дуга будет черти ться в паправлепии против часовой л ^ ^
стрелки, указываем зпачепие true. пРи Ра
дианы (которые
предпочит ает
context.arc (100 , 100, 75, 0, degr ее sToRadians (270) , true); context).

350 глава 7
раскрываем в себе художника

Классный разворот
Я говорю «градус», вы говорите «радиан» на 360 градусов! То есть
я хотел сказать, классный
Все мы каждый депь говорим об углах, связаппы х с
разворот на 2п радиан!
кругами: «Класспый разворот па 360 градусов», или
«Я паправился по этому нути и развернулся па целых
180 градусов», или... ну, в общем, вы попяли. Одпако
проблем а заклю чается в том, что мы думаем в граду­
сах, a c o n t e x t в случае с c a n va s —в радиапах. у __ Радиан -
еще одна единица и з м е ­
Сейчас мы могли бы сказать вам, что: рения углов. Один радиан
360 г р а д у с о в = 2 P i р а д и а н равен 120/Ъ,14-15Ч2<Ь5...
( то есть числу IS O , р а з ­
и после этого вы были бы готовы посчитать в уме
деленному на п).
градусы в радиапах в случае необходимости. Если по
какой-то причи пе вы пе захотели бы делать это в уме,
то зпайте, что существует удобпая фупкция, которая И с п о л ь з у й ^ э т у функцию
вы полпит дапную работу за вас: когда захот ит е дум ат ь
f u n c t i o n d e g re e s T o R a d ia n s (d e g re e s ) { в градусах, но будете о п е ­
рировать радианами при
re tu rn (d e g re e s * M a th . P I ) / 1 8 0;
рисовании дуги.

^ 1
Как пом н ит е, с этой ф у н к -
t Чтобы перевести
На с. 3 4 7 вы видели, как мы и сп о л ь ­
цией м ы м и м о л е т о м с т а л - г р а д у сы в р а д и а н ы ,
зовали 2 * Matk.PI для определения
кивались в гла ве, посвящ енной нуж но у м н о ж и т ь
конечного угла дуги на круге. Бы могли
A P I - и н т е р ф е й с у G eolocation. их на п и р а з д е л и т ь
бы п о с т у п и т ь т ак же... либо прост о
на 1 2 0 .
использовать degreesToRadians(3(,0).
(ТА Н Ь браум ром ---------------
I I н т е ] ^ р е т и р у й т е п о в е д е н н ы й н и ж е в ы зо в м е т о д а аГс и н а п и ш и т е все
со ощ В ещ ещ ^^Щ и е значения, к о т о р ы е б у д у т х а р а т с т е ^ ^ о В а т ь круг,
а т а к ж е и з о б р а з и т е ДУ^)» со зд а в а ем у ю в р е з у л ь т а т а э т ° Г о ВыЗоВа.

context.arc(100, 100, 75, degreesToRadians(270), 0, true);

Напишите все параметры


данного круга и нарисуйте дугу,
которая будет создана в резуль Подсказка: что останется от п и ­
т а т е вызова метода arc. рога, если съесть э т о т кусок?

дальше ► 351
/ еэеи г ZSZ

Ответ: Рисование угла осуществляется с использованием начального угла 0° и конечного


угла 360°. Неважно, какое направление вы выберете, поскольку будете рисовать полный круг.

^эинэьене 010 ии 1Э81/\1И бэмиэс^ю


иоаоэеь ои иии ишэс1±о иоаоэеь aniodu ^ le d e g is a н а 0HH0uaedueH эоме>]

ojOHLfou
bHHeaoond but/ я±еаоея1_гоиэи eietfAg н а н ш Л шяньэном и шяняиеьен иоме>]

W d M fD
‘S ? J V Y ) b S M V J l'p Y)dY\V)
H6&6J16VN
-у н б ф v gvbfivv д owie
Y)VVV9Q сэ ж >iVW I

OHhOWI 9jV JJ2M V jy?

YlYlh>iH(ncf? 1 X 9 1 V I 0 V Y)

s v a v iv v W d v g z d d jj
{
.' (q.xsq.uoo ;spaupo) эхоттэм^тр

онжВн д а в и CHfidov*
(+ + sax o iio .'OS > s s p i i o .'0 = 2 0 x 0 1 1 0 лгл) joj

-m ) nrihylHFi(r } („ se p iT O y == scteqs) j t ss x s {
(oHPVnowovI 0 go?fid>t Ot w ? {
\evndvH k»w ' ( i w v d e m 0 .' (q.xsq.uoo ;spaupo) si^nbsM^ip
sw nbs ™ v 4 " * ^ (++saienbs .'os > saienbs .'0 = saienbs л г л ) joj
vvdpwg « v w » 9° w ° ' A"У*
■<:,cwvdevg* v)VY) Yi?fidyI) } („ sei^ n b su == scteqs) j t
ssijvnbs ло s« jw p 9

/s n j B A * [хэрит] Cqo^-osx^s = ;п?л


.L o w v o v . nv 'огош
.'x s p u ip s q -o s x ^ s * C qo^-osx^s = х э р и т ;п?л
L to H * fie** наииш
.' ( 41sd ^ 4s 41) p iA g q .u s u is x a is 6 *^иэш поор = C q o io s x s s ;п?л
_ He e « »M HH»V

i (q.x©q.uoo ' s b a u b o ) л охо эр и п о х б эр -ея х Т Т З 1


• ( iiP 2 ii) ^-Xsq.u°oq.s5 * s p a o t o = q.xsq.uoo jctsa

.' ( 11s b a u ? o ^ i t 4 s ^ 11) p iA g q .u s u is x a is 6 *^иэш поор = s ? a u ? o a


jcts

} () згэ-[рит?да-этлэz d uopounj

:tfoH Ш Ч Я О Ы э ж и ц и1чииэ^эаис1и эдегадоН и s С •q.;rT4sq.3aM.q. ш г е ф

ОШ ЙЯыАф Я tfOH ИИ^ПСЯАЯХЭХЭЯХООЭ wn&zyotf И1ГИ H jA d ^ j) £ S 9 J ^ n b s


j o s a p j i ^ ошэш я (H jA d ^ j) s a p j i ^ w d y v in ч 1гэх^яоеч 1гоы о хь ‘q x m ra lta d iio к э х э ^ ^ х о п ш геь ш ю ‘q j^ a o D H d
- г а х и r i g o ! ^ *(шмш,ш1Ь^яя э э^ьХ 1гэ я и эгея) HOjAdn xiq n q iro aeH o d n о& qj/etfeo3 imhxox iqp^ *эхо;гтзмл?;гр
— ошйяыАф сяАяоы q in r a g o tf и :ц щ £ р э м х я KDqxXHdaa ^ d o n ‘ш М я q j^ ao D H d явя ‘эхэш ге и а в й ю я ‘q d a n a x

gozAd>| впнедоэй kv6 е б о ^ л ц ^ э э м ^ ошнеэпиен >j imfdetoedQsog

эогЛсй/ эпнэиэедод
раскрываем в себе художника

Пишем функцию drawCircle...


Подобно т о м у как мы п о с т у -
Теперь паппш ем фупкцию d ra w C ircle. Н е забы вайте, что здесь пам лали в случае с квадратами, мы
потребуется парисовать лиш ь одип произвольны й круг. О стальпой указываем 4(9 в качестве м а к ­
код обеспечит вызов даппой фупкции 2 0 раз. симальной величины радиуса,
чтобы наши круги не получились
f u n c t i o n d r a w C ir c le ( c a n v a s , c o n t e x t ) { слишком большими.
v a r r a d iu s = M a th . f l o o r ( M a t h . ra n d o m () * 4 0 ); О п я т ь -т а к и , координаты
v a r x = M a t h . f lo o r ( M a t h . r a n d o m () * c a n v a s .w id th ) х и у центра круга базиру­
ю тся на ширине и высоте
v a r у = M a t h . f lo o r ( M a t h . r a n d o m () * c a n v a s . h e ig h t)'J canvas. Мы выбираем п р о ­
извольные числа между О
и шириной и высотой с о о т ­
c o n t e x t . b e g in P a t h ( ) ; ветственно.
c o n te x t. a rc (x , y, r a d iu s , 0, d e g re e s T o R a d ia n s (360) tru e )

Используем конечный угол 3 6 <9 °


c o n te x t. f i l l S t y l e = " lig h tb lu e " ;
для создания полного круга.
c o n te x t. f i l l () ; Рисуем в направлении прот ив
Снова используем "UgWtblue"
в качестве значения для часовой с т р е л к и , однако в случае
fillStyle и заливаем контур с кругом неважно, какое н а пра в­
ление мы выбрали.
с помощ ью context. fill().

... и проводим тест-д р ай в !


Н аберите приведеппы й рапее код (и пе забудьте добавить фупкцию d e g re e s T o R a d ia n s ), сохрапи-
те его, а затем загрузите в своем браузере. Вот что мы видим (поскольку это произвольны е круги,
ваши будут выглядеть пемпого по-другому):

дальше ► 353
b iB
П е г е г

ЦебоЛьШой ле^е^ыБ на леченье

J f \ ^щраниДьх, п° Кощо^ыМ Мы с ВаМи


т°ЛьК« Чзцо проделали путь, быЛи ДоВоДь—
Но увлекательными. ]Je знаем, как Вы , а Мы
хоцшм печенья. ](ак насчет небольшого пере­
рыва? Д о не думайте» чт ° Мы не поручим Вам
нечщ о и н тересн ое, п о к а Вы б у д е т е ег° е с т ь
(на следующей странице справа Вас ждет
Задание).

|а к Чщо отки ньтесь на спинку стула, сде­


лайте небольшой перерыв, и «вгрызитесь»
В Задание пока ВаШ М°ЗГ и Желуд°К будут
ненадолго заняты к<>е-чем другим, ^атем
Возвращайтесь, и Мы ЗаК°нЧиМ ^weet^iiTt—К°д!

354 глава 7
раскрываем в себе художника

= гоо> Я.so
радиус - 2-5 *> У = 4 0 0 , 2SO
Справа изображено улыбающееся лицо (или печенье с кусочками шоко­
лада в форме улыбающегося лица, если вам так больше нравится). При­
веденный внизу код для рисования улыбающегося лица почти завершен;
нам нужна ваша помощь, чтобы устранить имеющиеся в нем пробелы.
После работы, проделанной в этой главе, у вас есть все необходимое для длийа
того, чтобы справиться с данной задачей. Закончив, вы сможете сверить носа = SO]
свои ответы с решением этого упражнения в конце главы.
угол)- 2.0°

у = з о о , 3SO
радиус = 7 5
f u n c t i o n d ra w S m ile y F a c e () {
v a r ca n va s = d o c u m e n t. g e tE le m e n tB y ld ( " s m i l e y " ) Bom что нам требуемся. По ходу дела
v a r c o n te x t = c a n v a s . g e tC o n te x t( " 2 d " ) ; у вас может возникнуть желание испечь
настоящее печенье с кусочками ш окола­
да в ф орме улыбающейся рожицы...
c o n t e x t . b e g i n P a t h () ;
c o n t e x t . a r c (3 0 0 , 300, 200, 0, d e g re e s T o R a d ia n s (3 6 0 ) , tru e К руг лица. Здесь мы
c o n te x t. f i l l S t y l e = " # ffffc c ";
уже уст ранили за
вас один из пробелов.
c o n t e x t . f ill();
О б рат ит е enuManuej
c o n t e x t . s t r o k e () ; что мы применили
к кругу заливку жел­
c o n t e x t . b e g i n P a t h () ;
т ы м цветом.
c o n t e x t . a r c (_____, 25, tr u e ) Левый глаз
c o n t e x t . s t r o k e () ;

c o n t e x t . b e g i n P a t h () ;
c o n t e x t . a r c ( 4 0 0 , _____, Правый глаз
c o n te x t. s tr o k e () ;

c o n t e x t . b e g i n P a t h () ;
c o n t e x t . _________(____ , Нос
c o n t e x t . _________(____ ,
c o n t e x t . __________ () ;
Рот. Самый мудреный
аспект!
c o n t e x t . b e g i n P a t h () ;
c o n te x t. (3 0 0 , 350, _, d e g re e s T o R a d ia n s (_ ) , d e g re e s T o R a d ia n s (_
c o n t e x t . s t r o k e () ;

дальше ► 355
добавление jsonp для твиттера

Говоря о вкусностях, помните


Добро побаловать обратно... JSONP-код, который мы готови­
ли в главе 6? Пора достать его
Итак, вы вернулись отдохнувшими. Мы с вами находим­ из «духовки».
ся на заключительном этапе. Нам осталось лишь обеспе­
чить отображение твитов и прочего текста при предвари­
тельном просмотре футболки в c a n v a s .
Теперь, чтобы добавить в c a n v a s твит, нам сначала нуж­
но извлечь последние твиты пользователя, из которых
можно будет выбрать желаемый, для чего воспользуем­
ся JSONP. Из главы 6 вам уже известно, как это делается
(если требуется освежить свои знания, вернитесь к гла­
ве 6). Вот что нам нужно будет сделать:

flo6aBHTb<script>BHH)KHK)K)4acTb4>aimatweetshirt.
html для вызова API-интерфейса JSONP Twitter. Мы бу­
дем запрашивать самые последние статусные обновле­
ния определенного пользователя.

Реализовать функцию обратного вызова для извлечения


твитов, которые Твиттер будет присылать в ответ. Имя
этой функции обратного вызова мы используем в URL-
адресе для <script> во время шага 1.

Наш HTML-ф айл для T w e e ts h ir t


Представьте, что здесь находится ваш элем ент <head>> а здесь —
£ ваш элем ент <form> (мы просто решили сэкономить место).
J S O N P -вызов; он работ ает п у т е м извлечения J S O N -данных,
получаемых посредством обращения к URL-адресу Т в и т т е р а ,
с последующей передачей этих J S O N -данных функции обратного
<body>
вызова (кот орую мы определим через несколько мгновений).
< fo rm > Вызов A P I-инт ерф ейса Twitter. Можете зам енит ь это
Мы запрашиваем временную шкалу своим именем пользова-
пользоват еля>что даст нам п о - т еля или другим , если
< /fo r m > следние статусы. ^ | пожелаете.
< s c r i p t s r c = " h t t p : / / t w i t t e r . c o m / s t a t u s e s / u s e r _ t im e lin e / w ic k e d s m a r t ly . j s o n ?
c a llb a c k = u p d a te T w e e ts ">

< /s c r ip t>

< /b o d y > Функция обратного вызова, которой Наберите все это


< / h tm l>
будут передаваться JSON -данные. в одной строке в своем
т екст овом файле ( у м е ­
Здесь много чего происходит. Если вы не все поним ает е, снова с т и т ь все в одну строку
взглянит е, как работ ает JSONP, обратившись к главе 6 . в книге не получилось).

356 глава 7
раскрываем в себе художника

извлечение твитов
Мы уже п о к о п ч и л и со слож пой работой, заключавш ейся в извлече­
нии твитов из Твиттера. Теперь пеобходимо добавить их в элем епт
<select>, используемый для вы бора твитов, в элемепте <f orm> па­
ш ей страпицы. Еще раз повторим: когда происходит вызов фупк­ Ответ Твиттера пред­
ции обратпого вы зова (в паш ем случае — update Tweets), Твиттер ставляет содой массив
передает ей ответ, содерж ащ ий твиты в ф орм ате JSON. твитов. Каждый твит
включает в себя массу
О тредактируйте файл tweetshirt.j s и добавьте фупкцию
данных; мы будем использо­
update Tweets в его пижпюю часть:
вать текст т вит а.

функция обратного вызова


Данной функции передается
от вет , содержащий твиты
с временной шкалы пользова­
теля в виде массива твитов. Извлекаем ссылку на
tweetsSelection из <form>.

function updateTweets(tweets) {
var tweetsSelection = document.getElementByld("tweets'
8 случае с каждым т вит ом в массиве
твитов мы сделаем следующее.
for (var i = 0; i < t weets.length; i++) {
— ■* Извлекаем твит из массива.
tweet = tweets[i]; ^
var option = document.createElement("option’ ) ; ^ — Создаем новый элемент option.
option.text = tweet.text; < ------------- Задаем
для его te x t
option.value = t w eet.t e x t .replace ("\"", "'") значение tweet.

•А также задаем для его value


tweetsSelection.options.add(option) аналогичное значение, но т оль­
ко немного обрабатываем при
этом ст р0Ку с целью замены
Затем берем двойных кавычек одинарными
tweetsSelection.selectedlndex новый элемент (чтобы избежать проблем ,
option и до­
ч бавляем его в Т т % ц * С* *°РматиР°вания
Наконец мы заботимся tweetsSelection
о т о м j что первым будет в <form>.
идти выбранный т вит , п у ­
тем присваивания свойству После того как мы продела­
selectedlndex элемента <select'> ем это с каждым т вит ом,
значения О (номер перво­ у нас получится элемент
го элемента o ptio n , который <select>j содержащий option
в нем содержится). для каждого твита.

дальше ► 357
тестирование tweetshirt с твиттером

TwectShlrt
Tecm-драйб TweetShirt L t j ^ r o ■'■»:ca Kxo-Bcn/HTHLS^c-jhin^indcxJhD С ] (QlS£*4£_J_ _ g;^

П роведем пебольш ой тест-драйв. Убедитесь, что вы


добавили весь соответствующ ий код в tweetshirt. j s и
index .html. Также удостоверьтесь, что вы используете
имя пользователя Твиттера, у которого имею тся све­
жие твиты , в вашем URL-адресе script src (благодаря
чему вы сможете быть уверепы в том, что обязательпо Selectbackgroundcolor:{ ;
увидите твиты !). Загрузите страпицу и щ елкпите па
Circlcs or squares? Гммы*» (;•{
элемепте для вы бора твитов. Вот что мы видим:
Select Lexl a iliir:

М е н ю выбора твитов J^lck a tweeu j


с НАСТОЯЩИМИ Если вы поклонник Твиттера, носите футболки TweeiShirl
(jPrnviw)
т $итами. Класс.

^ ( Ребята, это здорово. Мы можем Л


рисовать квадраты и круги, а Джим по-
заботился об извлечении твитов из Твиттера! )
А что дальше?

Планшетный к о м п ь ю ­
т ер Фрэнка

Д ж им : Мы почти достигли цели. Н еобходимо разобрать­


ся с текстом, которы й будет отображаться. У пас имею т­
ся два сообщ ения: Я повелся на этот твит... и ...а в
результате получил эту паршивую м а й к у !, а также твит,
которы й пользователь вы берет для отображ епия. Сей­
час нам нужно понять, как обеспечить их отображ епие,
не говоря уже о прим енении стилизации к тексту.
Ф рэнк: Полагаю, что мы можем вставить текст в canvas,
а затем прим енить к нему CSS?
Д ж о: Не думаю, что все будет происходить имеппо так.
Как известно, canvas является областью для рисовапия,
и я не думаю, что мы сможем поместить в пего текст и
стилизовать его; пам придется рисовать текст в canvas.
Д ж пм : Недавпо я получил хорош и й урок и па этот раз
павел справки, какой API-иптерф ейс предпазпачеп для
работы с текстом.
Д ж о: Это хорош о, по сам я пока еще пе смотрел что
к чему; как оп работает?

358 глава 7
раскрываем в себе художника

Джпм: Помпиш ь метод arc? С его помощью пам и придется рисовать весь текст.
Фрэпк: Ты что, шутишь? Похоже, теп ерь мы провозим ся весь уикепд.
Джпм: Как я тебя подловил! Если серьезпо, то существует метод fillText, которы й п рипим ает текст
для рисовапия в canvas паряду с п озиц и ей х, у, где оп будет рисоваться.
Джо: Звучит довольпо просто. А как пасчет разли чи й в стиле? Н асколько я помпю оригипал-макет,
ш ри ф т текста твита в пем был курсивпый, а остальпого текста —полужирпый.
Джпм: Н ам нужпо еще пемпого покопаться, поскольку существуют разпообразпы е методы для за-
дапия вы равпивапия, ш риф тов и стилей, по я пе очепь хорош о зпаю, как их использовать.
Фрэпк: Если подумать, то я, возможпо, мог бы помочь, по как это сделать без CSS?
Джпм: П рости, по как сказал Джо, это API-иптерф ейс для рисовапия в canvas, и оп пе использует
HTM L или CSS.
Джо: Тогда давайте остаповимся па даппом API-иптерфейсе, после чего можем попробовать па-
рисовать текст «Я повелся па этот твит...» в canvas. Фрэпк, присоединяйся к пам, все пе так уж и
плохо, и я увереп, что пам пригодятся твои зпапия в области ш риф тов, стилей и тому подобпого.
Фрэнк: К онечно, я к вашим услугам!

Нам необходимо нарисовать т е к с т «Я повелся на э т о т т вит ...»


над реальным т в и т о м пользователя в левом верхнем у гл у

Ч Я -------------------------------------------
повелся на этот твит...
Тбит алы будем рисо А за т е м мы нари су­
‘ ват* зЫсъ, посередине. ем «...а в р е зу л ь т а т е
получил э т у паршивую
м айку!» справа внизу,
под т е кс т о м твита.
...ав результате получил эту паршивую майку!

Мы извлечем выбранное
Select background color. (wbtej
значение цвета переднего
Circles o r Squares? fg'Vdes] t ) плана для использования его
в качестве цвета текста.
Select text c o lo r

Peek a tw e e t: [@stArbuzzceo you're о^a^shiirt #tweetsi


3 м еню выбора т вит о в у нас
tp rew e w j уже и м ею т ся варианты.

дальш е ► 359
обсуждение структуры и представления

Что меня смущает относительно рисова­


ния текста в canvas, так это то, что мы всегда
акцентировали внимание на отделении содер­
жимого от представления. А в случае с canvas
похоже, что они являются одним и тем же. Я хочу
сказать, что они не кажутся отдельными.

Это точно подмечено.


Д авайте разберемся, почему так обстоит дело. Как вы помпи-
те, ca n v a s является инструментом, позволяю щ им представлять
графику в браузере. Все в ca n v a s считается представлепием,
а не содержимым. Таким образом, несм отря на то что обы ч­
но вы рассматриваете текст — и, конечно же, твиты — как со­
держ имое, в данном случае вам следует рассматривать его как
представление. О н является частью дизайна. Подобпо худож­
нику, которы й использует художественные заглавные буквы как
часть своей картины , вы используете твиты как часть дизайпа
футболки.
Одна из главных п ричин того, что отделение представлепия
и содержимого —хорош ая идея, заклю чается в том, что браузер
может с умом подходить к представлению содержимого в раз­
личны х ситуациях: наприм ер, он мож ет представлять статью с
новостного веб-сайта одним образом на большом экрапе и Д р у ­
гим —на экране телеф она.
В случае дизайпа футболки пам пеобходимо, чтобы содерж и­
мое c a n v a s больше походило п а изображ епие: опо долж по ото­
браж аться одипаково пезависимо от того, каким образом вы
будете его просматривать.
Итак, давайте парисуем текст в c a n v a s и запустим паш стартап!

360 глава 7
раскрываем в себе художника

развлечения с магнитами
Пришло время вашего первого эксперимента с текстом в ca n v a s . Ниже приведен начатый нами код для
метода d ra w T e x t, который мы будем вызывать, чтобы нарисовать весь текст в c a n v a s для предвари­
тельного просмотра. Посмотрите, сможете ли вы завершить данный код, чтобы нарисовать Я п о в е л ся
на э т о т т в и т . . . и . . . а в р е з у л ь т а т е п о л учи л э т у паршивую м а й к у ! в c a n v a s , а рисование
реального твита пользователя мы оставим на потом. Проверьте свои ответы в конце главы, прежде чем
идти дальше.

f u n c t i o n d r a w T e x t( c a n v a s , c o n t e x t ) {

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " _____________________ " ) ;

v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;

v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

c o n t e x t . _________________= f g C o lo r ;

c o n t e x t . _____________ = " b o ld le m s a n s - s e r i f " ; Подсказка: это


позиция х, у для
c o n t e x t . _____________ =" l e f t " ; текста «Я повелся
на этот твит...».
c o n te x t. ( 20 , 40)

Подсказка: мы будем исполь­


зовать курсивный шрифт
// И звлечь нужный ва р и а н т и з меню выбора т в и т о в с засечками для т вит а,
Ha данный // Н а р исо ва ть т в и т но нам необходимо, чтобы
момент этот текст имел полуж ир­
размещаем ный шрифт без засечек.
КОММента- c o n te x t, fo n t Подсказка: мы хот им п о ­
puu т а м j
местить текст в правый
где будет c o n te x t.
нижний угол.
распола­
c o n te x t. (" ...а в р е з у л ь т а т е п о л учи л э т у паршивую м а й к у ! " ,
гаться код
для рисова­
ния текста
твита. }
У
Мы хот им нарисовать данный текст в 2 0 пикселах
от правой стороны canvas и в 4 0 пикселах от основания
canvas, чтобы он уравновешивал верхнюю ст року текста.

J Q
canvas.height-40

"Я повелся на этот


твит..."

дальше ► 361
более пристальный взгляд на текст в canvas

/> К ° д под увел и чител ьны м сш екл^м

Теперь, когда вам представилась возможность нарисовать свой первый текст в ca n va s,


пора более пристально взглянуть на методы и свойства для работы с текстом, доступные
в API-интерфейсе Canvas. Как вы поняли из предыдущего задания, это довольно низкоу­
ровневый API-интерфейс: вам приходится сообщать c o n te x t, какой текст рисовать, какую
позицию выбирать и какой шрифт использовать.

В данной секции мы детально рассмотрим такие свойства, как t e x t A i i g n , f o n t ,


t e x t B a s e iin e , а также методы f i i i T e x t и s tr o k e T e x t , благодаря чему вы превра­
титесь В эксперта ПО тексту В ca n va s!

textj^ign
Свойство t e x t A i i g n определяет, где будет находиться
якорная точка для текста. Значением по умолчанию явля­
ется " s t a r t " .
c o n te x t. t e x t A iig n = " le f t" ;

Возможные значения данного свойства: " s t a r t " , " e n d " ,


" l e f t " , " r i g h t " и " c e n t e r " . В арианты " s t a r t " и "e n d "
означаю т то же самое, что и слева и справа в языках, где Вырав­ Вырав­ Вырав­
все пиш ется и читается слева направо (например, англий­ нивание нивание нивание
ский). В язы ках же, где буквы располагаю тся справа на­ по левому по центру по право­
лево (например, и ври т), под значениям и " s t a r t " и "e n d " краю м у краю
будет пониматься соответственно справа и слева.

filfjext u s1joW]ext
Текст с заливкой
Как и в случае с прямоугольниками, мы можем обводить
текст и прим енять к нему заливку. Мы указываем текст
для рисования, позицию х, у и опциональны й парам етр
Dog1 ^
m a x wi d t h , что обеспечит масш табирование текста, если
он окажется ш ире, чем значение ma xw i d t h. m

context.fiiiT ext("D og", 1 00, 100, 200); Текст с обводкой

context.strokeT ext("C at", 100, 15 0, 200);

Если текст окажется шире ZOO п и к ­


селов, он автоматически будет подо­
гнан посредством масштабирования.

362 глава 7
раскрываем в себе художника

follt
П ри задании значений для свойства fo n t вы мож ете прим енять тот же
формат, что и в CSS, - это удобно. Если вы будете задавать все значения
для данного свойства, то среди них будут следующие: стиль ш риф та, его
толщ ина, разм ер, семейство —именно в таком порядке.

c o n t e x t . f o n t = "2em L u c id a G ra n d e ";

c o n t e x t . f i l l T e x t ( " T e a " , 100, 1 0 0 );


c o n te x t.fo n t = " i t a l i c b o ld 1 .5 e m T im e s , s e r if" ;

c o n te x t. f i l l T e x t (" C o ffe e " , 100, 1 5 0 );

В специф икации рекомендуется использовать только векторны е


ш риф ты (растровы е ш риф ты не очень хорош о отображ аю тся).

textj}as e W

Свойство t e x t B a s e li n e устанавливает точки вы равнивания в случае со ш риф том


и определяет линию располож ения ваших букв. Ч тобы увидеть, как эта лин и я
влияет на текст, попробуйте начертить ее в той же точке х, у, где вы рисовали
текст.
^ alphabetic
c o n te x t.b e g in P a th ( ) ; Alphabet
c o n te x t.m o v e T o ( 100, 100);
c o n t e x t . l i n e T o (2 5 0 , 1 0 0 ); A lp h a b e t b o tto m

c o n t e x t . s t r o k e () A lp h a b e t ^ m iddle
c o n t e x t . t e x t B a s e li n e = " m id d le " ; ' -
c o n t e x t .f illT e x t ( " A lp h a b e t" , 100, 100); Alphabet ^ top
Возможные значения данного свойства: " t o p " , " h a n g in g " , " m i d d le " , " a l p h a b e t i c " ,
" id e o g r a p h ic " и " b o tto m " . Значением по умолчанию является " a lp h a b e t ic " . П о­
экспериментируйте с разны ми значениями, чтобы выяснить, какое именно из
них вам требуется (а также загляните в специф икацию для получения дополни­
тельных сведений).

оальше ► 363
рисование текста

Применение drawText
Теперь, когда вы узпали еще об одпом API-иптерф ейсе, паберите код, пад которы м вы работали в п р е­
дыдущем упраж пепии «Развлечепия с магпитами». Вот как оп будет выглядеть после того, как таблички
с кодом окажутся па своих местах:
fu n c t io n d r a w T e x t( c a n v a s , c o n t e x t ) {
v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " f o r e g r o u n d C o lo r " ) ;
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;
v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

c o n te x t. f i l l S t y l e = f g C o lo r ;
c o n t e x t . f o n t = " b o ld le m s a n s - s e r i f " ;
c o n te x t. t e x t A lig n = " le f t" ;
c o n t e x t . f i l l T e x t ( "Я п о в е л с я на э т о т т в и т " , 20, 40)

Через несколько мгновений мы


помест им сюда код для рисования
текста твита...

c o n t e x t . f o n t = " b o ld le m s a n s - s e r i f " ;
c o n te x t. t e x t A lig n = " r ig h t" ;
c o n t e x t . f i l l T e x t ( "а в р е з у л ь т а т е п о л у чи л э т у паршивую м а й ку !
c a n v a s .w id t h - 2 0 , c a n v a s . h e i g h t - 4 0 ) ;
}

Н апечатав даппы й код, обповите фупкцию p r e v ie w H a n d le r с целью вы зова фупк-


ции d ra w T e x t и проведите тестирование, загрузив даппы й код в своем браузере.
Вы долж пы увидеть прим ерпо то же самое, что и мы:
Вот наш текст. У нас получился т екст , г Возьми в руку карандаш
имеющий полужирный шрифт без засечек
и корректное местоположение.
Попытайтесь самостоятельно завершить на­
пы е* писание функции d ra w T e x t. Вам необходимо
AT
извлечь выбранный твит, задать курсивный
Я по в е л с я на это т тви т...
шрифт с засечками, который немного круп­
нее (1 .2 е т ), чем шрифт по умолчанию, а так­
же убедиться в том, что текст будет выровнен
а в р е зу л ь тате пол учил э ту п ар ш и в у ю м айку! / О по левому краю, и разместить его в точке
А внизу
х = 30, у = 100. Это последний шаг перед
Select background color; j ммыИЦ у нас полу­ тем, как мы увидим в работе TweetShirt!
Circles or equine*'* | Нем** «Н чился текст
Sekul ibxI ^riun 04rt 1i) с вырав­ Н а п и ш и т е свой код в в е р х у
Pick a tw c c c | Если вы поклонник Твиттера, носите футболки TweetShirt ниванием и не з а г л я д ы в а й т е на с л е д у ю
щ к , с т ран и ц у ! (Мы серьезно!)
'Prwvtwj по правому
краю.

364 глава 7
раскрываем в себе художника

Завершаем написание функции drawText


Вот приводивш ийся чуть выше код, паписапие которого заверш или мы. Ну что, каков результат, если
сравпить его с паписаппы м вами? Если вы еще пе пабрали свой код, то используйте код, приведеппы й
пиж е (либо свою версию , если предпочитаете), и перезагрузите ф айл i n d e x . h t m l. Наш тест-драйв мы
продемонстрируем вам па следующей страпице.
f u n c t io n d r a w T e x t( c a n v a s , c o n t e x t ) {
v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " f o r e g r o u n d C o lo r " ) ;
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;
Нам не потребуется выравнивать
v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;
текст твита по левому краю ,
выравнивание по-преж нем у будет
c o n te x t. f i l l S t y l e = f g C o lo r ;
обеспечиваться отсюда.
c o n t e x t . f o n t = " b o ld le m s a n s - s e r i f " ;
c o n te x t. t e x t A iig n = " le f t" ;
c o n t e x t . f i i i T e x t ( "Я п о в е л с я на э т о т т в и т . . . " , 20 , 40) И зв л е ка е м н у ж н о м п а р а м е т р
и3 м е н ю выбора твитов.
selectObj = document.getElementByld (11tweets11)
index = selectObj.selectedlndex;
var tweet = selectObj[index].value; крупный курсив-
З а д а е м <5олее
ный шрифт с засечками...
context.font = "italic 1.2em serif";
context.fiiiText(tweet, 30, 100);
■и рисуем т екст , имеющий
позицию 3 О, НОО.
c o n t e x t . f o n t = " b o ld le m s a n s - s e r i f " ;
c o n te x t. t e x t A iig n = " r ig h t" ;
c o n t e x t . f i i i T e x t ( " . . . a в р е з у л ь т а т е п о л у чи л э т у паршивую м а й к у ! " ,
c a n v a s .w id t h - 2 0 , c a n v a s . h e i g h t - 4 0 ) ;

Фрэнк, скорее вы­


бирай предварительный
О просмотр. Я хочу увидеть
наше приложение T w eetS h irt
в работе!

дальше ► 365
запуск tweetshirt

Небольшой тест-драйв, 9 П П T*-e«5Mrt


■«“Til"*!©!*»:/
о затем — JfteW AJC ЗАПУСК! Я повелся на этот твит..
i.'TetiUtKn.inaeic.iKr С i f a 1 G:og)e

Надеемся, что вы видите то же самое, На футболке Если вы поклонник Твиттера, носите футболки Tweetshirt

что и мы! Здорово, не правда ли? Про­ при пред-


ведите тестирование интерфейса с вари тельном а в результате получил эту паршивую майку!
целью проверки качества созданного просмотре
Sekct background color: ( Ч1й« ?«j
программного продукта: попробуйте отобража­
Circles or squares'* 1arete* i: j
всевозможные комбинации цветов и ется твит.
фигур, замените имя пользователя дру­ Здорово!
Se'ect Uixt декхт

гим по своему усмотрению. P ic k 4 tWeCC 1 Если вы поклонникТвиттера, носите футболки Tweetshirt

Вам кажется, что вы по-настоящему


готовы переходить к запуску стартапа
Tweetshirt? Давайте сделаем это!

г Да!
Все работает!
Мы готовы к за­
пуску стартапа!

Ребята, не хочу вас разоча­


ровывать, но вы еще не все
сделали. Вы также должны были
поместить изображение птицы
Твиттера на футболку!

Т
Помните основательницу
TweetSkirt.com ?

366 глава 7
раскрываем в себе художника

Ребята, я тут самостоятельно


проделала небольшую работу
и написала код для добавления
изображения птицы Твиттера...

Давайте сей­
час вместе прой­
демся по нему...

В первую очередь пам пужпо изображ епие. Мы поместили файл t w i t t e r B i r d . p n g в папку


TweetShirt. Ч тобы добавить его в c a n v a s , пам спачала потребуется JavaScript-объект Im age.
Вот как оп создается:
^ --------- ‘ Создаем объект Image.
var twitterBird = new I m a g e ();
^— И задаем в качестве его
twitterBird. s rc = "twitterBird.png"; источника изображение
птицы Твиттера.

Следующий шаг уже долж еп показаться вам вполпе естествеппым. Н ам пужпо парисовать
изображ епие в c a n v a s , используя метод объекта c o n t e x t с имепем, как вы уже догадались,
d ra w lm a g e .

context.drawlmage(twitterBird, 20, 120, 70, 70);

^ 3 от наш ^
Используем метод drawlm age. объект Кром е того, указываем значения координат
местоположения х, у, ширины и высоты.
Image.
Об изображ епиях вам пужпо зпать еще одпу вещь: опи пе всегда загружаются мгповеппо, по­
этому вам будет пеобходимо удостовериться в том, что изображ епие полпостью загрузилось,
преж де чем вы приступите к его рисовапию . Как мы ждем, пока что-то загрузится, перед тем
как п редприпять действие? Мы реализуем для этого обработчик o n lo a d :
Здесь мы говорим: «Когда изо -
бражение загрузится, выполнить
twitterBird.onload = function () { данную функцию».

context.drawlmage(twitterBird, 20, 120, 70, 70);


V -' Рисуем изображение в canvas,
используя метод draw lm age
объекта context.

дальше ► 367
добавление изображения

Посмотрите, сможете ли вы собрать функцию d r a w B ir d из всех тех кусочков, которые нам


предоставила Джуди. Функция d ra w B ird принимает canvas и c o n te x t и рисует изображение
птицы в ca n va s. Исходите из того, что с помощью данной функции мы должны разместить
" t w i t t e r B i r d . p n g " в месте с координатами х = 20, у = 120, при этом ширина и высо­
та будут равны 70 пикселам. Мы уже написали за вас объявление метода и первую строку.
Решение данного упражнения вы найдете в конце главы.

f u n c t io n d r a w B ir d ( c a n v a s , c o n te x t) {
v a r tw itte r B ir d = new Im a g e ( ) ;

Свой код
напишите
здесь.

Убедитесь, что вы добавили вызов функции


drawBird в функцию preview Handler.
}

Еще один mecm-драйВ


Дважды проверьте свой код и проведите еще
T.VCCtShlrr
один тест-драйв! Здорово, теперь наше при­
ложение действительно выглядит отшлифо­
Я повелся
ванным.
Сделайте несколько попыток; попробуйте вы­ ЛОКЛ°ННиКТвиттера’ носитеФутболки T.ee,Shirt
брать Circles (Круги) или Squares (Квадраты)
в меню Circles or squares? (Круги или ква­
•ав результате получил эту паршивую майку!
драты?). Вы заметите, что мы использовали
изображение в формате PNG с прозрачным
фоном, чтобы круги и квадраты были видны,
если они окажутся позади изображения птицы. Select

Здорово, мы значительно пре~ - ^


успели в разработке классного
приложения. Но, как уже от м е ­
чалось ранее, мы рассчитываем
на вас в реализации всего необхо­
димо для ведения торговли через
Интернет и выполнения заказов,
связанных с футболками, и т. п.

368 глава 7
4acm° раскрываем в себе художника

ЧаДаБаеМые
В опросы

это хорошая штука, поскольку любые специальные символы или


Мы раньше не сталкивались с объектом im a g e . Вы ис­ даже кавычки, которые могли бы помешать нам получать твиты
пользовали его при добавлении изображения в c a n va s. А что он из JSON, представляются в виде сущностей. При отображении
собой представляет? Почему его нельзя было создать с помощью твитов с использованием HTML эти сущности отображаются в
d o c u m e n t. c r e a t e E le m e n t ( " im g " )? браузере как символы, которые вы и ожидаете увидеть, подобно
тому как сущности, добавляемые вами в собственную страницу,
0 : Оба упомянутых вами метода позволяют создавать объекты также будут корректно отображаться в браузере. Однако в canvas
Image. JavaScript-конструктор Im age предоставляет более пря­ они выглядят не так хорошо. К сожалению, в настоящее время в
мой путь создания изображений из JavaScript и дает нам больший API-интерфейсе Canvas нет функции для преобразования данных
контроль над процессом загрузки (например, позволяет исполь­ сущностей обратно в соответствующие символы, поэтому вам
зовать обработчик для получения уведомления, когда загрузка придется делать это самостоятельно.
изображения завершается). Наша цель заключается в создании
изображения, а также в том, чтобы убедиться, что оно уже загрузи­
^ J А можно ли сделать в c a n va s что-нибудь необычное, напри­
лось, прежде чем мы приступим к его рисованию в canvas. Объект
мер снабдить текст или фигуры тенью?
Im age позволяет сделать это оптимальным путем.

Q J Да! С помощью ca n va s вы можете делать массу необычных


вещей, и эффект отбрасывания тени относится к их числу. Как вы
которые трудности по сравнению с HTML. Что-то сложнее базовых
и могли ожидать, создание тени осуществляется путем присваива­
фигур, по-видимому, действительно будет сложно нарисовать.
ния значений соответствующим свойствам c o n te x t . Например,
чтобы задать степень размытия, необходимо присвоить требуемое
Q j Вы, несомненно, пишете код графики, когда программируете
значение свойству c o n t e x t . s h a d o w B lu r. Местоположение
ca n va s. В отличие от браузера, который вместо вас заботится
тени задается с помощью свойств c o n t e x t . shadow O f f s e t x
о массе деталей вроде добавления элементов на веб-страницу
и c o n t e x t . shadow O f f s e tY , а чтобы установить цвет, нужно
(благодаря чему вам не нужно самим все рисовать), вам придется
присвоить значение свойству c o n t e x t . shadow C olor. К прочим
говорить can vas, где все должно размещаться. Однако ca n va s
возможностям canvas относится рисование градиентов, вращение
обеспечивает широкие возможности создания графики почти что
фигур и закругление углов прямоугольников.
любого типа (в настоящий момент — 2D). Мы пребываем на на­
чальном этапе существования c a n v a s ; вероятно, библиотеки
I Что еще интересного можно делать в случае с canvas?
JavaScript-KOfla смогут облегчить создание графики в c a n v a s
в будущем.
В
0 : Много чего! В следующих главах мы расскажем еще о паре
В случае с очень длинными твитами я заметил, что часть способов использования c a n v a s . Кроме того, вы определенно
такого твита, выходящая за край c a n v a s , просто исчезает из захотите более подробно исследовать API-интерфейс Canvas,
виду. Как это исправить? для чего можете зайти по адресу http://dev.w3.org/html5/2dcontext/.

0 : Сначала нужно выяснить количество символов, содержащих­ А будет ли все создаваемое в ca n va s работать и на моем
ся в твите, и если оно будет превышать определенное число, то мобильном устройстве или мне придется переписывать его для
разбить данный твит на несколько строк и рисовать каждую из них мобильных пользователей?
отдельно в c a n v a s . Мы включили соответствующую функцию
s p l i t in t o L in e s в код, доступный по адресу wickedlysmart.com. 0 : Если на вашем мобильном устройстве установлен современ­
ный браузер (на всех устройствах вроде Android, iPhone и iPad
Я также заметил, что в некоторых твитах имеются HTML- как раз имеются такие браузеры), то все будет отлично работать
сущности вроде &quot; и &атр;. Что все это значит? (масштабирование страницы может быть отключено, однако функ­
циональность сохранится). Замечательная особенность ca n va s
0 : API-интерфейс Twitter, используемый нами для извлечения заключается в том, что, поскольку вы рисуете «сырые» пикселы,
твитов в виде JSON-данных, преобразует символы, которые поль­ все создаваемое вами будет везде отображаться одинаково (то есть
зователи печатают в своих твитах, в HTML-сущности. Вообще-то во всех браузерах, которые поддерживают canvas).

дальше ► 369
Для этого придется еще потрудиться.
Н а самом деле ca n v a s призван быть простой поверхностью
для рисования. Когда вы создаете фигуру, ca n v a s видит ее как
группу пикселов. О н ничего не знает об особеппостях того,
что вы рисуете, и не отслеж ивает никаких фигур, а просто соз­
дает пикселы, которы е вы говорите ему создать (если вам зпа-
комы такие терм ины из области граф ики, как «растровое р и ­
сование» и «векторное рисование», то вы пойм ете, что ca n va s
осущ ествляет растровое рисование).
Если вам захочется обходиться с прямоугольпиками в своем
ca n v a s как с набором объектов, которы й можпо будет сохра­
нить (или, возможно, вы захотите перемещ ать его или мани­
пулировать им), то вам потребуется сохрапять ипф орм ацию о
фигурах и контурах по ходу рисования их в canvas. Вы сможе­
те сохранить эти данны е в JavaScript-объектах. Н априм ер, если
вы захотите отследить произвольны е круги, парисоваппы е
вами в ca n va s при работе над TweetShirt, вам потребуется со­
хранить координаты м естополож ения х, у, зпачепия радиуса и
цвета каждого конкретного круга, чтобы вы смогли воссоздать
его позже.
П охоже, что это и есть плап действий, которы й вам п уж еп ...;)
раскрываем в себе художника

Поздравляю, ребята, вам


удалось это сделать! Созданное вами при­
ложение работает даже на моем iPad, так что
оно идеально подойдет для клиентов, находя­
щихся в дороге. Я впечатлена. У нас намечается
вечеринка по поводу запуска стартапа Tw eetS hirt,
поэтому присоединяйтесь к нам.

Основательница T w e e ts h irt.сот рада видеть,


что созданное нами веб-приложение работает
на ее iPad и iPhone! Если она рада , то и мы рады.

дальше ► 371
обзор canvas

КЛЮЧЕВЫЕ «
МОМЕНТЫ J O ' -------------------

■ canvas — это элемент, который вы размещаете в сво­ ■ Метода f i l l C i r c l e не существует. Чтобы нарисо­
ей странице с целью создания области для рисования. вать круг в c a n v a s , вам потребуется начертить дугу.

■ ca n va s не будет иметь стиля по умолчанию или со­ ■ Для рисования произвольных фигур или дуг сначала
держимого, пока вы не снабдите его им (таким образом, необходимо начертить контур.
вы не увидите c a n v a s на веб-странице до тех пор,
■ Контур — это невидимая линия или фигура, которую
пока не нарисуете что-нибудь в нем или не добавите
вы чертите для определения линии или области в
рамку для него с помощью CSS).
canvas. Контур нельзя будет увидеть до тех пор, пока
■ У вас на странице может иметься более одного вы не обведете его или не примените к нему заливку.
canvas. Вам, конечно же, потребуется присвоить каж­ ■ Для создания треугольника необходимо начать контур
дому из них уникальный идентификатор, чтобы к ним с ПОМОЩЬЮ b e g in P a th , а ЗЭТвМ ИСПОЛЬЗОВЭТЬ moveTo
можно было обращаться с использованием JavaScript. и lin e T o для рисования контура. Для соединения двух
■ Для задания размеров элемента c a n va s следует ис­ точек контура используйте c lo s e P a th .
пользовать его атрибуты w id t h И h e ig h t . ■ Чтобы нарисовать круг, начертите 360-градусную дугу.
■ Все, что вы захотите поместить в c a n v a s , будет Начальный угол будет 0°, а конечный — 360°.
рисоваться с применением JavaScript. ■ Углы задаются в canvas с использованием радианов,
■ Для рисования в c a n v a s вам сначала нужно будет а не градусов, поэтому нужно преобразовать градусы
создать контекст. В настоящее время вашим един­ в радианы, чтобы задать начальный и конечный углы.
ственным выбором является контекст 2d, однако в бу­ ■ 360 градусов = 2% радианов.
дущем возможно появление и других типов контекста.
■ Чтобы нарисовать текст в canvas, используйте метод
■ Контекст необходим ДЛЯ рисования В ca n va s потому, fiiiT e x t.
что он обеспечивает специфический тип интерфейса
■ При рисовании текста в c a n v a s вам будет нужно
(например, 2d и 3d). Вы сможете выбирать нужный
указывать позицию, стиль и пр., используя свойства
ТИП Интерфейса ДЛЯ рИСОВаНИЯ В ca n va s.
Объекта c o n te x t .
■ Обращаться к c a n v a s следует с использованием
■ Когда вы задаете значение для свойства объекта
свойств и методов объекта c o n te x t .
c o n t e x t , оно применяется на протяжении всего про­
■ Чтобы нарисовать в c a n v a s прямоугольник, нуж­ цесса рисования, пока вы не присвоите этому свойству
но воспользоваться методом c o n t e x t . f i l l R e c t . другое значение. Например, изменение значения свой­
Он создает прямоугольник с заливкой цветом. ства f i l i s t y l e повлияет на цвет фигур и текста,

■ Чтобы нарисовать контур прямоугольника, вместо создаваемых вами после присваивания этому свойству
нового значения.
f i l l R e c t используйте МвТОД s tr o k e R e c t.
■ Добавление изображений в c a n v a s осуществляется
■ Используйте f i l l S t y l e И s t r o k e S t y l e ДЛЯ ИЗ-
с ПОМОЩЬЮ метода d ra w lm a g e .
менения задаваемого по умолчанию цвета заливки
и обводки, которым является черный. ■ Чтобы добавить изображение в ca n va s, вам сначала
потребуется создать объект Im age и убедиться, что
■ Вы можете задавать цвета, используя тот же са­
соответствующее изображение полностью загрузилось.
мый формат, что и в CSS (например, " b l a c k " ,
" # 0 0 0 0 0 0 ", " r g b ( о , о, 0) " ) . Не забывайте за­ ■ Рисование в c a n va s сродни растровому рисованию
ключать значение f i l i s t y l e в кавычки. в программах для работы с графикой.

372 глава 7
раскрываем в себе художника

Ьеовилль — здесь ты узнаешь


обо всем первым
П осле экскл ю зи в н о го и н те р в ь ю м ы м ож ем сообщ ить,
ч т о э л е м е н т ы <canvas> и <video> н е п р о с т о д е л я т д р у г
с д р у г о м о д н и и те ж е в е б -с т р а н и ц ы ... О н и , н а п р и м е р ,
с м е ш и в а ю т св о е с о д е р ж и м о е .

Трой А рм строн г
Ш Т А Т Н Ы Й А В Т О Р « В Е Б В И Л Л Ь С К О Г О КУР ЬЕР А »

<video> говорит: «Это правда, мы наладили тесные взаимоотноше­


ния. Видите ли, я довольно простой парень, ко то р ы й умеет вос­
производить видео, причем делает это очень хорош о. Однако это
п очти все, чем я занимаюсь. Но благодаря <canvas> все изменилось.
Я облачаюсь в пользовательские элементы управления, я фильтрую
свое видеосодержимое, я одновременно показываю несколько ви­
деоизображений».

За комментариями мы обратились к <canvas>. Является ли он тем, Местная жительница Хайди


кто стоит за тегом <video>? От <canvas> мы услышали следующее: Масгров была потрясена,
«Что ж, <video> сам по себе очень хорошо справляется, ну там, когда узнала правду об этих
знаете, с декодированием всех этих видеофайлов, сжатых опреде­ двух элементах.
ленными кодеками, с поддержкой частоты кадров в секунду и тому
подобным. Это большая работа, с ко то р о й мне никогда не удалось
бы справиться. Однако с моей помозцыо он может избежать своего
обы чного, осмелюсь даже сказать, «скучного» способа воспроизве­
дения видео. Я даю ему средства для исследования всех креативны х
возможностей по объединению видео с веб-приложениями».

Ч то ж, кто бы мог такое предположить? Полагаю, что впереди нас


ждут интересные вещи, которы е станут результатом партнерства
<canvas> и <video>!

М ож но ожидать, что последствия этого откровения мы будем наблю­


дать в главе, посвящ енной элементу <video>, когда его многообещ аю­
щее партнерство с <canvas> будет подвергнуто пристальному внима­
нию общественности.

оальше ► 373
кроссворд

U I M L 5 - it occ B t a
Мы с п етерп еп и ем ждем следующей главы, где сможем подробпее погово­
рить о сепсациоппой повости, касаю щ ейся < c a n v a s > и < v id e o > . А вы тем
врем епем закрепите свои повы е зпапия о c a n v a s , разгадав пеболы ной кросс­
ворд (возможпо, за чаш кой чая).

По горизонтали По вертикали
2. Свойство, для которого мы задавали значение с целью заливки 1. Данный метод объекта c o n t e x t создает прямоугольник.
фигуры цветом. 3. < c a n v a s > и ____________ хорошо сочетаются друг с другом.
5. Несуществующий метод, который Джим пытался использовать 4. Объект, включающий методы и свойства для рисования
для рисования кругов.
В ca n va s.
6. Сообщить о завершении загрузки чего-либо можно с помощью
5. Используйте данный метод для рисования текста в canvas.
обработчика____________ .
8. Для рисования кругов следует применять метод____________ . 6. Наилучшее место для размещения хорошего твита.
9. Мы осуществляем ее для того, чтобы сделать контур фигуры 7. Чтобы переместить карандаш при черчении контура в точку с
видимым. координатами 100,100, используйте____________ (100,100).
10. Хотите узнать, какой параметр был выбран? Тогда вам может 12. Мы думаем в градусах, a c a n v a s — в __________ .
потребоваться данное свойство.
11. Невидимая линия, которую вы чертите с целью нарисовать
фигуру.
13. Мы выравнивали текст . . . а в р е з у л ь т а т е п о л учи л
э т у паршивую м а й к у ! по_____________краю.
14. В круге 360____________ .
15. Все в c a n va s является____________ .

374 глава 7
раскрываем в себе художника

(Т А Н Ь браузером. Решение
] е п е р ь , к ° г д а у Бас е с т ь и н т е р ­
ф ей с, В ы полните п о в ед е н н ы е
Представьте, что вы используете
этот интерфейс для выбора зна­ Здесь JaVa^cript—о п е ^ а т ^ ы
чений в случае со своей футболкой. и н а п и Ш и т е Значение
д л я к а ж д о г о эл ем ен ­

т а и н терф ей са.

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " b a c k g r o u n d C o lo r " ) ;
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;
v a r b g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ; white
v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " s h a p e " )
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;
v a r shape = s e l e c t O b j [ i n d e x ] . v a l u e ; circles
v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld ( " f o r e g r o u n d C o lo r ”
v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;
v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ; b la c k
Обратите внимание, что в случае Не забывайте, что значение^ парам е­
с каждым значением меню мы и з­ тра может отличаться от текста,
влекаем элемент select, в кот ором который вы видите в элементах
содержится соответствующий управления; в нашем случае это как
парам ет р , находим выбранный раз касается первых букв текста.
парамет р с помощью свойства
selectedlndex и извлекаем значение
этого параметра. При необходимости
Select background color: [ White t ] еще раз взгляните
на H T M L , чтобы
Circles ОГ squares? [ Neither t j увидеть значения
Во ^ ^ м ’ коглТ ' ^
параметров.
Select text color: [ Black 11 ]

Pick a tweet: [ ■; ]

( Preview)

дальше ► 375
решение упражнения

Развлечения с магнитами, решение


Воспользуйтесь своими псевдомагическими способностями программиста для размещения в нуж­
ной последовательности приведенных ниже табличек. Вам нужно написать псевдокод для функции
d ra w S q u a re . Данная функция принимает c a n v a s и c o n t e x t и рисует в c a n va s один квадрат произ­
вольного размера. Вот наше решение этого упражнения.
Одну из табличек мы
уже уизтьстили
разместили за вас
fu n c tio n d ra w S q u a re (
' { в нужном месте.

вычислить
произвольную ширину
для квадрата

вычислить произвольную позицию X


для квадрата внутри ca n va s

вычислить произвольную позицию у


для квадрата внутри canvas

Р а з м е с т и т е здесь
Задать для fillstyle значение
таблички с п с е в д о ­
" lig h tb lu e "
кодом в нужной п о ­
с л е д о в а т ел ь н о с т и !
нарисовать квадрат, имеющий
позицию х г у и ширину w

Возьми в руку карандаш


Решение Чтобы при каждом нажатии кнопки Preview (Предварительный про­
смотр) мы наблюдали в ca n va s только новые квадраты, потребует­
ся залить фон ca n v a s цветом, выбранным пользователем в меню
" b a c k g r o u n d C o lo r " . Сначала реализуем функцию для заливки
c a n v a s выбранным цветом. Ниже приведен код, в котором вам необ­
ходимо устранить пробелы. Вот наше решение этого упражнения.

fu n c t io n f illB a c k g r o u n d C o lo r ( c a n v a s , c o n te x t) {

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld (" b a c k g r o u n d C o t o r - ) t

var in d e x = s e le c tO b j . s e le c t e d ln d e x ; д дя заливки ф он а ц в е т о м МЫ р и с у е м

var b g c o lo r = s e le c t O b j . o p t io n s [ in d e x ] . v a l u e ; п р я м о у г о л ь н и к , к о т о р ы й за п о л н я е т
I ^ i ц в е т о м п о л н о с т ь ю весь canvas.
c o n te x t. f i l l S t y l e = и ^ С 0 \ 0 \ Г ;

c o n t e x t . f i l l R e c t (0, 0 , ca n va s.w id tk, canvas-height)

376 глава 7
раскрываем в себе художника

СТАНЬ браум ром . Решение


п о в е д е н н ы й н и ж е Вызов ме-щ°да ale и H anuinuine все со о г^ве ш —
сщВутоЩие значения, KoiiioJ^bie х а р а к т е р и з о в а т ь Круг, а хпакж е u3o£pa3uine
ду1Ч), со5ДаВаеМу!° В реЗуЛь-шагца эгцоГо Bj>i3oBa.

context.arc(100, 100, 75, degreesToRadians(270), 0, true);


И черт им против Начинаем здесь
часовой стрелки
Радиус = 75* пикселов

Дуга Конечный угол = О0

Начальный угол = 2 7 0 °

Umak, у нас е сть контур! U что теперь?


ажнение Теперь вы будете использовать этот контур для рисования линий и заливки своей фигуры
"Piешение
цветом, конечно же! Создайте простую НТМ1_5-страницу с элементом c a n v a s и наберите
весь приводившийся чуть ранее код. Затем проведите тестирование.

c o n te x t . b e g in P a t h ( ) ;
c o n te x t .m o v e T o (1 0 0 , 1 5 0 ); Вот код} приводившийся ранее
c o n te x t . l i n e T o (2 5 0 , 7 5 ) ;
c o n te x t . l i n e T o (1 2 5 , 3 0 ) ;
c o n te x t . c lo s e P a t h ( ) ;

c o n t e x t . lin e W i d t h = 5 ; Задать толщину линии для рисования поверх контура.


c o n te x t . s t r o k e ( ) ; Нарисовать линию поверх контура.
c o n te x t . f i l l S t y l e = "re d " Задать красный цвет для заливки треугольника.
c o n te x t • f i l l 0 ; Применить к треугольнику заливку красным цветом.

Загрузив веб-страницу Triangle ,


мы увидим вот это (для рисо­
вания мы создали canvas разм е­
ром ЗОО х ЗОО пикселов). у

дальше ► 377
решение упражнения

Перерыв, решение
il * )

X> У = 'Z-OO) 2 5 0
радиус = ZS *> у = 4 0 0 , 2.s o
Пора применить на практике ваши новые знания о дугах
и контурах для создания улыбающейся рожицы. Устра­
ните пробелы в приведенном ниже коде, который позво­
лит нарисовать улыбающееся лицо. Мы предусмотрели
для вас подсказки относительно того, где на диаграмме
должны располагаться глаза, нос и рот.
ЪОО, 3 0 0 | угол = 2 0 °
Вот наше решение этого упражнения: длина носа
fu n c t io n d ra w S m ile y F a c e () {
v a r c a n va s = d o c u m e n t. g e tE le m e n tB y ld ( " s m i l e y " ) ;
v a r c o n te x t = c a n v a s . g e tC o n te x t( " 2 d " ) ; у = зоо, з so
радиус = 7 s

c o n t e x t . b e g in P a t h ( ) ;
c o n t e x t .a r c ( 3 0 0 , 300, 200, 0, d e g re e s T o R a d ia n s (360 tr u e
c o n te x t . f i l l S t y l e = " # ffffc c "; К р' уг ......
лица. мы Здесь
уже устранили за вас
ооин из пробелов. ' Обратите
" ~I внимание , М Ы
^ми/нипиЬ;
c o n te x t •f i l l ( ) ;
применили к кругу заливку желт ым цветом.
c o n te x t . S tro k e ( ) ; Левый глаз. Центр
Левый глаз. Центр круга имеет координаты х = 2 0 0 , и = 2SO оади-
2 5 , начальный цгол О. конечный Mn-f-u р I *- о э х J
c o n t e x t b e g in P a th о Р 5вод“ м конт ур , чтобы получить очертания круга ( н о ^ е з з а л и в к и у ^ '
c o n te x t a r с ( 2 0 0 , 2 5 0 , 2 5 , О, dcgrCCS~ToRacliaiAS(3G?0), t r u e ) ;
c o n te x t S tro k e о ; Правый глаз. Такой Же, как
и левый, но с координатой
c o n t e x t b e g in P a th () ; & X = 40 0 . Мы используем

c o n t e x t a r c (4 0 0 , Z S O , 7 - 5 , О, degireesToRadians(3<bO), t r u e ) ; направление против часо-


вой стрелки (значение true)
c o n te x t s tr o k e ( ) , (при рисовании полного
круга направление неважно).
Это нос. Мы используем
c o n t e x t . b e g in P a t h ( ) ; m oveTo(300,
П О Л Ь З и Р . А Л 1ЛЛ rw/o'Tn^'z./ з ОО) для перемещения
пера в точку х
c o n t e x t . m oveTo (ЗОО, ЪОО) ; о ' ' '' У - 3(9(9, чтобы начать создание линии
uZm b Т при™еняем "™ Т о (3 0 0 , 3SO), поскольку нос будет '
c o n t e x t . ИпеТо (ЪОО, Ъ 50) ; имет ь длину s o пикселов. После этого обводим конт ур
c o n t e x t .s tro k e о ;
Чтобы у нас получилось более правдоподобное улыба­
ющееся лицо, начинаем и заканчиваем чертить края
У рта на 2 0 ° ниже оси X. Это означает, что начальный
c o n t e x t . b e g i n P a t h () ; X угол будет равен 2 0 °, а конечный составит г<ЬО°.
c o n te x t 0 Х С ( 300, 350, 75 , d e g re e s T o R a d ia n s ( 2 0 ) , d e g re e s T o R a d ia n s (К Ь О ) , fa ls e );

c o n t e x t s t r o k e () ; Направление — против часовой стрелки (значение false), ^


поскольку нам нужен улыбающийся рот (не забывайте,
что начальная точка находится справа от центра рта).

378 глава 7
раскрываем в себе художника

Развлечения с магнитами
Пришло время вашего первого эксперимента с текстом в c a n va s. Ниже приведен начатый нами код для
метода d ra w T e x t, который мы будем вызывать, чтобы нарисовать весь текст в c a n v a s для предвари­
тельного просмотра. Посмотрите, сможете ли вы завершить данный код, чтобы нарисовать Я п о в е л ся
на э т о т т в и т . . . и . . . а в р е з у л ь т а т е п о л у чи л э т у паршивую м а й ку ! в c a n v a s , а рисование
реального твита пользователя мы оставим на потом. Вот наше реш ение этого упражнения.

f u n c t i o n d r a w T e x t( c a n v a s , c o n t e x t ) {

v a r s e le c tO b j = d o c u m e n t. g e tE le m e n tB y ld (" fo r e g r o u n d e d or

v a r in d e x = s e l e c t O b j . s e le c t e d ln d e x ;

v a r f g C o lo r = s e l e c t O b j [ i n d e x ] . v a l u e ;

f i l l S t y l e | = f g C o lo r ;

fo n t \ = " b o ld le m s a n s - s e r i f " ; Подсказка: это позиция x, у


s-^ д л я текста «Я повелся на
te x t A iig n " le f t" ;
V этот твит...».
c o n te x t. fiiiT e x t i " я повелся на этот твит..." 20 , 40);

/ / И звлечь выбранный т в и т и з меню выбора т в и т о в -- Подсказка: МЫ будем испоЛЬ


На данный зовать курсивный шрифт
момент мы / / Н а р исо ва ть т в и т с засечками для твита, од­

размещаем нако нам необходимо, чтобы


ком мент а - ^ этот текст имел полу -
рии т а м > c o n t e x t . f o n t = " b o l d l em sans-serif In . Жирный шрифт Helvetica.
где будет
c o n te x t. t e x t A iig n Подсказка: мы хот им поместить
распола­ J = текст в правый нижний угол.
гаться код
c o n t e x t . f i i i T e x t I ( " . . . а в р е з у л ь т а т е п о л у чи л э т у паршивую м а й к у ! " ,
для рисова -
ния текста
c a n v a s .width-20 i~' - c a n v a s . height-4^Jj '
твита.
}
M w х о т и м нарисовать данный ^
текст в ZO пикселах от правой
стороны canvas и в 4 0 пикселов
от основания canvas , чтобы он ур а в­
новешивал верхнюю строку текста.

Лишние магнитные таблички

fillCircle fillRect

дальше ► 379
решение упражнения

пражнение Посмотрите, сможете ли вы собрать функцию d r a w B ir d из всех тех кусочков, которые нам предоста­
решение вила Джуди. Функция d r a w B ir d Принимает ca n va s И c o n te x t И рисует изображение ПТИЦЫ В canvas.
Исходите ИЗ ТОГО, ЧТО С ПОМОЩЬЮ данной функции МЫ ДОЛЖНЫ разместить " t w i t t e r B i r d . p n g " вместе
с координатами х = 20, у = 12 0, при этом ширина и высота будут равны 70 пикселам. Мы уже на­
писали за вас объявление метода и первую строку. Вот наше решение этого упражнения.

Не забудьте доба­
f u n c t i o n d r a w B ir d ( c a n v a s , c o n t e x t ) { вить вызов d ra w B ird
Свой код на п и ­ v a r t w i t t e r B i r d = new Im a g e ( ) ; в свою функцию
шите здесь tw itte r B ir d s r c = (ft w i t t e r 8 i i r d . p n g n; preview Handler!
tw itte r B ir d .o n lo a d = fu n c tio n Q {

c o n te x t.d r a w lw a g e ttw itte r B iir d j 2 0 , % 20, 7 0 , 7 0 );

1;

U r M L § - K r occ® T A - Г еШение

380 глава 7
раскрываем в себе художника

Пасхальное яйцо В Tw/eetShirt


Итак, вы сгенерировали отличны й предварительны й просм отр
TweetShirt. А что тенерь? Если вы действительно захотите превра­
тить свой дизайн в изображ ение на футболке, то сможете сделать
это! Каким образом? Вот небольш ое дополнение, которое вам
нужно внести в код, — насхальное яйцо в TweetShirt. Оно п ревра­
ти т ваш дизайн в изображ ение, нолностью готовое к выгрузке на
сайт, нозволяю щ ий нанечатать его на настоящ ей футболке (в И н­
терн ете таких сайтов существует целое множество).
Как это сделать? Элементарно! Мы можем воспользоваться мето­
дом toD a ta U R L объекта canvas. Взгляните на пример:

Мы создали новую функцию makelmage,


J чтобы добавить данную возможность.

f u n c t i o n m a k e lm a g e () { Извлекаем объект canvas...


v a r c a n v a s = d o c u m e n t. g e tE le m e n tB y ld ( " t s h i r t C a n v a s f
Г
c a n v a s . o n c lic k = fu n c t io n () { ...и добавляем обработ-
w in d o w . lo c a t io n = c a n v a s . to D a ta U R L ( " im a g e /p n g " ) ^ чик событийj чтобы
щелчок на элементе
A f
canvas приводил к гене-
> Мы задаем генерируемое изо - L nP0C“ M canvaS C°]_
дать изображение в ф ор - Р ж а н и ю изображения,
бражение в качестве значения
window .location в случае с брау­ мате PNG из пикселов,
зером, благодаря чему на ст р а ­ нарисованных в canvas. ^ Следует от мет ит ь, что

нице в браузере вы увидите PNQ является единствен­


именно это изображение. ным ф ормат ом, который
должен поддерживаться
Тенерь нросто добавьте вызов make Im age в функцию w in d o w .o n lo a d , браузерами , поэт ому им ен­
и ваш c a n v a s отны не сможет генерировать изображ ения, когда вы но его мы и рекомендуем
будете щелкать на нем. П роведите тестирование. И дайте нам знать, вам использовать.
если создадите футболку с изображением!
w in d o w .o n lo a d = f u n c t i o n () {
v a r b u t t o n = d o c u m e n t. g e tE le m e n tB y ld ( " p r e v ie w B u t t o n " ) ;
b u t t o n . o n c lic k = p r e v ie w H a n d le r ;

make im age ( ) ; — _ обеспечьте вызов makelmage для добавле-


} ния обработчика событий onclick для cav\vas>
и ваше пасхальное яйцо будет готово.

Некоторые браузеры не позволят извлекать изображение


из canvas, если вы выполняете данный код из file://.

Ды не I Выполняйте данный код, используя localhost:// или онлайн-


оСШ о^оЖ Ньх! сервер, если хотите, чтобы он работал во всех браузерах..

дальше ► 381
8 телевидение для нового поколения

* Элемент video...
...и наш особый гость—элемент canvas

Нам больше не нужны плагины. Элемент v i d e o отныне является полно­


ценным членом HTML-семейства: просто вставьте его в свою страницу — и вы
обеспечите прямую поддержку воспроизведения видео на большинстве устройств.
Однако v i d e o — нечто значительно большее, чем просто элемент: это API-
интерфейс JavaScript, позволяющий управлять воспроизведением, создавать
пользовательские видеоинтерфейсы и интегрировать видео с остальными HTML-
элементами совершенно новыми способами. Говоря об интеграции... как уже
отмечалось ранее, между v i d e o и c a n v a s существует связь, — вы увидите,
что объединение этих элементов открывает новые возможности по обработке
видео в режиме реального времени. В этой главе мы научимся внедрять элемент
v i d e o в веб-страницу, а затем поговорим об использовании соответствующего
API-интерфейса JavaScript. Вы будете поражены тем, что можно сделать с по­
мощью небольшого количества разметки, JavaScript и элементов v i d e o и c a n v a s .
анонс webville tv

Знакомство с Webville TV
Webville TV —это содерж имое, которого вы жда­
ли, нанрим ер: «Пункт назначения - планета Зем­
ля» (D estination Earth), «Нападение 50-футовой
женщины» (The Attack of the 50’ W om an), «Нечто»
(The T hing), «Капля» (The Blob), и не будет лиш ­
ним вклю чить сюда образовательны е фильмы
1950-х годов. Однако это всего лишь содерж и­
мое, а что касается технологий, то ож идаете ли
вы здесь чего-то меньш его, чем НТМЬ5-видео?
Это, конечно же, лиш ь наше видение нроблемы,
и если мы хотим трансф орм ировать его в нечто
реальное, то нам но требуется создать Webville
TV. Н а нескольких следующих страницах мы бу­
дем заниматься созданием Webville TV «с нуля»,
иснользуя НТМЬ5-разметку, элемент video и не­
много JavaScript.

Webville T V , на Ю О %
созданное с применением
технологии HTML5.

Скоро в вашем
браузере!

384 глава 8
телевидение для нового поколения

Разберемся с HTML-разм еткой...


Э то ведь уже глава 8, ноэтому не будем медлить! Д авайте сразу нристуним к нанисанию HTM L-разметки:

< ! d o c ty p e h tm l> Вполне стандартный HTMLS.


к Г '" "
< h tm l la n g = " e n " >
<head>
< t it le > W e b v ille T V < /t it le >
He забудьте CSS-файл
<m eta c h a r s e t = " u t f - 8 ">
для обеспечения краси-
<1±пк r e l= " s t y le s h e e t" h r e f = " w e b v i l l e t v . c s s "> вого внешнего вида.
< /h e a d >
<body>
Небольшое изображение,
< d iv i d = " t v " > чтобы все было похоже
< d iv id = " t v C o n s o le " > на настоящий телевизор.
< d iv i d = " h i g h l i g h t ">
< im g s r c = " im a g e s / h ig h l ig h t . p n g " a lt= " h ig h lig h t fo r tv " >
< / d iv >
< d iv id = " v id e o D iv " >
< v id e o c o n t r o ls a u t o p la y s r c = " v i d e o / p r e r o l l .m p4" w id th = " 4 8 0 h e ig h t = " 3 60"
p o s t e r = " im a g e s / p r e r o ll p o s t e r . j p g " id = " v id e o " >
< / v id e o >
А вот наш элемент <video>
< / d iv >
для воспроизведения видео. Ъолее
< / d iv > ' пристально на него мы взгля­
< / d iv > нем через несколько мгновений...
< /b o d y >
< / h tm l> Если у вас возникли
проблемыj перевер­
Включите э т о т «телеВизор» ните страницу!
i
и протестируйте его... Вот что мы видим.
Если вы наведете
Здесь нужно нозаботиться о некоторы х вещах: во- указатель мыши
нервых, наберите весь нриведенны й чуть выше на экран, то по­
код и сохраните его в ф айле w e b v ille tv .h tm l; явится набор эле­
во-вторых, загрузите на свой комнью тер соответ­ ментов управления,
ствующий CSS-файл, скачайте видеоф айлы и но- предназначенных для
местите их в каталог video. Сделав это, загрузите того, чтобы вос­
страницу, но еле чего откиньтесь на снинку стула производить видео}
и смотрите. ^ ставить на паузу ,
Все необходимое загрузите, посетив страницу регулировать звук,
h ttp : // wickedlysmart. com/hfktml5 осуществлять по­
иск в видео.
дальше ► 385
форматы видео могут вызывать проблемы

Я не вижу никакого видео. Я трижды


проверил код и расположил видео­
файлы в нужном каталоге.
Есть идеи?

Да, возможно, дело в формате видео.


Н есм отря на то что разработчики браузеров со­
гласны с тем, что элемент <video> и API-интерф ейс
Video схожи в HTML5, не все из них сходятся во
м нении насчет фактического формата самих видео­
файлов. Н анрим ер, если вы используете браузер
Safari, то нредночтительны м для вас будет ф орм ат
кодирования Н.264, а если C hrom e —то WebM и т. д.
В коде, нанисанием которого мы только что зани­
мались, в качестве ф орм ата кодирования предпо­
На момент ч т е ­ лагался Н.264, работаю щ ий в Safari, Mobile Safari,
ния вами этой In tern et E xplorer версии 9 и выше. Если вы ис-
книги данные ф ор­ нользуете другой браузер, загляните в свой каталог
маты могут уже
v id eo , где найдете видеоф айлы трех отличаю щ ихся
долее широко под­ тинов с трем я разны ми расш ирениями: MP4, OGV
держиваться всеми
и WEBM (что они означают, рассмотрим позже).
браузерами. Таким
образомj если видео В случае Safari вы уже долж ны использовать MP4
у вас воспроизво­ (которы й содерж ит Н.264).
дится, все о т ­ П ри иснользовании Google C hrom e следует прим е­
лично. Постоянно нять ф орм ат WEBM, для чего нужно зам енить зна­
заглядывайте в чение атрибута s r c следующим:
Интернет в поис­
ках самой свежей src = " v id e o /p re ro ll.w e b m "
информации по
Если же вы иснользуете Firefox или O pera, то заме­
этой развернутой
теме. Мы к ней
вскоре вернемся.
ните значение атрибута s r c на такое:

s r c = " v i d e o / p r e r o l l . ogv"
\ Попробуйте
А если вы работаете с In te rn e t Explorer версии 8 сделать так для
или ниж е, вам не новезло, —но стойте-ка, это же гла­ качала, а чуть
ва 8! Как вы до сих нор мож ете пользоваться браузе­ позже мы вер­
ром In tern et Explorer 8 (или ниже)? О бновите его! немся к этому.
Н о если вам необходимо узнать, как обеснечить р е­
зервное содерж имое для пользователей, у которы х
установлен In tern et Explorer 8, нотерните, но сколь­
ку мы еще дойдем до этого.

386 глава 8
телевидение для нового поколения

Как работает элемент video?


И так, вы все настроили, и у вас на странице воснроизводится видео. Однако нрежде, чем мы
двинемся дальше, давайте взглянем на элем ент video, которы й иснользован в наш ей разметке:

Если атрибут, controls присутствует , проигрыва-


/ — тель предоставит пользователю элементы управления
( для контроля над воспроизведением видео и аудио.
Благодаря атрибуту autoplay воспроизведение видео
<video controls запускаться по завершении загрузки страницы.
autoplay ----- - ,
IУ Исходное местоположение видео
src=,,video/preroll .mp4"
—. Ширина и высота видео
width="480" height="360" на странице
poster=" images/prerollposter .jpg"
id— video > _ Картинка , которая отображается,
</video> ^ когда видео не воспроизводится.
Идентификатор для эле­
мента video> чтобы мы
могли обращаться к нему
позже из JavaScript.

Еще один полезный совет из HTML5 -


руководства города Вебвилль.
Правила видеоэтикета:
свойство autoplay
Несмотря на то что a u t o p l a y может оказаться луч­
шим выбором в случае с такими сайтами, как YouTube
и Vimeo (или даже Webville TV), дважды подумайте,
прежде чем задавать его в своем теге < v i d e o > .
Пользователь зачастую желает сам решать, должно ли
воспроизводиться видео при загрузке вашей страницы.

дальше ► 387
обзор атрибутов элемента video

Пристальный взгляд на атрибуты элемента video...


Давайте внимательнее взглянем на наиболее важные
атрибуты элемента video:
яге
А трибут s r c подобен s r c элемента <im g> —
controls
А трибут controls является логи
L это U R L -адрес, ко то р ы й сообщает элементу video,
ческим. Либо он есть, либо его
src определяет, где искать ф айл-источник. В данном случае таким
нет. Если он присутствует, то какой видео­ файлом является v i d e o / p r e r o ll. m p 4 (если вы
браузер добавит свои встроен^ файл будет загрузили на свой компью тер код, используемый
„ы е элементы управления в об­ здесь воспроиз­ в этой главе, то сможете найти данны й видеофайл,
ласть отображения видео. Здесь а также два других в каталоге v id e o ).
водиться.
возможны вариации в зависи-
pielo
I мости от браузера, поэтому про-
веряйте, ка к они будут выглядеть Л о ги ч е с ки й атрибут p r e lo a d обычно
в каждом браузере. Вот ка к они высота используется для тщательного контроля
над загрузкой видео в целях оптимиза­
выглядят в Safari.
ции. Браузер, по большей части, решает,
ширина какой объем видео загружать, исходя,
например, из того, был ли задан атри­
бут a u to p la y , а также ориентируясь на
ащо пропускную способность канала поль­
t Ви де оп р ои гр ы -
зователя. Вы можете изменить данное
Л о ги ч е ски й атрибут a u t o p la y дает ватель поведение, присвоив p r e lo a d значение
браузеру команду начинать воспроиз­
попе (видео не будет загружаться до тех
ведение видео, как только у него будет
пор, пока пользователь не нажмет кн о п ­
достаточно данных. В случае с нашими
ку воспроизведения), либо m e ta d a ta
демонстрационны ми видеофайлами вы,
(метаданные видео будут загружаться,
вероятно,увидите, что их воспроизведе
но без видеосодержимого), либо a u to ,
ние запускается п о чти сразу.
которое позволит браузеру самостоя­
тельно приним ать решение.
poster 1+1 1 1
widlh, height
Браузер обычно отображает один кадр А трибуты w id t h и h e ig h t определяют ш ирину и высоту
видео в качестве постерного изображения области отображения видео (также известной как область
для представления этого видео. Если вы уда­ просмотра). Если вы зададите значение для p o s t e r , то по-
лите атрибут a u to p la y , то будете наблю­ стерное изображение будет подвергаться масштабированию
дать данное изображение, пока не нажмете в соответствии с указанными вами ш и р ино й и высотой.
кн о п ку воспроизведения. Браузер сам Видео также будет масштабироваться, но сохранит соотно­
решает, какой кадр показывать; зачастую шение ш ирины и высоты (например, 4:3 или 16:9), поэтому
он просто показывает первы й кадр видео... при наличии дополнительного пространства по бокам либо
ко торы й нередко оказывается полностью сверху и снизу видео станет выводиться в ТВ-формате L etter
черным. Если вы хотите, чтобы в данном Box либо P illa r Box с целью п одгонки под размеры области
случае выводилось определенное изобра­ отображения видео. Вы должны стараться обеспечивать со­
жение, вам потребуется создать его, а затем ответствие родным размерам видео, если требуется наилуч­
задать, используя атрибут p o s te r . шая производительность (браузеру не придется заниматься
масштабированием в режиме реального времени).
Т В -ф ор м ат P illar Box 773-ф орм ат L e tte r Box
loop, ко то р ы й представляет собой еще один
л огический атрибут, обеспечивает автомати­
ческий повтор воспроизведения видео после
> —
того, как его проигры вание завершается.
■ в □
388 глава 8
телевидение для нового поколения

Элементы управле­
ния в каждом браузере выглядят
по-разному; хотя при использова­
нии решений вроде Flash в их внеш­
нем виде, по крайней мере, наблюда­
лась согласованность.

Да, элементы управления отображением


HTML-видео в каждом из браузеров вы­
глядят по-разному.
В неш ний вид ваших элементов унравления
определяю т те, кто реализует браузеры. Эле­
менты управления зачастую выглядят неоди­
наково в разны х браузерах и онерационны х
системах. В н екоторы х случаях, н ан ри м ер
на план ш етн ом ком пью тере, они долж ны
выглядеть и вести себя по-другому, носкольку
само устройство работает иначе (и хорош о,
что об этом за вас уже позаботились). Вместе
с тем мы понимаем, что в случае, скажем, на­
стольных браузеров было бы ненлохо иметь
согласованно выглядящие элементы унравле­
ния, однако все это не является формальной
частью специф икации HTML5. В некоторы х
ситуациях нодход, работаю щ ий в одной оне-
р а ц и о н н о й систем е, м ож ет расходи ться с
основны м и н ри н ц ин ам и и н те р ф ей са поль­
зователя другой ОС. П росто знайте, что эле­
менты унравления могут различаться, а если
вами будет двигать глубокая м отивация, то
м ож ете реали зовать пользовательские эле­
м енты унравлен ия для своих нрилож ени й .

Этим мы займемся позже...

дальше ► 389
обзор форматов видео

Три разных формата


Что необходимо знать видео, используемых
о форматах видео в основных браузерах.
Э то контейнер..
Н ам бы хотелось, чтобы все было четко ...содер­
и ясно, как в случае с элементом v id eo и его { жащий
атрибутами, но, как оказалось, с форматами закоди­
видео в И н терн ете небольш ой беснорядок. Контейнер WebM рованные
Что же такое ф орм ат видео? М ожно рассма­ видео-
Видео,
тривать его следующим образом: видеоф айл закодированное и аудио-
содерж ит две части —видео и аудио, н ри этом кодеком VP8 ^ данные.
каждая из них закодирована (чтобы умень­
ш ить разм ер и обеснечить возмож ность бо­ Аудио,
закодированное
лее эф ф ективного воснроизведения файла) кодеком Vorbis
с иснользованием онределенного кодека.
Кодек в больш инстве случаев м ож ет оказы­
ваться тем, с чем будут согласны далеко не
все, — одни разработчики браузеров отдают Видео,
Контейнер Ogg
нредночтение кодеку Н.264, вторы м очень закодированное
кодеком Н.264 Видео,
нравится VP8, а третьи лю бят альтернатив­ закодированное
кодеком Theora
ные реш ения с откры ты м исходным кодом,
нанрим ер T heora. Все это еще больше услож­ AAC Audio
няется тем, что файл, содерж ащ ий закоди­ Encoding Аудио,
закодированное
рованны е с номощью онределенного кодека кодеком Vorbis
видео- и аудиоданные (он назы вается кон­
тейнером) , им еет собственны е ф орм ат и имя.
Таким образом, у нас нолучается настоящ ая
меш анина из технических терм инов.
У нас мог бы быть больш ой и счастливый
У вас может быть
другое мнение на
t
Каждый формат вклю ­
мир, если бы все разработчики браузеров до­ ф этот счет , посколь­ чает тип контейнера
говорились между собой о едином ф орм ате ку предпочитаемые (например j VJebM, МР4-,
для иснользования в И н терн ете, но, нохоже, форматы имеют Ogg) и используемых ви­
этого не случится, и на то есть ряд техниче­ тенденцию меняться део- и аудиокодеков (на­
ских, политических и ф илософ ских нричин. со временем. прим ер , VP8 , Vorbis).
Однако вместо того чтобы откры вать здесь
дискуссию, мы нросто ностараемся дать вам
достаточны й объем знаний но этой теме,
чтобы вы смогли нриним ать собственные
СпецификацияHTML5допускает
реш ения о том, как обеснечить ноддержку
для своей целевой аудитории.
прпмепеппелюбогоформатавпдео.
Д авайте взглянем на наиболее нопулярны е
кодеки. В настоящ ее врем я существуют три
Всезавпсптотреализациибраузера,
сонерника, нытаю щ ихся нравить м иром
(И нтернета)...
котораяиопределяет, какиеформа­
тыдействительноподдерживаются.
390 глава 8
телевидение для нового поколения

Претенденты
Если вы собираетесь ноставлять содерж имое для ш ирокого круга пользователей, то вам нри-
дется предусмотреть наличие видеоф айлов более чем одного формата. С другой стороны , если
вы нацеливаетесь, нанрим ер, только на пользователей A pple iPad, возможно, вам удастся обой­
тись лиш ь одним ф орм атом видео. В настоящ ее врем я существуют три основны х нретендента.

Контейнер M P4 с Видео Н . 2 6 4 Контейнер 1Л/еЬМ с Видео


и аудио ААС VP8 и аудио Vorbis
Н .2 6 4 л и ц е н з и р о в а н г р у п п о й M P E G -L A .
W e b M б ы л с о з д а н к о м п а н и е й G o o g le
С у щ е с т в у е т б о л е е о д н о г о т и п а Н .2 6 4 , дл я и спо л ь зо в ан и я в со четан ии с вид ео,
ка ж д ы й из ко то р ы х и зв ес те н как закодированны м с пом ощ ью V P8.
проф иль.
W e b M /V P 8 п о д д е р ж и в а е т с я б р а у з е р а м и
М Р 4 /Н .2 6 4 п о д д е р ж и в а е т с я б р а у з е р о м F ir e fo x , C h r o m e и O p e r a .
S a f a r i и In te r n e t E x p lo r e r в е р с и и 9 и в ы ш е
В и д ео ф ай л ы в ко нтей н ер н ом ф о р м ате
Т а кж е и м е етс я п о д д е р ж ка со с то р о н ы W ebM им ею т р асш и рени е W E B M .
н е к о то р ы х в е р с и й б р а у з е р а C h ro m e .

Контейнер Ogg с Видео Theora


и аудио Vorbis
Theora. А л ьт ер­

Я64
T h e o ra — это ко д е к с о ткр ы ты м нативное решение
ИСХОДНЫМ КОДОМ. н _ ^Ь им ец с от крыт ым исход­
В и д е о , з а к о д и р о в а н н о е с его п о м о щ ь ю , индустрии, но не ным кодом.
о б ы ч н о с о д е р ж и т с я в O g g -ф а й л е , правящий чемпион ...
ко то ры й и м е ет р асш и р е н и е O G V.

O g g /T h e o r a п о д д е р ж и в а е т с я б р а у з е р а м и
F ir e fo x , C h r o m e и O p e r a .

г
VPS — претендент , за спи-
ной которого стоит Google,
при эт ом поддерживается
браузерами других разра­
ботчиков и набирает силу...

дальше ► 391
управление форматами видео

Как Жонглировать всеми этими форматами...


Итак, в мире ф орматов видео присутствует н екоторы й беснорядок, но что нам делать? В зависимости
от ваш ей целевой аудитории вы мож ете реш ить обеснечить наличие видео только в одном ф орм ате
либо в нескольких. В любом случае вы сможете иснользовать один элемент < s o u rc e > (не путать с атри­
бутом src) на каждый ф орм ат внутри элем ента < v id e o > , чтобы обеснечить набор видеоф айлов, каждый
из которы х будет иметь свой собственны й формат, и дать возмож ность браузеру вы бирать видеоф айл
именно в том форм ате, которы й он ноддерживает. Н анример:

Обратите внимание, что мы удаляем ■■■и добавляем мри тега <source>, каж­
ат рибут src из тега <video> ... дый из которых имеет собственный Л
атрибут src, указывающий путь к ви­
деофайлу в отличающемся формате.
I г
< v id e o s r c = " v i d e o / p r e r o l l .m p4" id = " v id e o "
p o s te r = " v id e o / p r e r o llp o s t e r . jp g " c o n t r o ls
w id t h = " 4 8 0 " h e i g h t = " 3 6 0 ">
< s o u rc e s r c = " v id e o / p r e r o l l. m p 4 " >
< s o u rc e s r c = " v id e o / p r e r o ll. w e b m " >
< s o u rc e s r c = " v i d e o / p r e r o l l . o g v ">
< p > S o rry , y o u r b ro w s e r d o e s n 't s u p p o r t th e v id e o e le m e n t< /p >
< / v id e o > горюхи и двигается
г x ‘
браузер натИ^ Ы[Л, Ст файл в форма
Сообщение, которое выведет вниз, пока не о воспроизвести.
браузерл если он не поддер­
живает элемент video. \
3 случае с каждым <source> браузер загружа­
ет метаданные видеофайла, чтобы проверить,
сможет ли он его воспроизвести (этот процесс
бывает длительным, однако его можно облегчить
КЛЮЧЕВЫЕ ^ЛЯ
йраУзеРа " слЛ' бедующ ую страницу)
МОМЕНТЫ
Я
Контейнер — это формат файлов, используемый для «упаковки» видео-, аудио- и ме­
таданных. Среди распространенных контейнерных форматов можно назвать MP4, WebM,
Ogg и Flash Video.

Кодек — это программный инструмент, используемый для кодирования и декодирования


видео и аудио в определенном формате. К числу популярных веб-кодеков относятся Н.264,
VP8, Theora, ААС и Vorbis.

Браузер сам решает, какое видео он сможет декодировать. При этом среди разработчиков
браузеров нет согласия относительно единого формата видео, поэтому если вы хотите
обеспечить поддержку для каждого пользователя, вам придется позаботиться о наличии
видеофайлов в нескольких форматах.

392 глава 8
телевидение для нового поколения

Как обеспечить еще большую конкретизацию для своих форматов видео


Сообщив браузеру местонолож ение своих ф айлов-источников, вы даете ему набор различны х вариан­
тов, из которы х он сможет вы брать нодходящ ий. Однако веб-обозревателю нридется нровести кое-ка-
кое «расследование», нреж де чем у него нолучится точно онределить, сможет ли он воснроизвести со­
ответствую щ ий файл. Вы мож ете номочь своему браузеру, сообщив ему дополнительную инф орм ацию
о тине MIME и (онционально) о кодеках ваших видеофайлов:
файлj путь к которому вы Параметр codecs определяет,
указываете в src, на самом деле какие кодеки были использо-
является контейнером , содержа- влны для кодирования видео Видеокодек
щим фактическое видео (и аудио, и аудио с целью создания за - л
а также метаданные). ^ кодированного видеофайла / Аудиокодек
* I S»
< s o u rc e s r c = " v i d e o / p r e r o l l . o g v " t y p e = ' v id e o / o g g ; codecs= :" t h e o r a , v o r b is " '>

J
type является опциональным Это тип MIME видео- Обратите внимание на двойные
атрибутом , который вы­ файла Он определяет кавычки вокруг значения параметра
ступает в роли подсказки контейнерный формат, codecs. Они подразумевают , что
для браузера , помогающей ему значение атрибута type нам следует
понять , сможет ли он воспро­ заключить в одинарные кавычки.
извести данный тип файла.
Мы можем обновить наш и элементы <source> с целью вклю чения в них и нф орм ации о тине
для каждого из трех тинов видеоф айлов, которы е у нас имею тся, как но казано далее:

< v id e o i d = " v id e o " p o s t e r = " v i d e o / p r e r o l l p o s t e r . jp g " c o n t r o ls w id t h = " 4 8 0 " h e i g h t = " 3 6 0 ">


< s o u rc e s r c = " v i d e o / p r e r o l l .m p4" t y p e = ' v id e o /m p 4 ; c o d e c s = " a v c l. 42E01E, m p 4 a . 4 0 .2 " '>
< s o u rc e s r c = " v id e o / p r e r o ll. w e b m " t y p e = ' v id e o /w e b m ; c o d e c s = "v p 8 , v o r b i s " '>
< s o u rc e s r c = " v i d e o / p r e r o l l . o g v " t y p e = ' v id e o / o g g ; c o d e c s = " th e o r a , v o r b is " '>
< p > S o rry , y o u r b ro w s e r d o e s n 't s u p p o r t th e v id e o e le m e n t< /p >
< / v id e o > Значения параметра codecs в случае с MP4 будут
f более замысловатыми, чем в случае с двумя осталь­
Если вы не будете знать значений ными контейнерными форматами , поскольку ко­
параметров codecs, можете о т ­ дек Н.Я64 поддерживает разнообразные профили
бросить их и указать только тип с настройками кодирования видеофайлов для разных
MIME. Это обеспечит чуть меньшую пользователей (например , у одних из них может
эффективность , однако, по большей иметься канал с высокой пропускной способностью,
частиj все будет в порядке. а у других - с низкой). Таким образом , чтобы задать
здесь правильные значения, вам необходимо знать
подробности о том, как видео было закодировано.

Когда вы будете разбираться с кодированием видеоф айлов, вам нридется узнать подроб­
ности о разнообразны х вариантах нарам етров ty p e для иснользования в вашем элементе
< s o u rc e > . Д ополнительную инф орм ацию о данны х нарам етрах вы сможете найти но адресу
h t t p : / / w ik i. w h a t w g . o r g / w i k i/ V i d e o _ t y p e _ p a r a m e t e r s .

дальше ► 393
вопросы о кодировании и воспроизведении видео

Ч а с т°

Задаваем ы е
B o llp o C b l

видео для последующего размещения в Интернете. Если


f t * ™ . — вы собираетесь заняться серьезной обработкой видео,
жайшие несколько лет мы придем к единому контей­ используйте программы Final Cut Pro или Adobe Premiere,
нерному формату или типу кодека? Разве на это не в которых имеются встроенные производственные инстру­
указывает наличие у нас стандартов? менты. Наконец, если вы хотите осуществлять доставку
свого видео посредством сети Content Delivery Network
Q j Вряд ли в ближайшее время появится формат, кото­ (CDN), то знайте, что многие CDN-компании также предла­
рый станет господствующим над всеми остальными. Как гают услуги по кодированию. Таким образом, у вас имеется
мы уже отмечали, данная тема пересекается с целой мас­ широкий выбор разнообразных вариантов.
сой сложностей, начиная с компаний, желающих контроли­
ровать свою судьбу в сфере видео, и заканчивая комплекс­ Могу ли я воспроизводить свое видео в полно­
ными проблемами с интеллектуальной собственностью. экранном режиме? Удивительно, что в соответствую­
Комитет по стандартам HTML5 осознал это и решил не щем API-интерфейсе нет свойства для этого.
определять формат видео в спецификации HTML5. Таким
образом, несмотря на то что HTML5, в принципе, поддер­
Q j Данная функциональность еще не была стандарти­
живает (или, по крайней мере, агностически воспринимает)
зирована, однако в Интернете можно найти способы вос­
все эти форматы, в действительности разработчикам брау­
производить полноэкранное видео с помощью некоторых
зеров решать, что они будут, а что не будут поддерживать.
браузеров. Часть браузеров предусматривают наличие

Следите за этой темой, если видео имеет для вас большое элемента управления для проигрывания видео во весь
значение; за ней, несомненно, будет интересно наблюдать экран (например, на планшетных компьютерах), который
ближайшие несколько лет, пока специалисты будут со всем наделяет данной возможностью элемент v id e o . Однако
этим разбираться. И, как всегда, принимайте во внимание после того, как вы найдете способ воспроизводить видео
потребности своей целевой аудитории и обязательно в полноэкранном режиме, список того, что с ним можно
делайте все возможное, чтобы обеспечить для них соот­ будет сделать помимо простого проигрывания, может
ветствующую поддержку. оказаться ограниченным по соображениям безопасности
(как это бывает с видеоплагинами).

С чего мне начать, если я захочу заняться коди­


рованием собственного видео? А как насчет звука в моем видео? Можно ли ис­
пользовать API-интерфейс для управления уровнем
громкости?
Q j Существует масса программ для захвата и кодиро­
вания видео. А уж какую из них вам выбрать, зависит от
типа видео, захват которого вы хотите производить, и того, Q j Конечно можно. Вы можете присваивать свойству
как вы собираетесь использовать конечный результат. На v o lu m e значение с плавающей точкой в промежутке
тему кодирования видео написаны книги, так что будьте от 0 . О (звук отключен) до 1 . О (максимальная гром­
готовы войти в мир новых акронимов и технологий. Вы кость звука). Просто используйте объект v i d e o для
можете начать с несложных программ вроде iMovie или задания значения для этого свойства в любое время:
Adobe Premiere Elements, которые позволяют кодировать v id e o .v o lu m e = 0 . 9 ;

394 глава 8
телевМ е н и ед л я н о ап
° п°коления

* 4 .

Щь
ВАША СЛЕДУЮЩАЯ МИССИ Я: c o b e p iu e h u o
РАЗВЕДКА ПОДДЕРЖКИ ВИДЕО С ЕК РЕТН О
ВАМ ПОРУЧАЕТСЯ ОПРЕДЕЛИТЬ Т Е К У Щ И М У Р О В Е Н Ь ПОДДЕРЖКИ ВИДЕО
В КАЖДОМ ИЗ ПРИВЕДЕННЫХ НИЖЕ Б Р А У З Е Р О В (ПРИМЕЧАНИЕ: НУЖНУЮ ИНФОРМАЦИЮ
ВЫ СМОЖЕТЕ О Т Я С К А Т Ь ПО АДРЕСАМ HTTP: //E N .W IK IP E D IA .O R G /W IK I/H T M L 5 _
V ID E O , HTTP://CANIUSE.COM/#SEARCH=VIDEO)
ПРИНИМАЙТЕ ВО ВНИМАНИЕ НОВЕЙШИЕ В Е Р С И И БРАУЗЕРОВ. ПО КАЖДОМУ Б Р А У З Е Р У ,
ПРИВЕДЕННОМУ В С Т О Л Б Ц Е «ВИДЕО/БРАУЗЕР», ОТМЕТЬТЕ ВИДЕОПАРАМЕТРЫ, К О Т О Р Я Е
ОН ПОДДЕРЖИВАЕТ. ПО ВОЗВРАЩЕНИИ ПРЕДСТАВЬТЕ ОТЧЕТ ДЛЯ П О Л У Ч Е Н И Я Н О В О Г О
ЗАДАНИ Я!

Устройства под управлением операционных


систем iOS и Android (среди прочих)
Ч'

дальше ►
Нет проблем.
Существует ряд методик для п ереклю чения на другой
проигры ватель видео, если тот, которы й вы нредно-
читаете (будь то проигры ватель видео HTML5, или
Flash, или другой), не поддерж ивается.
Н иж е вы найдете прим ер того, как можно вставить
свое Flash-видео в качестве резервного содерж имо­
го, заменяю щего НТМЬБ-видео в ситуациях, когда
браузер не знает, как воспроизвести НТМЬб-видео.
Ясно, что данная область быстро меняется, ноэтому
заглядывайте в И н терн ет (в котором разм ещ ается
более свежая инф орм ация, чем нриводим ая в кни­
гах), чтобы использовать новейш ие и наилучшие
методики. Вы также сможете найти снособы сделать
резервны м не Flash-видео, а НТМЬБ-видео, если
п редпочтете отдавать п ри ори тет Flash-видео.

< v id e o p o s t e r = " v id e o . j p g " c o n t r o ls >


< s o u rc e s r c = " v id e o .m p 4 " >
< s o u rc e s r c = " v id e o .w e b m " >
< s o u rc e s r c = " v id e o . o g v ">
< o b je c t > . . .< /o b je c t>
< / v id e o >

Вставьте свой элемент <object>


в элемент <video>. Если браузер
не узнает элемент <video>, то буде
использоваться элемент <object>.
телевидение для нового поколения

Я слышал, там будут A PI-интерфейсы?


Как вы видите, иснользуя разметку и элемент
< v id e o > , можно много чего сделать. Однако эле­
мент < v id e o > также нредоставляет нам богаты й
API-интерфейс, которы й можно иснользовать для
реализации всевозмож ны х интересны х новедений
и взаимодействий, связанны х с видео. Вот краткая Вызывайте эти методы
сводка некоторы х методов, свойств и собы тий эле­
м ента < v id e o > , которы е могут вас заинтересовать воспроизводит ваше
(их исчерпы ваю щ ий неречень вы найдете в специ­ play видео
ф икации):
ставит ваше видео
pause
на паузу

load загружает ваше видео

используйте эти свойства canPlayType помогает программно


определить , какие типы
видео вы сможете вос­
videoWidth loop произвести

videoHeight muted

currentTime paused

duration readyState

¥
ended seeking
&
г error volume
Это свойства объекта эле­
мента <video>. Одним из них ^П ер ехв аты вай те эти события
вьч можете присваивать зна­
чения (например, loop и muted),
другие же предназначены play abort
только для чтения (например,
currentTime и error). pause waiting

progress loadeddata
Это события, которые вы сможете
обрабатывать, если захотите, до­ error loadedmetadata
бавив обработчики событий, вызов
которых будет происходить при timeupdate volumechange
наступлении события, прослушива­
ние которого вы ведете. ended

дальше ► 397
как работает плейлист

Немного «программирования» содержимого Webville TV


До настоящ его момента у нас но Webville TV демонстрировалось только
одно видео. Нам бы хотелось запрограм м ировать раснисание, но кото­
рому будет воспроизводиться нлейлист видеоф айлов. Донустим, в случае
с Webville TV нам требуется сделать следующее:

Показать аудитории небольшое предварительное


шоу, ну там, знаете, рекламу «кока-колы» и попкорна,
правила поведения для зрителей и т. д.

7 /и h i m l’ cf Ouulilij

£% Показать наш первый ролик под названием «Попу-


лярны ли вы?» (Are you Popular?). Поверьте, он вам
понравится.

А затем показать гвоздь нашей программы — полно­


Пункт нашчения - цветный фильм «Пункт назначения — планета Зем­
планета Земля ля» (Destination Earth). Созданный Американским
институтом нефти, какой же посыл он в себе несет?
Посмотрите — и узнаете.

Возьми в руку карандаш


У вас может возникнуть соблазн взглянуть на спецификации разметки < v id e o > ; чтобы узнать,
как определить плейлист. Что ж, для этого вам потребуется код, поскольку элемент < v id e o >
позволяет определять только одно видео. Если бы вы находились на необитаемом острове и
вам требовалось реализовать плейлист исключительно с использованием браузера, элемента
< v id e o > , свойства s r c , методов lo a d и p la y , а также свойства ended, то как бы вы сделали
это (у вас есть возможность использовать любые типы данных JavaScript, какие пожелаете)?

Подсказка: событие ended наступает, когда


видео достигает конца и его воспроизведе­
ние завершается. К а к и в случае с любым
другим событием, у вас может иметься подсматривайте
обработчик, вызов которого будет происхо - решение этого у п р а ж -
дить при наступлении данного события. нения!

398 глава 8
телевидение для нового поколения

в о з ь м и в руку карандаш
Решение У вас может возникнуть соблазн взглянуть на спецификации разметки
< v id e o > , чтобы узнать, как определить плейлист. Что ж, для этого вам потре­
При загрузке страницы мы буется код, поскольку элемент < v id e o > позволяет определять только одно
генерируем массив playlist, видео. Если бы вы находились на необитаемом острове и вам требовалось
запускаем воспроизведение реализовать плейлист исключительное использованием браузера, элемента
первого видео и задаем обра­ < v id e o > , свойства src, методов lo a d и p la y , а также свойства ended, то как
ботчик событий, иницииру­ бы вы сделали это (у вас есть возможность использовать любые типы данных
JavaScript, какие пожелаете)? Вот наше решение этого задания:
емых, когда воспроизведение
видео завершается. ^

Mbi сохраним плейлист в виде


Псевдокод плейлиста массива. Каждый элемент в нем
будет представлять собой видео
для воспроизведения.
Создать массив playlist с видео
Извлечь v id e o из объектной модели
документа (DOM).
<iS'
Задать обработчик событий в отношении £

v id e o ДЛЯ обработки События " e n d e d " .

*
£
&
Создать переменную p o s i t i o n = о. /Qj ft
Задать в качестве источника видео &
ПОЗИЦИЮ О В p l a y l i s t .
Массив playlist
Воспроизвести видео.

Каждый раз, когда воспроиз­ Вот наш обработчик, который


ведение видео завершается, вст упит в дело по завершении
Собы тие наступает событие ended... воспроизведения видео.
ended

Псевдокод обработчика
...что приводит
со бы ти й ended
к вызову обработчи­ Увеличить значение p o s i t i o n на 1.
ка событий ended.
Задать в качестве источника видео Дойдя до конца плей­
следующую ПОЗИЦИЮ В p l a y l i s t листа, мы можем
Воспроизвести следующее видео либо остановиться,
либо снова вернуться
к первому видео.

дальше ► 399
реализация плейлиста

Реализация плейлиста Webville TV


Тенерь мы воспользуемся JavaScript и API-интерф ейсом Video для реализа­
ции плейлиста Webville TV. Н ачнем с добавления ссылки на JavaScript-файл
в w e b v i l l e t v . h t m l ; нросто добавьте данную строку в элемент <head>:

< s c r ip t s r c = " w e b v ille tv . js " > < /s c r ip t >

И удалите эту строку из имею щ егося у вас элем ента <video>:

< v id e o c o n t r o ls a u t o p l a y s r c = ffv i d e o / p r e r o l l .m p411 w id th = " 4 8 0" h e ig h t = " 3 60"

p o s t e r = " im a g e s /p r e r o llp o s te r . jp g " id = " v id e o " > ^ Удаляем атрибуты autoplay


< / v id e o > ’S и src из тега <video>.
Также удалите все элементы <source>, с кото­
рыми вы, возможно, экспериментировали.

А тенерь создайте новы й файл с именем webvilletv. js. К роме того, давайте
онределим ряд глобальных нерем енны х и функцию, которая будет вы зы ваться
носле нолн ой загрузки страницы:

Сначала определим переменную, чтобы следить за тем, какое


^ видео мы воспроизводимj мыприсвоим ейимя position.
v a r p o s itio n = 0;
va r p la y lis t; -------- Еще нам потребуется переменная для размещения массива
var
.,
v id e o ;
playlist
г ^
с видео.
^ ' А также переменная для размещения ссылки на элемент video.

w in d o w .o n lo a d = f u n c t i o n () { М ы создадим массив playlist с тремя видео.


p l a y l i s t = [ " v i d e o / p r e r o l l .m p 4 ",
" v id e o / a r e y o u p o p u la r .m p 4 ",
" v id e o /d e s tin a tio n e a r th .m p 4 " ] ;
v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v id e o " ) ;£ Извлекаем элемент video.
v i d e o . a d d E v e n t L is t e n e r ( " e n d e d " , n e x tV id e o , fa ls e ) ;

И добавляем обработчик событии ended для video. Да, это


выглядит иначе, чем мы привыкли (потерпите немного —
мы поговорим об этом на следующей странице).
v id e o .s r c = p l a y l i s t [ p o s i t i o n ] ;
Теперь мы задаем для scr значение
v id e o , lo a d () , g виде первого видео.

v i d e o . p l a y () ; И з а г р у Ж а е м э т о

} чего воспроизводим его!

400 глава 8
телевидение для нового поколения

Так что там с кодом того обработчика событий?


Раньш е мы всегда нросто нрнсванвали функцию обработчика, вызываемую н ри наступлении соответ­
ствующего собы тия, свойству (нанрим ер, o n lo a d или o n c l ic k ) , как ноказано далее:
video.onended = nextVideo;
Однако на этот раз мы собираем ся ностунить немного но-другому. Почему? А нотому, что на момент
нанисания книги ноддерж ка всевозмож ны х свойств собы тий в объекте v id e o была немного неравно­
мерной. Э тот недостаток даст нам возможность п родем онстрировать еще один снособ регистрации,
касаю щ ийся событий: a d d E v e n tL is te n e r , которы й является общим методом, ноддерж иваемы м многи­
ми объектами для реги страци и в случае с различны м и событиями. Вот как он работает:
о ^ , (Ьинкиия которую мы будем вызывать при
Вы можете использовать метод addEventListener wy ч > rv а * события
для добавления обработчика событий. наступлении соотве у Щ
■I'
^ video.addEventListener ("ended11, nextVideo, false) ;

Объект, на Событие, прослушивание которого


котором м« ,« ведем. Обратите внимание на то. контролирует про-
прослцшиваем что мы не ставам on перед именем Хинцтяе методы п о у е н и * событии,
х а Г Г если задано значение true. Всегда зада-
определенное события, как в случае с обработчика- „ „ с , ,
тбьнллие . ■> байте здесь значение false (если только
сооытие ми, при задании которых использцем л ~
о ~ п , I ,\ вы не пишете продвинутый код),
свойства (например, onload). Г
Помимо того факта, что нрим енение метода a d d E v e n tL is te n e r является немного более замысловатым,
чем н ростое добавление обработчика нутем присваивания функции свойству, он работает во многом
так же. Итак, вернем ся к нашему коду!

Как написать обработчик «конца видео» ^ Данный обработчик


1 * * не будет вызывать -
Н ам осталось лиш ь нанисать обработчик для собы тия ended, наступающего нри ся, если пользова -
заверш ении военроизведения видео. Вызов данного обработчика будет нроис- тель поставит
ходить каждый раз, когда видеонроигры ватель будет достигать конца текуще- видео на паузу либо
го видеоф айла. Вот как мы наниш ем функцию n e x tV id e o (добавьте ее в файл если видео воспроиз-
w e b v i l l e t v . j s ): водится в зациклен -
f u n c t i o n n e x tV id e o () { Г Сначала увеличиваем по- ном режиме (что
J зицию в массиве playlist. можно обеспечить,
p o s itio n + + ; ъадав соответ­
if ( p o s itio n >= p l a y l i s t . le n g t h ) {
ствующее значение
свойства loop).
Q По достижении конца плейлиста мы про -
p o s itio n , возвращаемся в его начало, для чего
} задаем для position значение О.
v id e o .s r e = p la y lis t [p o s itio n ]} ^ — Теперьа л ы задаелл в качесп/\ве источника

следующее видео, которое будет воспроиз-


v id e o , lo a d () ; водить проигрыватель.
v i d e o . p l a y () ; Наконец, загружаем и запускаем
воспроизведение следующего видео.

дальше ► 401
тестирование плейлиста

Еще один тест-драйВ ...


Вы мож ете новерить, что мы готовы к тест-драйву?
Все, что мы сделали, — это воспользовались соответ­
ствующим API-интерфейсом , чтобы обеснечить ви­
део для воснроизведения, носле чего нозаботились
о наличии слушателя собы тий, готового к обработке
ситуации, возникаю щ ей но заверш ении нроигры ва-
н и я видео (что он и делает нутем зануска воснроиз­
ведения следующего видео в нлейлисте). Убедитесь,
что вы внесли необходимы е изм енения в свой HTM L-
файл, нанечатайте новы й JavaScript-код и нроведите
тест-драйв.

Все работает! Но как мы


решим, какой формат видео
воспроизводить, когда будем исполь­
зовать код для загрузки
источника видео?

Хороший вопрос.
Когда мы использовали множ ественны е теги < s o u rc e > , мы мог­
ли рассчиты вать, что браузер пройдется но одному или более
форматам видео и решит, сможет ли он воснроизвести какой-
либо из них. Теперь при использовании кода мы нросто даем
элементу v id e o единственны й вариант выбора. Так как же нам
проверить и узнать, какие ф орм аты видео ноддерж ивает брау­
зер, чтобы убедиться в том, что мы обеснечили наиболее нод-
ходящ ий из них?
Для этого мы можем воспользоваться методом c a n P la y T y p e объ­
екта v id e o . Он приним ает ф орм ат видео и возвращ ает строку,
которая дает понять, насколько браузер уверен в том, что он смо­
ж ет воспроизвести данны й тип видео. Существуют три стенени
уверенности: вероятно, может быть, уверенности нет. Д авайте бо­
лее пристально взглянем на canPlayType, а затем доработаем код
нашего плейлиста, чтобы задействовать в нем данны й метод.
ТВы почесываете затылок , произнося:
«Вероятно? Может быть?
А почему этот метод не возвращает true или false»? С нами было
то же самое! Через несколько мгновений вы узнаете , что под всем
эт им понимается...
402 глава 8
телевидение для нового поколения

Как работает метод canPlayType


О бъект v id e o предусматривает наличие метода c a n P la y T y p e , которы й мож ет онределять, насколько вы­
сока вероятность того, что вам удастся воспроизвести тот или и н ой ф орм ат видео. М етод c a n P la y T y p e
нриним ает то же самое онисание ф ормата, которое вы иснользовали в случае с тегом < s o u rc e > , и воз­
вращ ает одно из трех значений: нустую строку, "maybe" или "p ro b a b ly " . Вот как осущ ествляется вызов
c a n P la y T y p e :
^ ' п е р е д а д и м только краткое описание Будет возвращена пустая
Если в качестве результата с м о ж е м строка, если браузер поймет,
формата, то что не сможет воспроизве­
получить лишь " ” или " maybe". сти видео.
video.canPlayType ("video/ogg") Будет возвращена строка
"maybe", если браузер по­
video.canPlayType('video/ogg; codecs="theora , vorbis"')
считает, что ему, возможно,
удастся воспроизвести видео.
t Будет возвращена строка
Однако если мы передадим определенный тип с кодеком , "probably", если браузер будет
то сможем получить в ответ "maybe" либо " probably ". уверен в том, что сможет
воспроизвести видео.
О братите внимание, что браузер будет уверен больше, чем "m a y b e ", только £ ит рейт — это коли -
в том случае, если вы наряду с тином MIME укажите значение нарам етра чеСтво битов, которое
co d e c s . Также обращ аем ваше внимание на то, что возвращ аемого зн ачен ия браузеру необходимо
" I 'm a b s o l u t e ly s u re " не существует. Даже если браузер знает, что сможет успевать обрабаты -
воспроизвести тип видео, но-нрежнему не будет никаких гарантий, что он вать за единицу вре-
сможет воспроизвести фактическое видео: нанрим ер, битрейт видео мож ет мени чтобы декодиро-
оказаться слишком высоким и браузеру не удастся декодировать его. ^ вать видео и корректно
использование canPlayType отобразить его.
Мы собираем ся иснользовать c a n P la y T y p e для онределения того, какой ф орм ат видео будет прим е­
няться в случае с видео Webville TV. Вы уже знаете, что у нас имею тся три версии каждого файла: MP4,
WebM и O g g , и в зависимости от иснользуемого вами браузера одни из них будут работать, а другие нет.
Создадим новую функцию, которая будет возвращ ать расш ирение ф айла (" .m p 4 ", " .webm" или " . o g v " ),
нодходящ ее для вашего браузера. Мы станем указывать только тины MIME (" v id e o /m p 4 " , " v id e o /
webm" и " v id e o / o g g " ) без зн ачен ий c o d e c s , ноэтому возможны ми возвращ аемы ми зн ачен ия у нас будут
"m aybe" или нустая строка: M ы знаем , что сможем получить на­
зад только значение "maybe" либо пустую
f u n c t i o n g e tF o r m a tE x te n s io n () { строку, поэтому сможем удостовериться
лишь в т о м j что в случае с нашим соот­
i f ( v i d e o . c a n P la y T y p e ( " v id e o / m p 4 " ) != ) { ветствующим типом не окажется воз­
r e t u r n " .m p 4 " ; вращена пустая строка.
} e ls e i f ( v id e o . c a n P la y T y p e ( "v id e o /w e b m " : " " ) { \^М ы будем проверять каждый
r e t u r n " .webm" ; — из типов и возвращать со­

} e ls e i f ( v id e o . c a n P la y T y p e ( " v id e o / o g g " ) ответствующее расширение


') {
^ файлаj если браузер скажет:
re tu rn . ogv"
«Я может быть , и смогу его
T
При большинстве вариантов использования , если воспроизвести»,
вы не будете знать значений codecs , вполне доста­
точно будет уверенности " maybe ".
дальше ► 403
снова разбираемся с форматами

интеграция функции getFormatExtension

Тенерь нам необходимо внести ряд изм енений в функции w in d o w .o n lo a d и n e x t v id e o с целью задей­
ствовать g e tF o r m a tE x te n s io n . Сначала мы удалим расш ирения файлов из ф айловы х имен в плейлисте
(носкольку вместо этого мы будем нрим енять g e tF o r m a tE x te n s io n для их вы яснения), а затем вызовем
g e tF o r m a tE x te n s io n там, где мы задали свойство v i d e o . s r c :

w in d o w .o n lo a d f u n c t i o n () { Удалите расширения файлов.


p la y lis t : [" v id e o /p r e r o ll" , Теперь мы будем выяснять
" v id e o / a r e y o u p o p u la r " , их программным пут ем .
" v id e o / d e s tin a tio n e a r th " ] ;
v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " ) ;
v i d e o . a d d E v e n t L is t e n e r ( " e n d e d " , n e x t v i d e o , f a l s e ) ; y ' И конкатенируйте резуль­
v id e o .s r c = p l a y li s t [ p o s i t i o n ] + g e tF o r m a tE x te n s io n () т ат getForm atExtension
v id e o . lo a d ( ) ;
с файловым именем ис­
точника нового видео.
v id e o .p la y ( ) ;
}

И нроделайте то же самое в n e x tv id e o :
f u n c t io n n e x t v i d e o () {
p o s itio n + + ;
if ( p o s i t i o n >= p l a y l i s t . le n g t h ) {
p o s itio n = 0; Здесь мы делаем то
} же самое — конка­
тенируем результат
v id e o .s r c = p l a y li s t [ p o s i t i o n ] + g e tF o r m a tE x te n s io n ()
getForm atExtension
v id e o . lo a d ( ) ;
с файловым именем
v id e o .p la y ( ) ; источника видео.

U проведение mecm-драйва...
Добавьте функцию c a n P la y T y p e и внесите п родем онстриро­
ванны е чуть выше изм енения, носле чего перезагрузите свой
файл w e b v i l l e t v . h t m l . Ну как, работает? Тенерь ваш код сно- h ttp ://(o c a lh

собен вы яснять наиболее нодходящ ий формат. Если вы захо­


тите узнать, какое видео выбрал браузер, нонробуйте добавить
код a l e r t в функции w in d o w .o n lo a d и n e x tv id e o ; внесите его
в ниж ню ю часть каждой функции носле v i d e o . p l a y ( ) :

a l e r t ( " P la y in g " + v id e o . c u r r e n tS r c ) ;

К акой файл воснроизвел ваш браузер?

404 глава 8
телевидение для нового поколения
_ Часщо

^адаБ аеМ ы е
Б о Ц р о сьх

< s o u rc e > в объекте v id e o (как если бы вы набрали их в своей


Если я программно задаю источник своего видео и разметке). Благодаря этому у вашего объекта v id e o будет не­
canPlayType возвращает «maybe», но воспроизведение все сколько вариантов на выбор, и вам не придется заниматься напи­
же не происходит, как это можно исправить?
санием более сложного кода для обработки ошибок. Мы не станем
делать этого в данной главе, однако знайте о таком способе дать
О Исправить это можно двумя путями. Первый состоит в том, вашему объекту v id e o несколько вариантов на выбор, причем


чтобы перехватывать соответствующую ошибку и предоставлять посредством кода, а не разметки.
объекту v id e o другой источник (о перехвате ошибок мы поговорим
в конце главы). Второй заключается в использовании объектной
модели документа (DOM) для написания сразу нескольких тегов
^ V epG ° ° g /e Chrome
Вам может пот ребо­
ват ься уст ановит ь
Ii ] ) У Д ь т е c Целью обеспечен ^ ” ия
Quicktime для воспроиз­
ведения видеоф айлов °С 2 Ц о р о ^ Н ы ! ПаСНОСти- °'
с расширением MP4 Данные ограничения не пп
дыне
в браузере Safari. торые операции vid e o + T ™ ™ * * * °овеРШать не'ко
Программа Quicktime Ч ^ у и и Цу какфТс°(тТ ^ Г Г ' * * * £ ?
дет выглядеть как ?,) ваш и ^ - а д р ес бу-
зачастую устанавливается по умолчанию,
но если она все же не была инсталлирована, главы Кр К МЫ 6удвМ ПостУпать Т о с ^ ’ //)з Подоб"о
вы можете загрузить ее отсюда: http://www.
apple, com/quicktim e/do wnload/.

5 3 г = 3 5 £ Й £ г
Убедитесь, что с вашего сервера загружаю т ся видеоф айлы, имеющ ие
коррект ны й т ип MIME .
О
Независимо от того, используете вы свой собственный локальный сервер или
^ Д ь ш е выполняете приложение, задействуя видео с онлайн-сервера, нужно удосто­
вериться в том, что с сервера поступают видеофайлы с корректным типом
MIME. В противном случае они не смогут работать должным образом.
Если вы работаете в операционной системе Mac OS или Linux, то, скорее всего, используете Apache.
Вы можете модифицировать файл h t t p d . c o n f (если у вас имеется корневой доступ) либо создать
файл .h ta c c e s s в каталоге, где располагаются ваши видеофайлы, и добавить в него следующие
строки:
A ddType v id e o / o g g . ogv
A ddType v id e o /m p 4 . mp4

A ddType v id e o /w e b m . webm

Этот код сообщит серверу, как подходить к загрузке файлов с данными расширениями.
Вы можете установить Apache в операционной системе Windows и произвести аналогичные манипу­
ляции. В случае с серверами IIS рекомендуем заглянуть в онлайн-документацию Microsoft и найти там
«Конфигурирование типов MIME в IIS» (Configuring MIME types in IIS).

дальше ► 405
наше послание вам

Я неустанно твержу, что здесь речь идет не


только о JavaScript... Необходимо видеть общую
картину. Создание веб-приложений подразумева­
ет использование разметки, CSS, JavaScript
и его АР1-интерсрейсов.

В какой-то момент нам уже придется относиться к вам как к настоящим разработчикам.
В этой книге мы (надеемся) номогаем вам делать каждый шаг —мы находимся рядом, чтобы
нодхватить вас, нреж де чем вы унадете, и убедиться в том, что в вашем коде были расставле­
ны все точки над i. Однако быть настоящ им разработчиком номимо всего остального означа­
ет нонимать код, нанисанны й другими людьми, уметь увидеть главное за массой второстеп ен ­
ных деталей и разбираться в запутанности того, как все объединяется в одно целое.
В оставш ейся части главы мы нредоставим вам возмож ность сделать все это. Далее нриведен
нрим ер, которы й наиболее близок к реальному веб-нриложению из всего того, что нам до­
водилось видеть до настоящ его момента, нри этом он вклю чает массу составны х частей, ак­
тивное иснользование API-интерф ейсов и большое количество кода, которы й обеснечивает
обработку множ ества реальны х деталей. Тенерь мы не можем разбирать каждую часть, разъ­
ясняя вам каждый нюанс, как обычно это делали (иначе книга разрослась бы до 1200 стра­
ниц); мы и не хотим этого делать, но скольку вам необходимо н риобретать навы ки объедине­
н и я всех кусочков «мозаики» без нас.
Н е беснокойтесь, носкольку мы но-нрежнему будем рядом и расскажем, что именно делать,
однако вы долж ны учиться восприним ать код, читать его, разбираться в нем, а затем донол-
нять и изменять его для того, чтобы он делал то, что вам необходимо. Таким образом, на про­
тяж ении следующих трех глав мы хотим, чтобы вы ногрузились в нриводим ы е нрим еры ,
изучили их и «вбили» код себе в голову. Да... вы к этому готовы!

406 глава 8
телевидение для нового поколения

Нам требуется Ваша помощь!


Свежая новость... мы но лучили контракт на создание программного обеснечения комнании
Starring You V ideo для их новы х видеокабинок. Ч то это такое? Это новейш ие кабинки с нод-
д ерж кой HTM L5 для заниси видео со общений: клиент заходит в уединенпую кабинку и записы ­
вает свое видеосообщ ение. Затем он сможет разнообразить свое видео, иснользуя настоящ ие
киноэф ф екты ; в его распоряж ен и и будет сения-фильтр Old-tim e western (С ения), черно-белый
фильтр Film n o ir (О чень тем ны й) и даже фильтр не от м ира сего Sci-fi (И н верти рован ное ви­
део). П осле этого клиент сможет отнравить свое сообщ ение другу. Мы реш или действовать и
взяли на себя обязательство создать видеои н терф ейс и систему обработки видеоэф ф ектов.
Однако есть одна нроблема. Видеокабинки не будут достунны в течение следующих ш ести не­
дель, а когда они нрибудут, код уже долж ен быть готов. Таким образом, мы за это время соби­
раемся обзавестись демоблоком с частичной функциональностью и несколькими тестовы ми
видеоф айлами и нанисать весь код, иснользуя их. Когда мы закончим, реб ята из Starring You
Video смогут нросто н рим енить наш код к только что снятому реальному видео. И, конечно же,
не забы вайте, что сделать все это нам необходимо с иснользованием HTML5.
И так, мы надеемся, что вы с нами, но скольку мы ноднисали контракт!

Заходите, снимайте видео, стилизуйте


его и отправляйте своим друзьям.

дальше ► 407
исследуем видеокабинку starring you video

Заходите В Видеокабинку, и даВайте осмотримся...


Н иж е ириведеи наш демоблок с и нтерф ей сом пользователя. Там им еется видеоэкран, на котором поль­
зователи смогут просм атривать свое видео. У них будет возмож ность н рим енить фильтр (нанример,
Old-tim e w estern или Sci-fi) и но смотреть, как он работает, но еле чего они смогут отнравить видео дру­
зьям. Возможность заниси видео у нас нока отсутствует, ноэтому мы предусмотрели наличие тестовы х
видеоф айлов, с которы м и можно будет работать. Н аш а нервая задача —обеснечить работоспособность
кнонок, а затем мы займемся нанисанием видеоф ильтров. П реж де чем мы нристуним, взгляните на
интерф ейс:
Интерфейс демоблока. 8 центре располагается
окно проигрывателя для просмот ра видео.

Применяйте свой любимый Элементы управления , чт о­ Выбирайте тестовое видео.


эффект : O ld -tim e w estern , бы воспроизводить> ставить Иаил демоблок предлагает
Film n o ir или Sci-fi. на паузу и проигрывать на выбор два таких видео.
видео в зацикленном реж им е ,
а также отключать звук.

408 глава 8
телевидение для нового поколения

РаспакоВка демоблока
Н а следующий день наш демоблок был доставлен самолетом, и настало врем я
раснаковать его. П охоже, что мы нолучили функциональны й блок с уже нани
санной нростой HTM L-разметкой и JavaScript-кодом. Д авайте сначала взглянем
на HTM L ( v id e o b o o t h . h tm l) . Внереди вас ждут несколько страниц «заводского»
кода, нросм отром которого мы займемся, а затем нерейдем к настоящему коду.
J T HTMLS ■ конечно же ^ оме м о г^ вся стилизация
<! doctype html> ОЫЛа сделана 3(Х H a d Вот СО -
<html lang=Mе п п> ответствующий CSS -файл.
<head> J д вот Ja va S crip t-файл, который нам
<title>Starring YOU Video Booth</title> потребуется для размещения большей
<meta charset="utf-8"> части написанного кода. Чуть позже мы
Clink rel=Mstylesheet" href = пvideobooth, c s s 11> /"взглянем на него более подробно, и, п о -
<script src= "videobooth. j s nx / s c r i p t > ^ хоже, что они уже написали здесь код для

-
</head> контроля над кнопками в интерфейсе.
<body> Вот главный интерфейс, где у нас имеется сама консоль,
<div id= "booth”> которая разделена на область отображения видео и панель
<div id="console"> Управления с тремя наборами кнопок, сгруппированных
<div id="videoDiv"> Y- в "effects", "controls" и "videoSelection".
<video id="video" w idth=n720" height=" 480мX / video>
</div>
*ч _ Они уже установили видеопроигры­
<div id=" dashboard" > ватель. это хорошо, поскольку он
<div id="effects"> нам понадобится.
<a class="effect" i d = " n o r m a l " X / a >
<a class="effect" i d = " w e s t e r n " X / a >
<a class="effect" i d = " n o i r " X / a >
\ Вот все эффекты
Это всего лишь H TM L-якоря.
<a class="effect" id=" scifi" X / a >
О привязке к ним мы пого­
</div> J ворим чуть позже...
<div id="controls">
<a class="control id="play"X/a>
<a class="control id=" pause" Х / а >
И элементы управления
<a class="control id="loop"X/a>
проигрывателем
<a class="control id="mute"X/a>
</div>
<div i d = "videoSelection">
<a class="videoSelection" id="videol"></a> И два демовидео для
<a class="videoSelection" id="video2"></a> тестирования
</div>
</div>
</div>
</body>
</html>

дальше ► 409
рассмотрение имеющегося кода

Рассмотрение остальной части «заВодского» кода


Тенерь взглянем на весь JavaScript-код, которы й мы нолучили с «завода», вклю чая код
для конф игурирования кнонок (мы только что его рассматривали в соответствующ ем • - S
HTM L-файле) и код для каждого обработчика кнонки (которы й на текущий момент
заботится о том, чтобы назад «отжимались» именно те наж атые кнонки, что и пужно).
Мы рассмотрим весь этот код нрежде, чем начнем добавлять свой собственны й код.

А сейчас переходим k JavaScript...


Д авайте откроем JavaScript-файл ( v id e o b o o th , j s ) . П охоже, что все кнонки в и н терф ей се работают,
нросто они но ка не делаю т ничего интересного. Мы знаем, как они сконфигурированы , но скольку эти
кнонки будут вызы вать код, которы й нам необходимо нанисать (нанример, для воснроизведения видео
или для нросм отра видео с нрим енением фильтра, обеснечиваю щ его тот или и ной эф ф ект).
Чуть ниж е вы найдете функцию, вызов которой нр о исходит но заверш ении загрузки страницы . В слу­
чае с каждым набором кнонок ( " e f f e c t s " , " c o n t r o ls " и " v id e o s e le c t io n " ) код нроходится но кнонкам
и нрисваивает обработчики собы тий c l i c k якорны м ссылкам. Д авайте взглянем на это:
функция, которая будет вызываться
Каждый оператор
после полной загрузки страницы
совершает цикл по
w in d o w .o n lo a d = f u n c t i o n () { ^
элементам одной
v a r c o n t r o lL i n k s = d o c u m e n t. q u e r y S e l e c t o r A l l ( " a . c o n t r o l " )
из группы кнопок.
f o r ( v a r i = 0 ; i < c o n t r o l L i n k s . l e n g t h ; i+ + ) {
c o n t r o l L i n k s [ i ] . o n c l i c k = h a n d le C o n t r o l; "f 3 случае с оЬраЬотчи -
} ком onclick для каждой
кнопки в элементах
v a r e f f e c t L i n k s = d o c u m e n t. q u e r y S e l e c t o r A l l ( " а . e f f e c t " управления проигрыва­
f o r ( v a r i = 0 ; i < e f f e c t L i n k s . l e n g t h ; i+ + ) { телем задается обра­
e f f e c t L i n k s [ i ] . o n c lic k = s e t E f f e c t ; ^ . ботчик handleControl.
} случае с обработчиком
ля effects задается setEffect.
v a r v id e o L in k s = d o c u m e n t. q u e r y S e l e c t o r A l l ( " a . v i d e o S e le c t io n "
f o r ( v a r i = 0 ; i < v i d e o L i n k s . l e n g t h ; i+ +I-) {
v i d e o L i n k s [ i ] . o n c l i c k = s e tV id e o ; ^ ^ ^ наконец, в случае с обра-
} ботчиком для videoSelection
задается setVideo.
p u s h U n p u s h B u t to n s ( " v id e o l" , []); < r Сделав всю подготовительную работ у, мы исполь­
p u s h U n p u s h B u tto n s ( " n o r m a l" , []); зуем вспомогательную функцию, чтобы визуально
« о т ж ат ь» назад кнопки "v id e o l" и "norm al" (без
применения фильтров) в интерфейсе.

С методом d o c u m e n t. q u e r y S e le c t o r A ll вы ранее не сталкивались; он аналогичен


d o cu m e n t.g e tE le m e n ts B y T a g N a m e , за исклю чением того, что вы осущ ествляете выборку
элементов, соответствующ их селектору CSS. Д анны й метод возвращ ает массив объектов
элементов, соответствующ их аргументу в виде указанного селектора CSS.
v a r e le m e n tA r r a y = d o c u m e n t. q u e r y S e l e c t o r A l l ( " s e l e c t o r " ) ;

410 глава 8
телевидение для нового поколения

Взгляд на обработчики кнопок


Итак, JavaScript-код заботится о конф игурировании всех кнонок, чтобы н ри щелчке
нользователя на них нроизош ел вызов соответствующ его обработчика. Д авайте взгля­
нем на ф актические обработчики, начав с обработчика для кнонок нроигры вателя
(Play (В оснроизведение), Pause (Пауза), Loop (В оснроизведение в зацикленном реж и­
ме) и M ute (О тклю чить звук)), и носмотрим, что они делают:
Первое, что мы делаем в данном обработчике, это вы­
ясняем, кто совершил вызов обработчика, для чего извле­
каем идентификатор элемента, который это сделал.
f u n c t i o n h a n d le C o n t r o l (е) { ^
v a r id = е . t a r g e t. g e tA ttr ib u te (" id " ) ; Выяснив идентификатор j мы узнаем,
какой элемент это был: "play", "pause",
"loop" или "mute".
if ( i d == " p la y " ) {
p u s h U n p u s h B u tto n s ( " p la y " , [" p a u s e " ]) В зависимости от того, какая это
окажется кнопка, мы изменим инт ер-
} e ls e i f ( i d == " p a u s e " ) { . фейс, чтобы он отражал нажат ую
p u s h U n p u s h B u tto n s (" p a u s e " , [" p la y " ]) кнопку. Например, если была нажата
кнопка Pause (Пауза), — в этом случае
} e ls e i f ( i d == " lo o p " ) { кнопка Play (Воспроизведение).
i f ( is B u tto n P u s h e d ( " l o o p " )) {
p u s h U n p u s h B u tto n s ( " " , [ " l o o p " ] ) , Мы используем вспомогательную
} e ls e { функцию, чтобы позаботиться о со­
p u s h U n p u s h B u t to n s ( " lo o p " , [ ] ) ; стояниях кнопок на экране, с именем
} pushUnpushButtons, которая приним а­
} e ls e i f ( i d == "m u te ") { ет значение id нажатой кнопки наря­
if ( is B u tto n P u s h e d ( " m u t e " ) ) { ду с массивом значений id ненажатых
p u s h U n p u s h B u tto n s ( " " , [ " m u t e " ] ) , кнопок и обновляет интерфейс с целью
} e ls e { отражения в нем данного состояния.
p u s h U n p u s h B u tto n s (" m u te " , [];
к
f
} Разные кнопки обладают разной семан­
} тикой. Например, Play (Воспроизведе­
Весь эт от показанный код является косм ет и­ ние) и Pause (Пауза) подобны настоящим
ческим и лишь изменяет внешний вид кнопок радиокнопкам, в то время как Mute
с нажатого состояния на ненажатое. У нас (О т клю чит ь звук) и Loop (Воспроизведе­
пока от сут ст вует код для выполнения чего- ние в зацикленном режиме) сродни кно п­
то реального, например для воспроизведения кам -переключателям.
видео. Его нам и предстоит написать.

Все это, конечно, здорово, однако где будет располагаться наш код? Д авайте нодумаем: когда пользова­
тель нажмет кнонку, нанрим ер Play (В оснроизведение), нам не только пужно будет обеснечить обнов­
ление и н терф ей са (для чего у нас уже им еется код), но и предусмотреть вы нолнение дополнительного
кода, которы й действительно что-то делает, нанрим ер запускает воснроизведение видео. Д винемся
дальше и взглянем на два других обработчика (для задания видеоэф ф ектов и тестового видео), и вам
станет внолне ясно (если уже не стало), где именно будет располагаться наш код...

дальше ► 411
задание обработчиков кнопок

Обработчики setEffect и setVideo


О бработчик s e t E f f e c t обрабаты вает ваш выбор эф ф екта: нанрим ер, нрим еняем ы е эф ­
ф екты могут вообщ е отсутствовать (нри вы боре "n o rm a l") либо быть " w e s te rn " , " n o ir " или
" s c i f i " . Аналогичным образом, обработчик s e tV id e o обрабаты вает ваш вы бор тестового
видео нод ном ером 1 или 2:
Он работает т ак же, как обработчик
kandleControl: мы извлекаем идентифи­
катор осуществившего вызов элемента
fu n c t io n s e tE f fe c t ( e ) { (кнопки, кот орую нажал пользователь),
v a r id = e . t a r g e t. g e tA ttr ib u te (" id " ) ; а затем соответствующим образом
обновляем интерфейс.
i f ( i d == " n o r m a l" ) {
А здесь будет
p u s h U n p u s h B u tto n s ( " n o r m a l" , [ " w e s t e r n " , " n o i r " , " s c i f i " ] ) ; располагаться
наш код.
} e ls e i f ( i d == " w e s t e r n " ) {
p u s h U n p u s h B u tto n s ( " w e s t e r n " , [ " n o r m a l" , " n o ir " , " s c if i" ] ) ;

} e ls e i f ( i d == " n o i r " ) {
p u s h U n p u s h B u tto n s ( " n o i r " , [ " n o r m a l" , "w e s te rn ", " s c if i" ] ) ;

} e ls e i f ( i d == " s c i f i " ) {
p u s h U n p u s h B u tto n s ( " s c i f i " , [ " n o r m a l" , "w e s te rn ", " n o ir " ] ) ;

}
3 каждом случае мы добавим код для об­
работки реализации соответствующего
фильтра, обеспечивающего спецэффекты.

То же самое справедливо и для setVideo;


мы выясняем, какая кнопка была нажата,
и обновляем интерфейс.
f u n c t i o n s e t V id e o (е) {
v a r id = е . t a r g e t. g e tA ttr ib u te (" id " ) ;
i f ( i d == " v i d e o l " ) {
p u s h U n p u s h B u t to n s ( " v id e o l" , [ " v i d e o 2 " ] ) ;
} e ls e i f ( i d == " v id e o 2 " ) {
p u s h U n p u s h B u tto n s ( " v id e o 2 " , [ " v i d e o l " ] ) ;
}

Мы также добавим сюда код


для реализации переключения
между двумя тестовыми видео.

412 глава 8
телевидение для нового поколения
И не забывайте, что если вы не хотите
набирать приводимый в книге код, може-
А Bom U 8 СП0 М 02 <1ГП6 ЛЬНЫ6 функции те целиком загрузить его, посетив адрес
h ttp ://w ic k e d ly sm a rt.c o m /h fh tm ls.
И для нолноты (либо если вы соверш аете 11-часовой н ерелет на Фиджи, не имея н ри
этом достуна в И нтернет, и у вас возникло ж елание заняться набором всего этого кода):
pushUnpushButtons забот и т ся о состояниях кнопок. Он п рини ­
м а е т ар гум ен т ы в виде значения id кнопки, кот орая будет в ы ­
глядет ь нажатой, а также значения id одной или более кнопок Сначала мы убеж даем ся в т о м ,
в массиве, которые б уд ут выглядеть ненажатыми. ч т о значение id кнопки для н а -
f u n c t i o n p u sh U n p u sh B u tto n s (id T o P u sh, idA rrayT oU npush) { , Ж ат ия не я вляет ся п у с т ы м .
if ( id T o P u s h != " " ) { < п .
И з в л е к а е м э л е м е н т a n c h o r с ис~
v a r a n c h o r = d o c u m e n t . g e t E l e m e n t B y l d ( id T o P u s h ) ; п о л ь з о в а н и е м данного значения id...
v a r t h e C l a s s = a n c h o r . g e t A t t r i b u t e ( " c l a s s ") ; 4---------- ...и и зв л е к а е м а т р и б у т class.
if (! t h e C l a s s . i n d e x O f ( " s e l e c t e d " ) > = 0 ) { Мы « н а ж и м а е м » кн опку n y -
^ ^ „ lff „ ___________ т е м добавления класса "s e l e c t e d "
th e C la ss = th e C la ss + " s e le c te d " ; c r ----------✓-
л / & a n c h o r и...
a n c h o r . s e t A t t r i b u t e (" c l a s s ", th e C la ss);
v a r n ew lm age = " u r l ( i m a g e s / " + i d T o P u s h + " p r e s s e d . p n g ) " ;
a n c h o r . s t y l e . b a c k g ro u n d lm a g e = n e w lm a g e ; бы OHO пбрбКрЫЛО
} . .. о * « > в л « м ф о н о во е oSpa.WM. « “ У
’ 9 c P1
“ ИНГ „ 3
"° е" % Э е « С о д “ » в < .~ е .« С р а ж е н u t ■ p a ^ p r e s s e «
Чтобы кнопки выглядели нена-

жатыми, мы соверш аем цикл по


fo r (v a r i = 0; i < id A r ra y T o U n p u s h . l e n g t h ; i+ + ) { * \ м а с с и в у з н а ч е н и й i d кнопок, K O -
a n c h o r = d o c u m e n t. g e tE le m e n tB y ld (id A rra y T o U n p u s h [ i ] ) ; т орые должны приобрести такой
вид, извлекая каждый anchor...
th e C la s s = a n c h o r . g e t A t t r i b u t e ( " c l a s s " ) ; x
••-Уоеждаемся,
что кнопка действи -
if ( t h e C la s s . in d e x O f ( " s e l e c t e d ” ) > = 0 ) { К мельно нажата (если это так, mo
th e C la s s = th e C la s s . r e p la c e ( " s e le c t e d ” , " " ) ; У Hee & уд ет и м е т ь с я к ла с с " s e le c te d ." )..,

a n c h o r . s e t A t t r i b u t e ( " c la s s " , t h e C la s s ) ; ■■■Удаляем " se le c ted " из c la ss...

a n c h o r . s ty le .b a c k g r o u n d lm a g e = " " ;
^ ...а также удаляем фоновое изо-
} бражение, чтобы мы смогли
} увидеть ненажатую кнопку.

isButtonPushed п р о с т о п р о в е р я е т ,
наж ат а ли кнопка. О н п р и н и м а е т
fj=u n c .t i •o n • т > 4- 4-
is B u t to n PI-»u s 1h e dл/('idл)\ {г id э л е м е н т а anchor...
...извлекает anchor...
v a r a n c h o r = d o c u m e n t. g e tE le m e n tB y ld ( id ) ;
_ _ , I, , ... i
v a r th e C la s s = a n c h o r . g e t A t t r i b u t e ( " c l a s s " ) ;
ff4 ,
^ —
...извлекает class данного anchor . . .

re tu rn ( t h e C la s s . in d e x O f ( " s e l e c t e d ” ) > = 0 ) ; ...и возвращает tru e , если у anchor


} имеется класс “selected".
дальше ► 413
ранний тест

Запах ноВой демомашины...


пришло Время mecm-gpaiiBa!
Мы нанисали не слишком много кода, однако мы читаем
имею щ ийся код и вникаем в него, и это хорош о. И так, за­
грузите ф айл v id e o b o o t h . h t m l в своем браузере и восполь­
зуйтесь кнонками. Х орош енько протестируйте их. Также
добавьте несколько a l e r t в функции обработчиков. П ро­
чувствуйте, как все это работает. Когда вы вернетесь, мы
нристуним к нанисанию кода, которы й заставит кнонки
работать но-настоящему.

Протестируйте все эти кнопки, при этом


обратите внимание на то, что одни из них
подобны радиокнопкам, а другие сродни кноп­
кам - переключателям.

^ .В озьми в руку карандаш


Пометьте, какие из приведенных ниже кнопок подобны пере­
ключателям (то есть являются независимыми), а какие — радио­
решение к данному заданию
кнопкам, когда нажатие одной кнопки будет приводить к тому, что
вы найдете, пролистав
остальные перестанут быть нажатыми). Также напишите рядом с
вперед две страницы .. каждой кнопкой имя соответствующего обработчика. Мы уже сде­
лали это за вас для двух пар кнопок:

Play (Воспроизведение) и Pause (Пауза)


Loop (Воспроизведение в зацикленном режиме)
подобны радиокнопкам и не могут быть
и Mute (Отключить звук) подобны кнопкам-
выбраны одновременно. переключателям и могут использоваться
независимо от других кнопок.
414 глава 8
телевидение для нового поколения

Кажется, я что-то
пропустила... Как вы проводили из­
влечение из элементов <div> с использо­
ванием якорных тегов <а>, чтобы в интер­
фейсе были кнопки?

Все благодаря мощи CSS.


Ж аль, что эта книга не назы вается «Изучаем програм м ирование
на HTM L5 с использованием JavaScript и CSS» (H ead First HTML5
P rogram m ing with JavaScript 8c CSS), но тогда она содерж ала бы
1400 страниц, не так ли? Нас, конечно же, можно было бы угово­
рить написать продвинутую книгу по CSS...
А если серьезно, то мощь разм етки направлена на структуру, a CSS —
на представление (если это новая для вас тема, то загляните в книгу
«Изучаем HTM L, XHTM L и CSS»). То, что мы делаем, не является
таким уж сложным; опиш ем все вкратце для тех, кому лю бопы тно.
Мы задаем карт инку с консолью видеокабинки (без кнопок) в каче-
стве фонового изображения для элемента <div> с id в виде console.

Элемент <video>
располагается
в <diV>j который пс
зиционируется о т ­
носительно консоли
Кром е того , мы
производим абсо­
лютное позициони­
рование элемента
<video>j чтобы он
оказался в центре
консоли.

Мы позиционируем <div> с id Каждый якорь "button" позициониру­


в виде dashboard относительно Каждый элемент <div> ется в <div> для определенной группы
консоли , а затем позициониру­ группы кнопок получает и получает ширину и высоту, чтобы
ем элементы <div> для каждой фоновое изображение для совпадать по размерам с кнопкой ,
группы кнопок относительно всех ненажатых кнопок. которой он соответствует. Когда
панели управления. пользователь щелкнет "b u tto n ", мы
снабдим данный якорь фоновым изо­
бражением нажатой кнопки , которое
Если вам захочется подробно исследовать CSS,
перекроет собой ненажатую кнопку.
загляните в файл videobooth.css.

дальше ► 415
решение упражнения

-.Возьми в руку карандаш


Пометьте, какие из приведенных ниже кнопок подобны переключате­
лям (то есть являются независимыми), а какие — радиокнопкам (когда
нажатие одной кнопки будет приводить к тому, что остальные переста­
нут быть нажатыми). Также напишите рядом с каждой кнопкой имя соот­
ветствующего обработчика. Вот наше решение этого упражнения.

Все эти кнопки подобны Кнопки для выбора


радиокнопкам ; мы даем Play (Воспроизведе­ Loop (Воспроизве­ видео также подобны
пользователю возмож­ ние) и Pause (Пауза) дение в зациклен­ радиокнопкаМу то есть
ность применять к подобны радиокноп­ ном режиме) и Mute за раз пользователь
видео только один э ф ­ кам и не могут (Отключить звук) сможет выбрать
фект за раз. быть выбраны подобны кнопкам -пе­ только одно видео
одновременно . реключателям и м о ­ для просмотра.
гут использоваться
независимо от других
кнопок.

416 глава 8
телевидение для нового поколения

Подготовка
v
демоВидео...
v v l^ bl создадим этот
П реж де чем мы реализуем элементы унравления button, нам нотребуется видео °^ьект &ля разме
для их тестирования, и, как можно судить но кнонкам, сотрудники S tarring You
щения
*
двух
и демо-
Video нрислали нам два демовидео. Создадим объект для разм ещ ения двух видео,
видео. Вскоре мы
вернемся к этому
а затем добавим код для нашего обработчика onload, чтобы задать источник объ­
и объясним вам все
екта video (точно так же, как мы делали в случае с Webville TV).
подробнее.
var videos = {videol: пvideo/demovideolп , video 2 : "video/demovideo 2

Извлекаем элемент video и з а -


w in d o w .o n lo a d = f u n c t i o n () { ^ даем в к а ч е с т в е его и с т о ч н и к а

п е р в о е ви д ео в м а с с и в е , и м е ю -

v a r v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " ) ; \щ е р а с ш и р е н и е , к о т о р о е М ОЖ -

v i d e o . s r c = v i d e o s . v i d e o l + g e tF o r m a tE x te n s io n () ; КО б у д е т в о с п р о и зв е с т и .

v i d e o . l o a d () ; ^ _______________ ^ Затем мы загружаем


видео, благодаря чему
оно будет готово
v a r c o n t r o lL i n k s = d o c u m e n t. q u e r y S e l e c t o r A l l ( " а . c o n t r o l " ) ; л
к проигрыванию , если
fo r (v a r i = 0; i < c o n tr o lL in k s . le n g th ; i+ + ) { пользователь щелк-
c o n t r o lL in k s [ i] .o n c lic k = h a n d le C o n t r o l; нет на кнопке вое -
j произведения.
v a r e ffe c tL in k s = d o c u m e n t. q u e r y S e l e c t o r A l l ( " a . e f f e e t " ) ;
fo r (v a r i = 0; i < e f f e c t L in k s . le n g th ; i+ + ) {
e f f e c t L i n k s [ i ] . o n c lic k = s e t E f f e c t ;
}
v a r v id e o L in k s = d o c u m e n t. q u e r y S e l e c t o r A l l ( " a . v i d e o S e l e c t i o n " ) ;
fo r (v a r i = 0; i < v id e o L in k s . le n g th ; i+ + ) {
v i d e o L i n k s [ i ] . o n c l i c k = s e tV id e o ;
}
p u s h U n p u s h B u t to n s ( " v id e o l" , [] ) ;
p u s h U n p u s h B u tto n s ( " n o r m a l" , [] ) ;
ВН И М АТЕ ЛЬН О ПРО Ч ИТАЙ ТЕ!
Ч тобы не допустить небреж ности, не забы вайте, что в Webville TV есть функция
g e tF o r m a tE x te n s io n , но не этот код! Поэтому открой те файл w e b v i l l e t v . j s ,
сконируйте и вставьте данную функцию в код своего н рилож ения Video Booth.
И еще один небольш ой аснект: в коде Video B ooth у нас нет глобального объ­
екта v id e o , ноэтому добавьте данпую строку в верхню ю часть своей функции
g e tF o r m a tE x te n s io n , чтобы иенравить это:
^ ^ Добавьте данную строку в верхнюю
v a r v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " ) ; 4 a C m t> Ф У ^ Ц и и getForm atExtension.

дальше ► 417
поддержка пользовательских элементов управления видео

Реализация элементов управления Видео Сейнас мы стираемся реали-


зовать все эти кнопки.
П риш ло время заняться кнонками! Важно отметить, что в данном нроекте мы собираемся реализовать
собственные элементы унравления видео. То есть вместо того чтобы иснользовать встроенны е элемен­
ты унравления видео, мы сами будем контролировать данное взаимодействие. Таким образом, когда
пользователям нотребуется воспроизвести, ноставить н а наузу видео, отклю чить в нем звук или даже
н роиграть его в зацикленном реж име, они будут нрим енять наш и пользовательские элементы унравле­
н и я b u t t o n , а не встроенны е. Это также означает, что мы будем делать все это нрограммно с номощью
соответствующ его API-интерфейса. Сейчас мы не собираем ся идти до конца, носкольку это означало
бы реализацию , н анрим ер, кнонок N ext (Далее) и Previous (Назад), смысла в которы х в данном п ри ­
лож ении нет, номы могли бы это сделать при необходимости. Н а нростом нрим ере реализации небольш ой
нанели унравления вы сможете нонять идею и развить ее дальше, если нож елаете.
И так, нристуним. Как насчет того, чтобы начать с кнонки Play (В оснроизведение), а затем двипуться от
нее внраво, к кнонке Pause (Пауза), носле нее —к Loop (В оснроизведение в зацикленном реж им е), а за­
тем —к M ute (О тклю чить звук))? Н айдите обработчик h a n d le C o n tr o l и добавьте туда следующий код:

f u n c t i o n h a n d le C o n t r o l (е) {
v a r id = е . ta r g e t. g e tA ttr ib u te (" id " ) ;
Нам необходима ссылка
v a r v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " ) ;
на объект video.
if ( i d == " p la y " ) {
p u s h U n p u s h B u tto n s ( " p la y " , [" p a u s e " ]) ; Это должно быть довольно просто
i f ( v i d e o . ended) { для вас. Если пользователь щелкнет
v id e o . lo a d () ; \ на кнопке Play ( Воспроизведение),
} то произойдет вызов метода play
v i d e o . p l a y () ; в отношении объекта video.
} e ls e i f ( i d == "p a u s e " ) {
p u s h U n p u s h B u tto n s (" p a u s e " , [" p la y " ]);
Но хот им предупредить, что
здесь имеется один сложный м о ­
} e ls e i f ( i d == " lo o p " ) {
мент , который может оказаться
if ( is B u tto n P u s h e d ( " l o o p " )) {
хлопотным: если бы мы воспроиз­
p u s h U n p u s h B u tto n s ( " " , [ " l o o p " ] ) ;
водили видео и позволили ему п р о ­
} e ls e {
играться до конца, то для того,
p u s h U n p u s h B u tto n s ( " lo o p " , [ ] ) ;
чтобы опять запуст ит ь его, нам
}
сначала пришлось бы снова его
} e ls e i f ( i d == "m u te ") {
загрузить. Мы проверяем, что
if ( is B u tto n P u s h e d ( " m u t e " )) {
видео проигралось до конца (а не
p u s h U n p u s h B u tto n s ( " " , [ " m u t e " ] ) ;
было просто поставлено на паузу),
} e ls e {
поскольку в данном случае нам п о ­
p u s h U n p u s h B u tto n s (" m u te " , [ ] ) ;
требуется лишь снова загрузить
}
его. Если оно было поставлено на
паузу, мы сможем воспроизвести
его, не прибегая к загрузке.

418 глава 8
телевидение для нового поколения

Реализация остальных элементов управления Видео


Реализуем остальные элементы унравления — они настолько нросты ,
что чуть ли не сами могут нанисать свой код:

f u n c t i o n h a n d le C o n t r o l (е) {
v a r id = е . ta r g e t. g e tA ttr ib u te (" id " ) ;
v a r v id e o = d o c u m e n t. g e tE le m e n tB y ld ( " v i d e o " )

if ( i d == " p la y " ) {
p u s h U n p u s h B u tto n s ( " p la y " , [ " p a u s e " ] ) ; Если пользователь пост а­
v id e o . lo a d ( ) ; вит видео на паузу, то бу­
v id e o .p la y ( ) ; дет задействован метод
} e ls e i f ( i d == " p a u s e " ) { pause объекта video.
p u s h U n p u s h B u tto n s (" p a u s e " , [ " p l a y " ] ) ;
v id e o . p a u s e ( ) ; Для воспроизведения видео в за ­
цикленном режиме у нас в объекте
} e ls e i f ( i d == " lo o p " ) { video имеется логическое свойство
if ( is B u tto n P u s h e d ( " l o o p " )) { loop. Мы просто присваиваем ему
p u s h U n p u s h B u tto n s ( " " , [ " l o o p " ] ) ; соответствующее значение...
} e ls e {
p u s h U n p u s h B u tto n s ( " lo o p " , [ ] ) ; ...для чего, чтобы было еще
} интереснее , используем ло­
v id e o .lo o p = ! v id e o .lo o p ; гический оператор ! («не»),
который просто меняет
} e ls e i f ( i d == " m u te ") { за нас логическое значение.
if ( is B u tto n P u s h e d ( " m u t e " )) {
p u s h U n p u s h B u tto n s ( " " , [ " m u te " ] ) ;
з случае с m ute все происходит
} e ls e {
аналогичным образом'- мы п р о ­
p u s h U n p u s h B u tto n s (" m u te " , [ ] ) ;
сто меняем текущее значение
}
свойства m ute , когда пользо­
v id e o .m u te d = ! v id e o .m u t e d ;
ватель нажимает кнопку Mute
(О т клю чит ь звук).
}

Еще один mecm-драйВ!


Убедитесь, что вы внесли в код все нриведенны е выше изменения.
Загрузите v id e o b o o t h . h t m l в браузере и протестируйте элементы
унравления b u t t o n . Вы долж ны видеть, как запускается воснроизве-
дение видео, иметь возмож ность ставить его на наузу, отклю чать в
нем звук и даже нроигры вать его в зацикленном реж име. Вы, конеч­
но же, но ка не сможете вы брать другое демовидео или добавить эф ­
фект, однако вскоре мы дойдем и до этого!

дальше ► 419
разбираемся с событием ended объекта video

ДорабатыВаем один нюанс...


Нам необходимо доработать один небольш ой нюанс, чтобы кнонки действи­
тельно работали так, как надо. Вот вариант иснользования: допустим, вы вос­
производите видео и нри этом не нажали кнонку Loop (В оснроизведение в за­
цикленном реж им е), в результате чего нроигры вание видео осущ ествляется до
конца и затем заверш ается. В силу нашего нодхода к реализации кнонка Play
(В оснроизведение) будет оставаться в нажатом состоянии. А не будет ли лучше, Наша кнопка Play
если она вернется в исходное нолож ение и будет готова к новому нажатию? (Воспроизведение)
пока не является на
Иснользуя собы тия, мы можем легко обеснечить данное нов едение. Н ачнем Ю О % такой, какой
с добавления слушателя собы тий ended. Внесите данны й код в ниж ню ю часть она должна быть.
обработчика onload:

video.addEventListener("ended", endedHandler, false);


Мы задаем обработчик
для события "ended",
Тенерь наниш ем обработчик, вызов которого будет нроисходить который будет вызы­
каждый раз, когда воснроизведение видео будет заверш аться нри ваться по завершении
достиж ении конца видеофайла: воспроизведения видео
(но НЕ когда видео будет
function endedHandler() { ст авиться на паузу!).
Нам нужно лишь
pushUnpushButtons("", ["play"]) сделать т а к , ч т о ­
бы кнопка Play (Вос­
произведение) снова
приобрела ненажатое
состояние. И все!
U еще один mecm-драйВ...
И так, внесите изм енения, сохраните код и перезагрузите страницу. Запустите видео, дайте ему нроиг-
раться до конца и не наж имайте кнонку Loop (В оснроизведение в зацикленном реж им е). В результате
вы долж ны увидеть, как в конце кнонка Play (В оснроизведение) сама вернется в исходное нолож ение.

Кнопка Play (Воспроизведение) вернется в исходное п о ­


ложение сразу же по завершении проигрывания видео.

420 глава 8
телевидение для нового поколения

Переключение меЖду тестовы м и Видео


д н м о в и д ш ) No 2
Мы уже добавили объект для разм ещ ения наш их двух тестовы х ви­

J
део и даже раснолагаем двумя кнонками для вы бора между ними.
Каждой кнонке нрисвоен обработчик setVideo. Д авайте взглянем
на код, которы й нозволит нереклю чаться между этими видео: 4 1 ,
Д1<М 0Ш ЦШ ) \ 1
Вот наш объект с двумя видео, который мы приводим снова
в качестве напоминания, чтобы вы смогли по нят ь, как мы IV 1

собираемся его использовать... ^


var videos = {videol: "video/demovideol", video2: "video/demovideo2"}

function setVideo (e) { д gQM снова т ш 0Ьр а 6 о т т к .

var id = e .t a r g e t .getAtt r i b u t e ("id");

var video = d o c um e n t .getElementByld("video”) ;


О п я т ь -т а к и , нам т ребует ся
ссылка на объект video.

if (id == "videol”) {
З а т е м мы обновляем кнопки
pushUnpushButtons("videol" , ["v i d e o 2 "]);
т е м же п у т е м , что и раньше,
} else if (id == "video2") { никаких изменений здесь нет.
pushUnpushButtons("video2" , ["videol"]);
Д а л ее мы используем id кнопки
(а т р и б ут id элем ент а anchor)
video.src = videos[id] + getFormatExtension();
для извлечения со от вет ст вуй
к - ющего имени видеофайла и
video, load () ; прибавляем расширение, под­
video .pi ay () ; держиваемое нашим браузером.
О бр ат и т е внимание, что мы
применяем скобочную нотацию
pushUnpushButtons("play", ["pause"]); в случае с объектом videos, и с­
пользуя ст року id в качестве
Мы удостоверяемся, что кнопка Play имени свойства.
(Воспроизведение) нажата, поскольку Имея корректный п у т ь
за п у с т и м проигрывание видео, когда к видео и его файловое
пользователь щ елкнет на кнопке для имя, мы загружаем и
выбора нового видео. воспроизводим данный
видеофайл.

Внесите изменения и проведите тест-д р а й в !


Внесите данны е изм енения в вашу функцию
setV id eo , а затем перезагрузите страницу. После
этого у вас долж на ноявиться возмож ность легко
нереклю чаться между источникам и видео.

дальше ► 421
интервью с элементом video

Интервью недели:
Признания элемента video

Head First: Д обро ножаловать, Video. Сра­ Head First: Все это звучит здорово, однако
зу нерейду к вонросу, которы й всех и н тере­ видео требует больших вы числительны х
сует, и заклю чаться он будет в отнош ениях ресурсов для обработки. Я имею в виду, что
между Вами и элементом canvas. н ри этом нроходит огром ны й н оток дан­
Элемент Video: Ч то Вы имеете в виду? ных. Как JavaScript, язы к сценариев, смо­
ж ет сделать здесь что-либо реальное? На-
Head First: Вы якобы кутите ночи н анролет нисание JavaScript-кода — не то же самое,
в вихре удовольствий, завтракаете вместе
что програм м ирование на нативном языке.
но утрам. Нужно ли еще что-то говорить?
Video: О, для вас это будет сю рнризом...
Video: Здесь следует отметить, что у нас с
Вы см отрели носледние тесты производи­
Canvas сложились нрекрасны е взаим оотно­
ш ения. Canvas отображ ает свое содерж и­ тельности JavaScript? Он уже является бы­
мое в весьма п ривлекательной в визуаль­ стрым, и его скорость с каждым днем повы ­
ном плане манере, а я являю сь «рабочей шается. Самые блестящ ие снециалисты но
видеолош адкой». Я разбираю сь с кодеками виртуальным машинам в индустрии уснеш-
и доставляю видеосодерж имое в браузер. но работаю т над этой нроблемой.

Head First: Ч то ж, это не совсем тот от­ Head First: Да, но что с видео? Д ействи­
вет, на которы й я рассчиты вал, но он тельно ли с ним все обстоит так?
меня устраивает. Ладно, элемент canvas
Video: Д ействительно.
нрекрасно снравляется с отображ ением
2Б-граф ики, а Вы —с отображ ением видео. Head First: Н е могли бы Вы нривести нри-
И что? В чем здесь и стинная связь? меры того, что можно сделать с номощью
Video: Как и в любых взаимоотнош ениях, JavaScript, canvas и video?
когда вы объединяете две вещ и и имеете Video: Конечно. Вы мож ете обрабаты вать
на выходе нечто большее, чем сумма двух видео в реж им е реального времени, ин­
частей, то вы нолучаете нечто особенное.
спектировать характеристики видео, из­
Head First: Ч то ж, а не могли бы Вы вы ра­ влекать данны е из видеокадров, модиф и­
зиться более конкретно? ц ировать видеоданные путем, нанример...
Video: Это нростая конценция. Если вы вращ ения, м асш табирования видео или
хотите делать что-то еще номимо обы чно­ даже и зм енения никселов.
го воснроизведения видео (нанример, осу­ Head First: Н е могли бы Вы нам нов едать,
щ ествлять обработку своего видео, либо как это можно сделать в коде?
задействовать пользовательские оверлеи,
либо одноврем енно выводить несколько Video: Я еще верпусь к Вам, чтобы обсу­
видеоизображ ений), то вам нотребуется дить данны й вонрос, мне тут нросто носту-
иснользовать canvas. нил звонок от Canvas... Нужно бежать...

422 глава 8
телевидение для нового поколения

Время спецэффектов
Н е н ора ли нам добавить видеоэффекты ? Мы хотим нрим енять
эф ф екты к нашему оригинальному видео, такие как Film noir, Old-
tim e w estern и даже Sci-fi. Н о если вы взглянете на API-интерф ейс
Video, то не найдете там каких-либо методов для н рим енения эф ­
фектов либо снособов добавить их нанрямую. Так как же мы будем
добавлять эти эффекты ? Мы х о т и м прим енят ь к на ­
Н емного но думайте над тем, как мы могли бы добавить эф ф екты ш ему оригинальному видео
в наше видео. Не беснокойтесь, если вы нока еще не знаете, как такие эф ф ек т ы , как Film
обрабаты вать видео, нросто обдумайте вы сокоуровневы й дизайн. noirj O ld -tim e w estern и Sci-fi.

Starring You Video Используйт е эт и за м ет к и по разработке,


Заметки no разработке... чтобы сделать набросок, пом ет ки или на п и ­
сать псевдокод для любого кода, который о т ­
носится к вашим видеоэффектам. Считайте
это своего рода разминкой для мозга...

Добравшись до пикселов,
К ак вы сможете до­
как вы будете обрабаты­
браться до пикселов,
образующих каждый вать их с целью применения
определенного эф ф екта?
кадр видео?

Как вы сможете от обра­


Д о п у с т и м , вам необхо
зи т ь видео, когда обра­
димо написать функцию
ботаете все его пикселы
для реализации каждого
с целью применения о п р е ­
эф ф ект а, — как она бу­
деленного эф ф екта?
дет выглядеть?

\
идеи напиш ите здесь.

дальше ► 423
план реализации спецэффектов

План реализации спецэффектов


Мы нока не знаем точно, как реализовать эф ф екты , однако
вы сокоуровневы й нлан действий будет выглядеть следую­
щим образом: Кнопки все
еще ждут,
Мы знаем, что нам все еще нужно подключить когда мы их
соответствующие кнопки, которые управляют подключим.
эффектами. Поэтому мы займемся этим в пер­
вую очередь.

Временный буфер,
Мы немного изучим особенности видеообра-
который и н т е ­
ботки и познакомимся с методикой на основе
ресно выглядит...
применения временного буфера для добавле­
ния наших эффектов.
Мы реализуем
Мы реализуем временный буфер, который даст временный буфер,
нам возможность увидеть совместно в дей­ используя canvas
ствии video И canvas. (хо т ит е —
верьте, х о т и ­
т е — нет)!

Мы реализуем по одной функции для каждого function n o i r ( p o s , г, g, b, data) {


эффекта: western, noir И scifi.
}

К ''
Измененные п и к ­
И наконец, мы соединим все воедино и прове­
селы мы будем
дем тестирование! отображать,
как вы уже дога­
дались, в canvas.

lO T W T V P M

Теперь вы знаете, что мы собираемся реализовать функцию, которая будет обрабатывать


каждый эффект. Возьмем, к примеру, эффект Film noir. Как вы будете выбирать тот или
иной цветной пиксел из видео и делать его черным либо белым? Подсказка: каждый пиксел
включает три компонента: г (red — красный), g (green — зеленый) и ь (blue — синий). Если
бы у нас был доступ к этим составным частям, то чтобы мы могли сделать?

424 глава 8
телевидение для нового поколения

Пора обеспечить работоспособность кнопок


для применения эффектов
Сначала легкая часть: мы нодклю чнм соответствующ ие кнонки и сделаем так, чтобы они работали.
Н ачнем с создания глобальной н ерем ен ной effect Function. О на будет содерж ать функцию, которая
сможет извлекать данны е из видео и нрим енять к ним фильтр. То есть в зависимости от желаемого
эф ф екта нерем енная effect Function будет содерж ать функцию, которая знает, как обрабаты вать виде­
оданны е и делать их черно-белыми либо н рим енять к ним сению или инвертирование. Итак, добавьте
эту неременпую в верхню ю часть своего файла:

var e f f e ctFunction = null;

Мы станем нрисваивать этой функции соответствующ ее значение каждый раз, когда пользователь бу­
дет щелкать н а кнонке для н рим ен ен ия эф ф екта. Сейчас мы воспользуемся такими именами функций,
как western, noir и scifi, а сами эти функции наниш ем немного нозже.

8 от снова наш обработчик setEffect. Как вы по м нит е При каждом нажатии кнопки
его вызов происходит всякий р а з>когда пользователь пользоват елем мы будем присва­
щ елкает на кнопке для применения эффекта. ивать переменной effect Function
значение в виде соот вет ст вую щ ей
f unction setEffect (е) { функции (все эти функции нам
var id = е .t a r g e t .g e t A t t r i b u t e ("id" / еще предст оит написать).
Если пользователь
if (id == "normal") { ре ш и т не п р и ­
менят ь э ф ф ек т ы j
pushUnpushButtons("normal", ["western",
то есть выберет
effectFunction = null;
"normal", мы присво­
} else if (id == "western") { им значение null.
p u s h U n p u s h B u t t o n s (" w e s t e r n " , ["normal", "noir", "scifi"])
у
*■— 8 иных случа -
effectFunction = western;
ях мы будем
} else if (id == "noir") { >/ присваивать
p u s h U n p u s h B u t t o n s (" n o i r " , ["normal", "western", "scifi"]) eff ectFunction
effectFunction = noir; значение в виде
имени с о о т ­
} else if (id == "scifi") {
вет ст вую щ ей
p u s h U n p u s h B u t t o n s (" s c i f i " , ["normal", "western", "noir"])
ф ункциил которая
effectFunction = scifi; займ ет ся п р и ­
менением опреде­
Нам по-преж нему нужно написать все эти функции ленного эффекта.
* для применения эффектов. Д авай т е п о см от рим
как осуществляется обработка видео, чтобы мы
смогли п р им енит ь к нему эффекты!

Итак, мы можем нереходить к изучению врем енного буфера, носле чего вернемся и носмотрим, как дан­
ные функции внисы ваю тся в общую картипу и как осущ ествляется их нанисание!

дальше ► 425
обзор процесса обработки видео

Как происходит обработка Видео


Ранее мы обеснечнлн снособ нрнсванвать функцию глобальной н ерем ен ной ef f ectsFunction в резуль­
тате наж атия пользователем кнонок для н рим ен ен ия эф ф ектов в интерф ей се. Сейчас возьм ите эти
сведения и ненадолго отлож ите их у себя в нодсознании, носкольку нам нредстоит заняться тем, как
мы на самом деле собираемся брать и обрабаты вать видео в реж им е реального времени с целью добав­
лен и я эф ф ектов. Д ля этого нам нотребуется «дотяпуться руками» до никселов видео, изм енить их для
достиж ения ж елаемого нами эф ф екта, а затем как-то вернуть на экран.
П редусматривает ли API-интерф ейс Video какой-нибудь снособ обработки видео до того, как оно будет
отображено? Нет. Однако он дает нам снособ добраться до никселов, ноэтому остается лиш ь выяснить,
как их обработать и отобразить. П остойте, никселы? О тображ ение? П омните главу 7? Элемент canvas!
Все верно, ранее мы кое-что уноминали об «особых взаимоотнош ениях», установивш ихся между эле­
ментами video и canvas. Давайте взглянем н а один из снособов, но средств ом которы х элементы video
и canvas могут работать сообща. ^
Подробности сенсационной н о- ^
^

в ости, наконец, раскрыты! )

ф Видеопроигрыватель декодирует (2 ) Видео копируется кадр за кадром


и воспроизводит видео «за кули­ в (скрытый) буферный c a n v a s
сами». и подвергается обработке.

Ц вета оригинального видео


Обработка цветов видео с преобра­
зованием их, например, в черно-бе­
лые, в буферном canvas.

/ З а т е м мы копируем обра­
ботанный кадр из б уф ер ­
ного canvas в canvas о т о ­
бражения.
' Если говорить кратко,
то мы берем каждый
кадр видео и преоб­
р азуем из цветного в
черно-белый, после чего
отображаем его.

© После того как кадр обработан,


он копируется В другой c a n v a s
отображения для просмотра.

426 глава 8
телевидение для нового поколения

Как обрабаты вать Видео с использованием 3 а сценой


Временного буфера
У вас мож ет возникпуть вонрос: ночему мы иснользуем два canvas —для обработки и отображ ения ви­
део. Почему бы нросто не найти снособ обрабаты вать видео н ри его декодировании?
М етодика, которую мы здесь иснользуем, является н роверен н ой и н озволяет м иним изировать визуаль­
ные неноладки во врем я интенсивн ой обработки видео и изображ ений: она известна как использование
временного буфера. Путем обработки кадров видео в буфере с но следующим конированием их всех сразу
в canvas отображ ения мы минимизируем визуальные нроблемы.
П ош агово разберемся, как будет работать наша реализация врем енного буфера.

ф Браузер декодирует видео в серию кадров. Каждый кадр — это


прямоугольник с пикселами, который представляет собой мо­
ментальный снимок видео в определенный момент времени.

Один кадр видео

(3 } П о мере декодирования каждого из кадров мы копируем его


в c a n v a s , который выступает в роли временного буфера.

Целиком копируем кадр в canvas.. ? ^ Временный буфер

дальше ► 427
использование временного буфера

Мы совершаем итерацию по времен­


После извлечения пикселных данных
ному буферу, пиксел за пикселом, из canvas мы обращаемся к ним
передавая на обработку каждый пик­ по одному пикселу зл раз и обра
сел нашей функции e f f e c t F u n c t i o n . батываем их п у т е м м а н и п у л и ­
рования значениями RGB в случае
с каждым пикселом.

После того как все пикселы во вре­


©
менном буфере будут обработаны,
мы скопируем их из временно-бусрер-
ного c a n v a s в c a n v a s отображения.

...мы извлечем изображение \ И конечно же,


Как только данные во временном из временного буф ерно- J это будет canvas,
буфере будут обработаны... го canvas и скопируем все ^ который вы р е ­
в canvas отображения. ально увидите!
Затем мы повторяем данный процесс
для каждого кадра по мере того, как он
декодируется объектом v i d e o .

428 глава 8
телевидение для нового поколения

Реализация временного буфера в canvas


Как вы уже знаете, чтобы реализовать врем енной буфер в canvas, нам необходимо два canvas: нервы й,
в котором мы будем нроизводить свои вы числения, и второй, где будут отображ аться результаты. Соз­
дание этих двух canvas мы начнем в HTM L-файле videobooth.html. О ткройте данны й файл, найдите
там <div> с id в виде "videoDiv" и добавьте два элем ента canvas нод <video>:

<div id="videoDiv">

<video id="video" width="720" height="480"></video>

<canvas id="buffer" width="720" height="480"></canvas>

<canvas id="display" width="720" height="4 8 0 " Ж / canvas>

</div>

Mw добавляем два элемента О брат ит е внимание, что


один
буфера Ка ' д е РЫ*' “грат ь Роль они будут точно такого же
^ “ ем ен” vide°-

Позиционирование элементов video и canvas


У вас мог возникнуть вонрос насчет н озиц и они рован и я данны х элементов; мы собираем ся располо­
ж ить один из них новерх другого. Таким образом, внизу будет располагаться элемент video, новерх
него — буферный canvas (buf f е г Canvas), новерх которого в свою очередь будет находиться canvas
отображ ения (displayCanvas). Мы воспользуемся CSS, чтобы сделать это; хотя мы не слишком много
говорим о CSS в данной книге, если вы откроете videobooth.css, то увидите, как осущ ествляется но-
зи ци он ирован и е этих трех элементов:
Элемент <div> с id в виде videoDiv позиционируется о т н о - ^
div#videoDiv { сительно элемент а, в кот ором он располагается (<div> с id
position: relative; ~~ в виде console), в г г о пикселах от верха и в г я о пикселах
width: 72Opx; от левой границы, в р е зу л ь т а т е чего он оказывается в цен-
'■*------ - т р е элемент а <div> с id в виде console. Д а я w idth и height
height: 48Opx;
мы задаем значения, аналогичные значениям w idth и height
top: 18Opx;
элемент а <video> и двух элемент ов <canvas>.
left: 190px;
<video> является первым э лем ент ом в <div> с id в виде
} videoDiv, по эт ом у он автоматически позиционируется вверху
video { слева в <div>. Мы задаем black в качестве значения цвета фона,
background-color: black; из-за чего при выводе видео в ТВ -ф о р м а т е Letter Box или
} Pillar Box полосы по его краям будут черного цвета.
div#videoDiv canvas {
К двум э лем ент ам <canvas> в <div> с id в виде videoDiv п р и м е ­
position: absolute;
няется абсолютное позиционирование относительно videoDiv
top: Opx;
(их родительского элемента), поэт ом у, позиционируя э л е ­
left: Opx; м ент ы <canvas> в О пикселах от верха и О пикселах от левого
} края, мы располагаем их в т о м же м ест е, что и элементы
<video> и videoDiv.
дальше > 429
реализация обработки кадров

Написание кода для обработки Видео


У нас имеется элемент v id eo , а также буфер, которы й является canvas, и еще один canvas, в котором
будут отображ аться итоговы е видеокадры. К роме того, эти элементы располагаю тся один новерх дру­
гого, в силу чего мы сможем увидеть только верхн ий canvas отображ ения, в котором будет содерж ать­
ся видео с нрим ененны м эф ф ектом . Д ля обработки видео мы воспользуемся собы тием p la y элемента
v id eo , которое инициируется нри запуске во снроизв едения видео. Добавьте данны й код в конец о бра-
ботчика onload: \с.0гда видео начнет воспроиз-
Л водиться, произойдет вызов
v i d e o .addEventListener("play", processFrame, false);
функции processFrame.
В функции processFram e мы будем осуществлять обработку никселов видео и неренос их в canvas для
отображ ения. Н ачнем мы с того, что убедимся в наличии достуна ко всем наш им объектам DOM:
■Сначала мы извлекаем объект video...
function p r o c e s s F r a m e () { /г
var video = d o c u m e n t .g etElementByld("video"); ...и проверяем, продолжается ли все
if (video.paused || video.ended) { ^ еще воспроизведение видео. Если н е т ,
return; то здесь нам больше нечего делать
} и мы просто выполняем return.
var bufferCanvas = document.getElementByld("buffer");
var di splayCanvas = document.getE 1ementByld ("di splay")
Извлекаем ссылку на оба
var buffer = bufferCanvas.getContext("2d");
элемент а canvas и ссыл­
var display = displayCanvas.getContext("2d"); ку на их context, которые
нам потребуются.

Как создать буфер


Д ля создания буфера нам нотребуется взять текущий видеокадр и сконировать его в буферный canvas.
Как только он окаж ется в canvas, мы сможем обработать данны е в этом кадре. Таким образом, чтобы
создать буфер, мы делаем следующее (добавьте данны й код в нижню ю часть processF ram e):
Он п р ини м ает изображение и р и су ет его в canvas
в позиции х, у с заданными шириной и высотой. ■
Помните мет од
На э т о т раз мы извлекаем изображение из видео.
draw lm age объекта
Мы указываем video как источник, и draw lm age
context из главы 7?
получает один кадр соот вет ст вую щ его видео
качестве данных изображения.
b u f f e r .drawImage(video, 0, 0, buffer C a n v a s .w i d t h , b u f f e r C a n v a s .h e i g h t ) ;
var frame = b u f f e r .getlma g e D a t a (0, 0, buffer C a n v a s .width, buffer C a n v a s .h e i g h t ) ;

(Z З1а т е м мы извлекаем данные ^изображения


4— “ ^\ '
из context элемент а canvas и сохраняем Здесь мы просто говорим, что нам т ре-
их в переменной frame, чтобы была воз­ буются все данные изображения в canvas.
можность их обработать.

430 глава 8
телевидение для нового поколения

Как обрабаты вать буфер


И так, мы но лучили кадр видеоданных, но это му давайте обработаем его! Д ля обработки кадра мы будем
соверш ать цикл но каждому никселу в frame.data и извлекать зн ачен ия цветов RGB, содерж ащ иеся в
каждом никселе. Вообще-то никсел им еет четы ре значения — RGB и A lpha (н ен розрачн ость), однако
мы не станем иснользовать Alpha. Получив зн ачен ия RGB, мы вы зовем effect Function (это функция,
о которой мы говорили на с. 426, где нросили вас отложить сведения о н ей у себя в нодсознании!) с ис­
пользованием RGB-инф ормации и кадра.
Добавьте данны й код в ниж ню ю часть функции pro cess Frame:
b u f f e r .drawlmage(video, 0 , 0 , buffe r C a n v a s .w i d t h , displayCanvas.h e i g h t ) ;
var frame = b u f f e r .getIma g e D a t a (0, 0, buffer C a n v a s .w i d t h , displayCanvas.h e i g h t ) ;

Сначала мы выясняем длину frame.data. Следует


var length = f r a m e .data.length / 4; о т м е т и т ь , что данные располагаются в свойстве
frame — fram e.data, a length является свойством
frame.data. На самом деле длина в четыре раза п р е ­
вышает размер canvas, поскольку каждый пиксел
им е ет четыре значения (RGBA).
for (var i = 0; i < length; i++) { Теперь мы совершаем цикл по данным и и з ­
var r = frame.data[i * 4 + влекаем значения RGB в случае с каждым
var g = frame.data[i * 4 + пикселом. Каждый пиксел заним ает четыре
мест а в массиве, поэт ом у мы извлекаем г из
var b = frame.data[i * 4 +
первой позиции, g из второй и b из т рет ьей.
if (effectFunction) {
effectFunction(i, r , g, b, frame.data) ;

}
З а т е м мы вызываем effectFunction (если т о л ь ­
} ко значением соот вет ст вую щ ей переменной
display.putImageData(frame, 0, 0) не окажется null, что бывает, когда пользова­
На данном эт апе обработка frame.data уже т ель нажимает кнопку "normal"), передавая ей
проведена, поэт ом у мы используем мет од позицию пиксела, значения RQB и массив frame,
putlm a geP ata объекта context для размещения data, функция effectFunction обновит массив
данных в canvas отображения. Данный мет од fram e.data, используя новые значения пикселов,
при ним ает данные в fram e и записывает их обработанные в соот вет ст вии с т е м , какая
в canvas в указанную позицию х, у. функция для применения ф и л ьт р а была п р и ­
своена effectFunction.
Мы обработали один кадр, что дальше?
Да, мы т о л ь к о что обработали один-единственны й кадр и хотим нродолж ать об- setT im eout анало-
работку всех кадров, нока будет идти нроцесс воснроизведения видео. Мы можем гичен setlnterval,
иснользовать метод setT im eo u t и нередать ему значение 0 миллисекунд, чтобы дать о>а исключением
указание JavaScript снова вы нолнить processF ram e так быстро, как это будет воз- того, что вы -
можно. Вообще-то JavaScript не станет вы нолнять функцию через 0 миллисекунд, полняется т о л ь -
однако обеснечит для нас самое бы строе следующее врем енное окно. Д ля этого вам ко один раз через
пужно нросто добавить данны й код в нижню ю часть функции processFram e: заданное время
Э т им мы даем иказание JavaScript в миллисекундах.
s e tT im e o u t(p ro c e s s F ra m e f 0 ) ; „ .
снова выполнить processFrame т ак
быстро, как это будет возможно!
дальше ► 431
частота кадров и таймеры

Интересно, что вы используете


setT im eout со значением времени 0.
Что там происходит? Не долж ны л и м ы
делать что-то привязанное к частоте
кадров видео и л и вроде того?

Мы бы хотели, чтобы у нас была такая возможность.


Вы абсолю тно правы: нам бы хотелось, чтобы вызов на­
шего обработчика происходил но одному разу в случае с
каждым кадром, однако API-интерфейс Video не дает нам
это сделать. Он предусматривает собы тие tim e u p d ate, ко­
торое можно использовать для обновления отображ ения
текущего времени вашего видео, однако оно не имеет
тенденции осуществлять обновление с той детализаци­
ей, которую вы мож ете прим енить нри обработке кадров
(другими словами, все будет происходить с более низкой
частотой, чем та, которую имеет видео).
Поэтому вместо этого мы используем setTimeout. П ере­
давая значение 0 методу setTimeout, вы даете указание
JavaScript запускать вы полнение соответствующ его обра­
ботчика так быстро, как это будет возможно.
А мож ет ли это происходить бы стрее частоты кадров?
Н е лучше ли вы числить врем я ож идания близко к требу­
ющемуся в случае с определенной частотой кадров? Это
можно сделать, однако вряд ли обработчик действительно
станет вы нолняться строго с частотой, аналогичной часто­
те кадров вашего видео, ноэтому 0 является нодходящ им
приблизительны м значением. Если вы стремитесь увели­
чить производительность своего нрилож ения, то, конеч­
но же, всегда сможете нрибегпуть к н роф илированию
и вы яснить онтимальны е значения. Но до тех нор, но ка
у нас не н оявится более специф ический API-интерф ейс,
дело будет обстоять именно так.

432 глава 8
телевидение для нового поколения

Займемся написанием эффектов


Н аконец, у нас есть все необходимое для нанисания видеоэф ф ектов: мы извлекаем каждый кадр но мере
его ноступления, обращ аемся к fra m e . d a ta никсел за никселом и отнравляем никселы наш ей функции,
иснользуемой для н рим ен ен ия онределенного фильтра. Д авайте взглянем на ф ильтр Film n o ir (кото­
ры й в нашем варианте нросто является нричудливым названием черно-белого фильтра):

Передаем функции, и с ­ ...значения пикселов


пользуемой для п р и м е ­ красного, зеленого ...а также ссылку на массив
нения ф и л ь т р а , п о зи ­ и синего цвета... frame.data в canvas.
цию пиксела...

>>> является
m
function n o i r ( p o s, r , g , b, data) {
Таким образом, первое,
что мы делаем, — это
вычисляем значение
brightness для данного
поразрядным
—^ var brightness = (3*r + 4*g + b) » > 3; пиксела, взяв за осно­
операт ором,
который сдви­ if (brightness < 0 ) brightness = 0 ; ву все его компоненты
гает биты в (г, b и д).
data[pos 0 ] = brigh t n e s s ;
числовом з н а ­ А за т е м присваиваем
data[pos 1 ] = brightness ;
чении с цельно каждому компонент у
его м одиф и­ data[pos 2 ] = brightness ; в изображении canvas дан­
кации. Ъолее ное значение brightness.
подробно о \
нем вы с м о ­
жете узнат ь
7 Это будет и м е т ь эф ф ект задания
для пикселя значения, обеспечивающего
из справочника Помните, что эта от т енки серого, которые с о о т в е т ­
по JavaScript. функция будет
с т в у ю т общей яркости пиксела.
вызываться по од­
ному разу в случае
с каждым пикселом
в видеокадре!

Tecm-драйв фильтра Film noir


Д обавьте нриведенпую выше функцию в файл v id e o b o o th , j s ,
а затем перезагрузите свою страницу. Как только видео нач­
нет нроигры ваться, наж мите кнонку FILM NOIR, и вы увидите
его в м рачном черно-белом варианте. А тенерь снова наж м ите
NORMAL. Н енлохо, не нравда ли? И все это на JavaScript, в р е­
жиме реального времени!

Т
Вели задуматься, получается в неко­
т ором роде удивительная вещь.

дальше ► 433
упражнение по реализации видеоэффектов

З озьааи в руку карандаш_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


Данная книга не посвящена обработке видео и эффектам, однако это,
несомненно, увлекательная тема. Ниже приведены функции western
и scifi, позволяющие применять соответствующие эффекты. Про­
смотрите код и напишите справа, как работает каждая из них. Кроме
того, мы добавили к ним еще одну функцию — что она делает?

function western(pos, г, g , b, data) {

var brightness = (3*r + 4*g + b) » > 3;

data[pos * 4 + 0] = brightness+40;
data[pos * 4 + 1 ] = brightness+20;

data[pos * 4 + 2 ] = brightness-20;

function scifi.(pos, r, g, b, data) {

var offset = pos * 4;


data[offset] = M a t h . r o u n d (255 - r) ;

data[offset+1] = M a t h . r o u n d (255 - g) ;

data[offset+2] = M a t h . r o u n d (255 - b) ;

function bw ca rtoon(pos, r, g, b, outputData) {

var offset = pos * 4;


i f ( outputData[offset] < 120 ) {

outputData[offset] = 80;

outputData[++offset] = 80;
outputData[++offset] = 80;

} else {

outputData[offset] = 255;
outputData[++offset] = 255;

outputData[++offset] = 255;

}
outputData[++offset] = 255;

++offse t ;

434 глава 8
телевидение для нового поколения

Большой тест-д р айв


В о т и все! Мы заверш или работу над кодом, и он готов

к отнравке в комнанию S ta rrin g You V ideo. Дважды нро-


верьте весь код, которы й вы нанечатали, сохраните его и
загрузите v id e o b o o th , htm l. Затем развлекитесь, ноиграв
со своим новы м нриложением!

Реж им S C I-F I

Реж им W E S T E R N

Р еж и м FILM N O IR

дальше ► 435
В ЛАБОРАТОРИИ
Мы лишь поверхностно затронули тему обработки видео. Увере­
ны, что вы сможете придумать более креативные эффекты, чем
те, которые были продемонстрированы. Придумайте несколько
таких эффектов, реализуйте и задокументируйте их здесь.
Удалось ли вам изобрести и реализовать что-то по-настоящему
классное? Расскажите нам об этом, посетив wickedlysmart.com,
и мы продемонстрируем плоды вашего труда другим читателям!

функция bwcartoon позволяет


делать одну из многих забав­
ных вещей, которые возможны
при использовании функций
для применения эффектов.

436 глава 8
телевидение для нового поколения

Я знаю, что м ы почти подош ли


к концу главы, однако все же хочу сп р о ­
сить: м ы загружали видео из локал ьного файла,
а что изменится, если мое видео будет распола­
гаться в Интернете?

Вам лишь потребуется использовать веб-URL.


Вы мож ете подставить веб-URL вместо любого из источников, которы е мы
определяли локально. Н апример:
<video src="h t t p :/ / w i c k e d l y s m a r t .c o m / m y v i d e o . m p 4 ">

И мейте в виду, что вероятность возникновения проблем более высока, когда


ваше видео доставляется через И н терн ет (чуть позже мы поговорим о том, как
с ними справляться). Кроме того, битрейт вашего видео начинает приобретать
намного большее значение, когда вы доставляете его в браузер или на мобиль­
ное устройство по Сети. Как и в случае с ф орматами видео, если вы реш ите пой­
ти этим путем, общ айтесь со специалистами и занимайтесь самообразованием.

О тлично, и еще один


вопрос: есть л и разница
между тем, что м ы делаем,
и потоковы м видео?

Да, есть, причем большая разница.


П онятие «потоковая передача» используется так же часто, как понятие
«ксерокс» или «носовой платок», —это общ ий терм ин, означаю щ ий до­
ставку видео из И н терн ета в ваш браузер. «П рогрессивное видео» и
«потоковое видео» на самом деле являю тся техническими терминами.
В данной книге мы используем прогрессивное видео, а это означает,
что когда мы извлекаем видео (локально либо по С ети), мы извлека­
ем соответствующ ий файл с использованием H TTP точно так же, как
HTM L-файл или изображ ение, и пытаемся декодировать и воспроиз­
вести данны й файл после его извлечения. П отоковое видео доставля­
ется с использованием протокола, которы й тонко настроен для достав­
ки видео оптимальны м путем (возможно, даже с изменением битрейта
видео по мере того, как сниж ается или растет нагрузка на канал).
П отоковое видео, вероятно, способно обеспечить для ваших пользова­
телей более качественное взаимодействие (и это правда) и, возможно,
является более эф ф ективны м в нлане нагрузки на канал нодклю чения
ваших пользователей, а также на ваш канал (что тож е нравда). В допол­
нение ко всему этому н отоковое видео облегчает защиту содержимого
видео, если вам нотребуется обеснечить безонасность.

дальше ► 437
video streaming

А существует ли
стандарт для потокового
видео в случае HTM L5?

В HTML5 нет стандарта для потокового видео.


Дело в том, что проблема заклю чается не в
HTML5, а в отсутствии поддерж иваемого стан­
дарта для потокового видео; вместе с тем суще­
ствует масса собственных вариантов. Почему?
Тому есть множество причин: это и деньги, ко­
торы е можно заработать на потоковом видео,
и тот факт, что многие люди, заняты е в сф ере
программного обеспечения с откры ты м исход­
ным кодом, не желаю т работать над протоколом,
которы й может быть использован для DRM и
прочих технологий защ иты. Как и с форматами
видео, ситуация с потоковы м видео непростая.

Существует ряд решений.


Технологии потокового видео находят
массу разумных прим енений, и если вы
располагаете обш ирной аудиторией либо
содержимым, которое, как вам кажется,
нуждается в защ ите, обратите внимание
на H TTP Live Stream ing от компании
Apple, Sm ooth Stream ing от M icrosoft и
H TTP Dynamic Stream ing от A dobe, кото­
ры е станут хорош им отправны м пунктом.
Есть и хорош ие новости: ком итет стан­
дартов начинает обращ ать пристальное
внимание на потоковое видео на основе
HTTP, поэтому следите за разработками
в данной области.

438 глава 8
телевидение для нового поколения

Если бы это был совершенный м ир...


Однако он не является таковым: мы сталкиваемся с ненри-
ятны м и сетевыми нроблемами, несовместимы ми устрой­
ствами и онерационны м и системами и возрастаю щ ей ве­
роятностью того, что астероиды могут врезаться в Землю. <11II НТК НАСТ
С носледним мы ничего не можем но делать, а что касается
нервы х двух, то знание того, что у вас возникла ошибка, — У НАС ВОЗНИКЛИ ТЕХНИЧЕСКИЕ
это уже нолдела, носкольку вы тогда, но крайн ей мере, смо­ ПРОБЛЕМЫ
ж ете что-нибудь нреднринять.
О бъект video вклю чает собы тие error, инициирую щ ееся
но ряду нричин, которы е можно оты скать в свойстве video,
error, точнее говоря, в свойстве v i d e o .e r r o r .code. Д авайте
взглянем, какие тины ош ибок мы можем обнаруживать.

Ошибки
MEDIA ERR ABORTED= 1

Генерируется каждый раз, когда про­


цесс передачи видео по сети отменя­
ется браузером (возможно, по требо­
ванию пользователя).

MEDIA_ERR_NETW/0RK= 2 MEDIA_ERRJ)EC0DE = 3

Генерируется каждый раз, когда Генерируется каждый раз, когда д еко­


передача видео по сети преры­ дирование видео оказывается неудач­
вается вследствие ош ибки сети. ным. Это может случаться из-за того,
что видео было закодировано с о со ­
бенностями, которые не поддержи­
ваются браузером, либо видеоф айл
оказался поврежден.

MEDIA_ERR_SRC_N0T_SUPP0RTED = 4

Генерируется, когда указанный источник


видео не поддерживается из-за непра­
вильного URL-адреса либо ти п источника *Каждый muiA. ошибки также об
не может быть декодирован браузером. ладает ассоциированным но м е­
р о м j который представляет со­
бой код ошибкиj сгенерированный
событием error, о чем мы пого­
ворим через несколько мгновений..

дальше ► 439
обработка ошибок видео

Как использовать события error


О бращ ение с ошибками является н енросты м занятием, зависящ им от вашего нрилож ения, а также от
того, что окаж ется нодходящ им для вашего н рилож ения и ваших пользователей. По крайн ей мере, мы
можем но мочь вам начать и указать нрав ильное нанравление. Возьмем нрилож ение Webville TV и на­
делим его способностью узнавать о том, что оно столкнулось с ош ибкой, —и если оно с н ей столкнется,
то выведет для аудитории сообщ ение p le a s e s ta n d by (не меняйте настройки).
Мы хотим нолучать уведомление, когда им еет место сообщ ение об ошибке, ноэтому нам нотребуется
добавить слушатель собы тий e r r o r . Вот как мы сделаем это (добавьте данны й код в обработчик onlo ad
в w e b v ille . j s):
video.addEventListener("error", errorHandler, false);

Тенерь нам нужно нанисать функцию e rro rH a n d le r, Когда произойдет ошибка, будет
которая будет нроводить нроверку на нредмет
ошибок. Если она обнаружит ошибку, то разм естит
наше изображ ение с наднисью p le a s e s ta n d by
(не меняйте настройки) в области отображ ения
V nbllfirtHrt
вызвана Antiuwuua trirnirf-l /ил 10 ir
функция 0errorHandler.

Если происходит вызов обработчика, м ы -


удостоверяемся в т о м , что имела мест о
ошибка, для чего обращаемся к свойству
видео, сделав его ностерны м:
video.error, а за т е м размещ аем постерное
function errorH a n d l e r () { изображение в области отображения видео.
var video = d o c u m e n t .g etElementByld("video");

if (video.error) {

video .poster = "images /technical difficulties .jpg" ;

alert(video.e r r o r .c o d e ) ;
Вы можете опционально добавить дан­
ную ст року, чтобы и м е т ь возможность
увидеть код ошибки (см. предыдущую
страницу, где рассказывается о цело­
Kpaui-mecm! численных значениях, которые р асполага­
ю тся в свойстве code).
Существует много нричин, но которы м воснроизведение видео мож ет ока­
заться неудачным, а для тестирован и я данного кода вы снециально сделае­
те так, чтобы это нроизош ло. Вот ряд советов о том, как это можно сделать:
■ нонробуйте отклю чать свою сеть в разны е моменты воснроизведения
видео;
■ введите в нроигры вателе неправильны й URL-адрес;
■ нонробуйте воспроизвести в нроигры вателе видео, которое, как вам
будет известно заранее, он не сможет декодировать;
■ иснользуйте нрограм м ное обеснечение для сниж ения нропускной
снособности своего канала (оно существует, нужно лиш ь ноискать).

И так, наберите данны й код и нроведите тестирование. Вы сможете соноставить целочисленны е


зн ачен ия в диалоговы х окнах a l e r t с реальны м кодом, взглянув на коды ош ибок на с. 441.

440 глава 8
телевидение для нового поколения

Куда вы смоЖете отправиться отсюда?


Задумайтесь над всем тем, что вы уже умеете делать с номощью HTM L-разметки, элем ента v id e o и, ко­
нечно же, canvas... не говоря уже о веб-службах, API-интерф ейсе G eolocation. Здорово! Мы с вами нро-
вели классную обработку видео с иснользованием canvas, однако вы сможете нрим енить свои знания о
canvas и в случае с элементом v ideo. Н иж е нриведены наш и идеи, а вы добавьте к ним свои. И нохва-
лите себя от нашего имени, носкольку вы это заслужили!

Используйте веб­
Создавайте основанное службы для обеспечения
на времени содержимое, соответствующей
которое отображается контексту информации
только в определенные для своего видео.
промежутки времени Создавайте
при воспроизведении собственные
видео. экранные элементы
управления или
Используйте программные
JSONP для указатели.
добавления
интерактив­
ности!

Обеспечи­ Применяй­
вайте режим те все API-
просмотра интерфейсы
«картинка в для работы
картинке». с графикой
и текстом,
которыми вы
Используйте
умеете поль­
свои стра­
зоваться, на­
ницы для
чиная с Canvas,
размещения
и наклады­
соответству­
вайте изобра­
ющей рекламы.
жения прямо
поверх видео.

дальше ► 441
обзор api-интерфейсэ video

КЛЮЧЕВЫЕ ff
"МОМЕНТЫ » ---

Вы можете воспроизводить видео путем использования Вы можете программно спрашивать у объекта video,
элемента < v i d e o > в сочетании с несколькими про­ сумеет ли он воспроизвести видео в том или ином
стыми атрибутами. формате, используя canPlayType.
Атрибут a utoplay обеспечивает запуск воспроизве­ Метод canPlayType возвращает пустую строку (под­
дения видео по окончании загрузки страницы, однако держка формата отсутствует), "maybe " (если ему, воз­
его следует использовать, только когда он уместен. можно, удастся воспроизвести видео в определенном
Благодаря наличию атрибута controls браузер пре­ формате) и "probably" (если он будет уверен в том,
доставит пользователю набор элементов управления что не сможет воспроизвести видео в определенном
воспроизведением видео. формате).
Внешний вид элементов управления различается canvas может использоваться в качестве поверхности
в разных браузерах. отображения для video с целью реализации пользо­
вательских элементов управления и прочих эффектов
Посредством атрибута poster вы можете предусмо­
в случае с видео.
треть наличие своего собственного постерного изо­
бражения. Вы можете использовать временный буфер для об­
работки видео, прежде чем оно будет скопировано
Атрибут s г с содержит URL-адрес видео для воспро­
В displayCanvas.
изведения.
Вы можете задать обработчик setTimeout для видео­
Для форматов видео и аудио существует множество
кадров; несмотря на то что он не привязывается на­
«стандартов».
прямую к каждому кадру видео, это наилучший метод,
Широко применяются три формата: WebM, МР4/Н.264
который имеется на данный момент.
и Ogg/Theora.
Вы можете использовать URL-адрес как источник видео
Изучайте свою аудиторию, чтобы понять, какие фор­
для воспроизведения видеофайлов, размещаемых
маты видео вам потребуется обеспечить.
в Сети.
Используйте тег <source> для определения альтер­
Некоторые браузеры задействуют политику одного
нативных форматов видео.
источника в случае с видео, так что вам придется
Используйте полностью определенные типы в сво­ загружать свое видео из того же источника, откуда
ем теге <source>, чтобы сэкономить силы и время исходит ваша соответствующая страница.
браузера.
В случае с видео возникновение ошибок возможно
Вы сможете сохранить поддержку других видео- всегда, особенно когда задействуется Сеть.
фреймворков, например Flash, добавив резервный
Событие error может использоваться для уведомле­
тег <ob j ect> в элемент video.
ния обработчика, когда при извлечении, декодировании
Элемент v i d e o предусматривает богатый набор или воспроизведении случаются ошибки.
свойств, методов и событий.
Элемент video полагается на прогрессивно загружа­
video поддерживает методы И свойства play, pause, емое видео. В настоящее время нет НТ1\/^5-стандарта
load, loop И mut e ДЛЯ ПрЯМОГО КОНТРОЛЯ НЭД BOC- для потоковой передачи видео, однако комитет стан­
произведением видео. дартов начинает обращать внимание на решения для
Событие ended может использоваться для того, чтобы передачи потокового видео на основе HTTP.
дать знать, когда воспроизведение видео закончится На текущий момент не существует стандартного спо­
(например, для реализации плейлиста). соба защиты видео, доставляемого посредством эле­
мента video.

442 глава 8
телевидение для нового поколения

Щ Щ -К ^ С С В о р д

П реж де чем вы откинетесь на снинку стула и захотите еще


но смотреть Webville TV, разгадайте небольш ой кроссворд
для закренления изученного материала.

По горизонтали По вертикали
I. Для обеспечения набора видео в форматах, из которых 2. Мы смотрели____________ фильмы 1950-х годов.
можно будет выбрать подходящий, используйте сразу 5. Внешний вид элементов управления_____________
_____________ элементов s o u r c e . в разных браузерах.
3. Используется для отображения обработанного видео. 6. Задействуйте атрибут_____________ , если вам требу­
4. Тип буфера, который мы использовали в случае ются встроенные средства управления видео.
С can vas. 8. Что следует делать, если астероид собирается врезаться
7. Тип доставки, который элемент v i d e o использует в Землю?
в случае с видео. 12. Клинту Иствуду понравился бы тип видеоэффекта, ко­
9. Когда воспроизведение видео заканчивается, иницииру­ торый обеспечивается нажатием данной кнопки.
ется данное событие. 14. То, что мы обрабатывали при каждом вызове
10. Свойство для воспроизведения видео в зацикленном setTimeout.
режиме.
II. Запускает воспроизведение видео так быстро, как это
только будет возможно.
13. Аудиокодек с открытым исходным кодом.
15. Я могу воспроизвести данный тип видео, а ты?

дальше ► 443
решение упражнения

^озьлли в руку карандаш


Решение Данная книга не посвящена обработке видео и эффектам, однако
это, несомненно, увлекательная тема. Ниже приведены функции
western и scifi, позволяющие применять соответствующие эффек­
ты. Просмотрите код и напишите справа, как работает каждая из
них. Кроме того, мы добавили к ним еще одну функцию — что она
делает? Вот наше решение этого упражнения.

function western(pos, г , д , b, data) {

var brightness = (3*r + 4*g + b)> » 3; функция для применения фильт ра


data [pos * 4 + 0] = b rightness+40 ; w estern усиливает компоненты IT (к рас-
data [pos * 4 + 1] = b rightness+20; Hbiu) U Q (зеленый)пиксела, одновременно

data [pos * 4 + 2] = brightness-20; ослабляя Компонент b (синий), Чтобы


} придать видео коричневатый от т енок.

function scifi. (pos, r, g, b, data) { функция для применения фильт ра scifi


var offset = pos * 4; изменяет в обратную ст орону количе-
data [of f set] = M a t h . round (255 - r) ; ство компонентов RGB каждого пиксела.
data [ offset+1 ] = M a t h .round (255 - g) ; TaKUM образом, если пиксел Содержал
data [ offset+2 ] = M a t h . round (255 - b) ; много красного3 mo т еперь его будет
> мало. Если же пиксел включал мало з е ­
леного, то т еперь его будет много.
function bwcartoon(pos, r, g, b, outputData) {

var offset = pos * 4; функция для применения фильт ра


if ( outputData [of f set] < 120 ) { b w cartoon превращ ает каждый пиксел

outputData [of f set] =80; с компонентом IT(красный), меньшим


outputData[++offset] = 80; t-ZO (из 2 5 5 ), в черный, а все ост аль -
outputData[++offset] = 80; ные пикселы — в белые, придавая видео
} else { причудливый мультяшный черно-белый
outputData [offset] = 255; вид.
outputData[++offset] = 255;

outputData[++offset] = 255;

}
outputData[++offset] = 255;

++offset;

444 глава 8
id
И
В w
M ro
X H
S to
И я
>
\ Safari
a
s S о
I 2 to
to
\ Chrome ^ c< и
o' I Tl
N
я Firefox > ?
SX.cc DO
i.- l s
S M obile Webkit Ob to
м
-s I о
N я Opera
• !
о 5
£ ^3
X Si
Internet Explorer JE
и выше s
0
1
I
<T
X
Internet Explorer
Э
I
Internet Explorer
сохран яем Д ан н ы е Л ^каЛ ьН с

API-интерфейс Web Storage


/ Я уже устала от этого ' >
тесного шкафа и от то го , что мне
приходится носить один и тот же
брю чны й костю м. Благодаря HTM L5
у меня будет достаточно места для
одежды, я см о гу каждый день надевать
^ новый костю м!

Устали от того, что клиентские данные приходится втискивать в тес­


ные ш кау ы ф айлы cookie? В 1990-е годы такой проблемы не было, однако
сейчас при использовании веб-приложений запросы значительно возросли. Как бы
вы отнеслись к тому, если бы мы сказали, что у вас есть возможность выделять
по 5 Мбайт на браузер каждого пользователя? Вы, вероятно, подумали бы, что
мы шутим. Однако не стоит быть скептичными, поскольку API-интерфейс HTML5
Web Storage как раз позволят это делать! Из данной главы вы узнаете обо всем,
что необходимо для сохранения объектов локально на устройстве пользователя
и использования их в работе ваших веб-приложений.
история браузерного хранилища

Как работает браузерное хранилище (1 9 9 5 -2 0 1 0 ) За сЦеНои


Создаете электронную корзину? Вам требуется сохранять установки пользователей на своем сайте? Или
нросто нужно н рин рятать данны е, которы е долж ны быть ассоциированы с каждым из пользователей?
И менно здесь встунает в дело браузерное хранилищ е. Это хранилищ е н озволяет сохранять на постоян­
н ой основе данны е, которы е мы сможем иснользовать в работе своих веб-нриложений.
До настоящ его врем ени существовал только один онтим альны й вариант для сохранения инф орм ации
в браузере —файлы cookie. Д авайте но смотрим, как они работают.

Когда ваш браузер извлекает веб-страницу, скажем, из pets-R-us.com,


сервер может присылать файлы cookie вместе со своим ответом.
Файлы cookie содержат одну или более пар «ключ — значение»:

Когда я загружаю веб­


страницу, я также присы лаю вам
пары « кл ю ч — значение», чтобы вы
сохранили и х для меня. В след ую щ ий
раз, когда вы обратитесь ко мне, отправь­
те и х вместе со своим запросом.

1 2

С Браузер

Браузер сохраняем
Веб-сервер

'
Содержимое файлов
cookie.
файлы cookie локально. Cookie: pet=dog; age=5; color=black
Он отправим их об­
ратно на сервер, когда Г
Пары «клю ч — значение». У нас имеется
будет совершать запрос ключ p e t со значением dog, а также ключ
о следующий раз.
аде со значением 5 и т. д.

448 глава 9
сохраняем данные локально

Когда браузер будет совершать запрос pets-R-us.com в следующий раз, он отпра-


вит вместе с ним все файлы cookie, которые были присланы ранее.

В прош лы й раз, когда мы


с вами общались, вы прислали мне
эти ф айлы cookie. Я отправляю и х
вам обратно.

Файлы cookie отправляют­


ся туда-сюда при каждом
HTTP-запросе и ответе.

Браузер Размер файлов cookie Веб-сервер


ограничен *4-Кбайтами
данных.

Сервер затем сможет использовать эти файлы cookie для персонализации взаимо-
действия. В данном случае это будет выражаться в продвижении соответствующих
элементов, касающихся определенного пользователя, но существует и масса дру­
гих способов использования файлов cookie.

Благодарим вас. Х отим


сообщить, что у нас большая
распродажа товаров для собак Файлы cookie могут
среднего возраста. использоваться для
всевозможных целей
^ вроде настройки
пользовательского
взаимодействия ,
сохранения данных ,
напримерj в элек­
тронной корзинеj
файлы cookie ассоциированы или для поддержа­
с доменом, нап р и м ер , ния состояния игры.
p e ts-R -u s.co m , и будут о т ­
правляться только в э т о т
Браузер домен. Таким образом, до- Веб-сервер
мен PetsEmporium.com никак
не сможет получит ь эти
файлы cookie.
дальше ► 449
как работает web storage

Ш Т У Р М
Файлы cookie уже давно у нас под рукой, однако вам, возможно, удастся придумать способ
усовершенствовать их.
Отметьте флажками те пункты из приведенных ниже, которые, по вашему мнению, делают ис­
пользование файлов cookie проблематичным.

| | Для работы доступно лишь 4 Кбайта, а моему приложению требуется хранилище


большего размера.
□ Отправка файлов cookie туда-сюда каждый раз очень неэффективна, особенно при
использовании мобильных устройств в сочетании с медленным каналом связи.

□ Похоже, что они являются удобным способом передачи вирусов и прочего вредо­
носного программного обеспечения в мой браузер.

| | Мне доводилось слышать, что способ, посредством которого пары «ключ — значе­
ние» включаются в HTTP-запрос, сложно реализовать в коде.

| | А разве мы потенциально не отправляем личные данные туда-сюда каждый раз,


когда совершаем запрос?

□ Не похоже, что они хорошо сочетаются с нашей разработкой, связанной с клиент­


ской стороной. Мне кажется, они предполагают, что все будет происходить на сер­
вере.
Y)?v?\MWJY)viooFidY)2 K v g w?frir»K?py)dvi кэм снхудк ?н ю icihvvvios?^ oucivogoq
?l>joov iQvvivcp r?oH\Mvdgo ?oo?dv i g о\мь o w i vh ndwiowo?f-\

Я надеюсь, что H TM L5
предусматривает простой A P I-
интерсрейс клиентской стороны для
сохранения данны х, которы й обеспечивает и х
хранение на постоянной основе в браузере, пред­
лагает больш ий объем хранилищ а и передачу
данны х на сервер только в том случае, если
я этого захочу.

450 глава 9
сохраняем данные локально

Как работает Web Storage HTML5 сценой Д И

HTM L5 предусматривает изящ пы й и простой API-иптерф ейс JavaScript в браузере для сохрапепия
устойчивы х пар «ключ —зпачепие». К роме того, вы пе будете ограпичепы скудпыми 4 Кбайтами храпи-
лища; в пастоящ ее врем я все браузеры готовы предоставить вам храпилищ е разм ером от 5 до 10 Мбайт,
причем в браузере каждого пользователя. Н ТМ Ьб-техпология localStorage также создавалась с учетом
веб-прилож епий (и мобильпых прилож епий!); опа озпачает, что ваше п рилож епие сможет сохрапять
даппы е в браузере, чтобы спизить объем «общепия» с сервером. Д авайте посмотрим, как все это рабо­
тает (а затем пы рпем в даппы й API-иптерф ейс с головой).

Страница может сохранить одну или бо- 0 ^ Позднее можно будет использовать
лее пар «ключ — значение» в локаль­ ключ для извлечения соответству­
ном хранилище (localStorage) браузера. ющего значения.
Используя С0° Г р ,_
бетстбук^ ^

значение»
Имея ключ»
л .н о е х р а н и л и щ е .
MW сможем т а к *
1л з 6лече> значение
и 3 локального
xpa HwAWiMa -

Браузер
Пара «клю ч — Браузер
значение»
Конечно можно,
этим значением
будет dog.
Каждый современ-
у / ный браузер обе­
спечивает локальное ПРИМЕЧАНИЕ: сервер
хранилище раз­ будет продолжать за­
мером 5 Мбайт гружать ваши страни­
цы, а вы при этом даже
(“ ^оле-е!) для каждо- сможете отправить на
го домена.
него немного данных, рас­
полагающихся в вашем
localStorage локальном хранилище, для
проведения вычислений
localStorage Как и в случае с файла­ на стороне сервера. Одна­
Хранилище обеспечива­ ми cookies, ваша ст ра ­ ко с деталями локального
ет сохранение данных на ница сможет сохранять Хранилища будет р а з­
постоянной основе, даже и извлекать лишь те бираться клиент, а не
элементы, которые были сервер (как это обычно
если вы закроете окно
сгенерированы страница­ бывает в случае с файла­
браузера или вообще з а ­
ми, исходящими из того ми cookie).
верш ите его р аб от у. же домена. Подробно об
этом поговорим позже.

дальше ► 451
использование web storage

Зам етка 9АЯ себя...


Вам требуется система, чтобы управиться с делами? Сложпо
улучшить старую добрую систему заметок-папомипапий (более
известную как клейкие заметки). Вы зпаете, как опа работает:
вы записы ваете па листке бумаги нупкт «это пужпо сделать»,
приклеиваете его куда-пибудь и после вы полпепия записаппо-
го вы брасы ваете эту клейкую бумажку в мусорпое ведро. З а б р а в
Попробуем создать такую систему с использованием HTML. 6 eiM u

Н ам потребуется способ сохрапять все эти клейкие замет­


из
ки, поэтому пам будет нужеп сервер, а также ф айлы cookie...
Постойте-ка, вклю чите задпий ход, ведь мы можем сделать все
„ , 1лчне|1л
это с помощью API-иптерф ейса HTM L5 Web Storage!
<^коЛ -оЗУ *'
S '
A P I -инт ерф ейс Web Storage прост и увлекат елен,
работ ат ь с ним - одно удовольствие. Уверяем вас!

Не будем валять дурака, а сразу приступим к использованию локального хранилища. Для этого
вам потребуется создать простую HTML-страницу с базовыми элементами: <head>, <body> и
нение <script> (либо ВЫ можете просто воспользоваться файлом no t e t o s e l f . h t m l в примерах
кода). Следуйте за нами и наберите в своем элементе <script> приведенный далее код (ввод
кода способствует запоминанию материала):
Мы начина­
На клейкой заметке присутствует лишь текст, который вы напи­ ем с простого,
сали, не так ли? Поэтому давайте сначала сохраним эту заметку однако прежде,
(sticky) ДЛЯ "Pick up dry cleaning" ("Забрать вещи из чем вы осознаете
химчистки"): fs" это, у нас уЖе
будет целое р а ­
ботающее п р и ­
A P I - ин терф ей с Web Storage Метод set Item принима ложение Stickies.
будет доступен посредством ет две строки в каче­
обьекта localStorage. Вы увидите, Вы сможете сохранять
стве а р гум ент ов, кото
что браузер уже определил его за рые играю т роль пары только элементы т ипа
вас. Применяя его, вы используе­ «клю ч — значение». string. Напрямую сохра­
нять числа или объекты

/ \
т е основную сист ему локального
хранения, ^ нельзя (однако мы вскоре
найдем способ обойти
это ограничение).
localStorage. set Item ("sticky_0 ’’ Pick up dry c l e a n i n g " ) ;

Чтобы сохранить что-


т о , мы используем
мет од setltem. П
с ‘/ ^ ‘7 ° Т й
\ Второй строковый аргум ент
является значением, которое
вы хо т и т е сохранить в л о ­
~ s : i ^ : z z r кальном хранилище.

452 глава 9
сохраняем данные локально

Предыдущее действие было довольно простым. Давайте добавим второй элемент в локальное
О хранилище:
l o c a l s t o r a g e . s e t I t e m (" sticky_l", "Cancel cable tv, who needs it now?");

Рше один «Люч. К ак м ь I уже говорили, у вас есть Значение, которое будет
Кпъллпжность использовать для ключа любое и м я , соот вет ст воват ь нашему
^ с к о л ь к у он является ст рока*. ^ ^
сохранять только одно значение на каждый ка

4 ^ Теперь, когда у нас есть два значения, надежно сохраненные в локальном хранилище браузе-
ра, вы можете воспользоваться одним из ключей для извлечения соответствующего значения
из localStorage. Например:

Извлекаем значение, ассоциированное с ключом


«stickyjD », из локального хранилища...
...и присваиваем его ^
^ переменной sticky.

var sticky = l o c a l S t o r a g e .g e t l t e m (" s t i c k y _ 0 ");

alert (sticky) ; Чтобы все стало еще интереснее, используем ф у ,


нк-
цмю alert для вывода на экран значения sticky.

Время тест-д р айв а!


Убедитесь, что вы папечатали весь приведеппы й чуть выше код в своем элемепте < s c r i p t > , H загрузите
его в своем браузере. Вот результат пашего тест-драйва:
диалоговое J a v a S c r ip t -о к н о
Это наше sticky О в качестве
alert со значением
предупреж даю щ его сообщения.

J a v a S c rip t
Здорово, что данное значение было сохранено
Pick up dry cleaning и извлечено из localStorage браузера! Вы можете
заверш ит ь работу своего браузера, о т п р а ­
виться в от пуск на фиджи, за т е м вернуться
( )
а оно по-преж нему будет дожидаться вас там.

К. Ладно-ладно, мы согласны, что пример мог бы


быть более захватывающим... Однако ост авай­
тесь с нам и, поскольку скоро т ак и будет...

дальше ► 453
как работает ар 'ьинтерфейс localStorage

Это бы ло здорово,
но не м о гл и бы м ы с вами О о
пройтись по коду подробно?
Я не уверена, что разобралась
в происшедшем на 100 %.

Разумеется. Кратко о том, как обстоят дела:


браузер обеспечивает для вас локальное хран и ­
лищ е —область на вашем компью тере, в вашем
браузере, — которое страница мож ет исполь­
зовать для сохранения пар «ключ —значение».
Вы создаете несколько пар «ключ — значе­
ние», сохраняете их, используя API-интерфейс
localStorage, а затем извлекаете одну из них
для использования в своем прилож ении. Н е­
смотря на то что это, может, и не самый за­
хваты ваю щ ий прим ер, существует масса и нте­
ресны х вещ ей, которы е вы сможете сделать,
используя хранилищ е в браузере каждого из
пользователей (и мы уверены, что вы сможете
придумать по крайней мере несколько таких
ситуаций).
А теперь подробпо разберем ся в том, что толь­
ко что произош ло.

Во-первых, помните, что каждый браузер располагает


локальным хранилищем, которое вы можете исполь­
зовать для сохранения пар «ключ — значение».

Каждый современный
^ ^ д р а у з е р располагает
локальным хранилищ ем
«за кулисам и» , г о т о ­
вым к использованию
вами для сохранения пар
«клю ч — значение».

localStorage

Браузер

454 глава 9
сохраняем данные локально

Используя данное локальное хранилище, вы можете взять ключ и значе­


ние (которые будут представлять собой строки) и сохранить их там.
localStorage.setltem("sticky_0" " P i c k u p d r y c l e a n i n g 11)

Используем м ет од setltem для со­


Т
хранения пары «клю ч — значение».
/
К лю чом будет "sticky_Ou, а значе­
нием — "Pick up dry cleaning" ("За­
брать вещи из химчистки"). v C|eaning-
Пара «клю ч — з н а ­
чение» , сохраненная При помещении пары
посредством вызова «ключ — значение»
метода setltem. в localStorage она сохра-
нится т а м , даже если вы
закроете окно браузера,
вообще заверш ит е работу
браузера или перезагрузите \
компью тер. localStorage
Затем мы снова вызвали setltem и сохранили вторую пару «ключ —
значение», куда на этот раз входит ключ "sticky i" и значение
"Cancel cable tv, who needs it n o w ? " ("Отказаться от подписки
на кабельное ТВ, ведь кому оно теперь нужно?").

l o c a l S t o r a g e . s e t l t e m ( 11s t i c k y _ l 11, " C a n c e l c a b l e tv, w h o n e e d s i t now?")


Теперь у нас есть два уникальных
значения, сохраненных под двумя
уникальными ключами^

И когда вызовем метод getltem, указав при этом ключ


МЫ
"sticky o", он
вернет значение, имеющееся в соответствующей
паре «ключ — значение».
l o c a l S t o r a g e .g e t l t e m (" s t i c k y _ 0 " );
6 о 3 6 р а ^ е1ЛЛ
localStorage
“Pick up dry g e tlte m находит э лем ент с ключом ".sticky_0"
cleaning” (при наличии такового) и возвращает его значение.

Следует о т м е т и т ь , ч т о , извлекая элем ент , мы не удаляем его из х р а ­


нилища (он по-преж нему ост ается там). Мы лишь извлекаем значение,
соот вет ст вую щ ее определенному ключу.

дальше ► 455
вопросы о локальном хранилище
Част°
Задаваем ы е
Боцрось!

ft «Web Storage» и локальное хранилище — это одно и то же? 0 : В других технологиях, позволяющих сохранять данные в
браузере, нет ничего плохого, однако локальное хранилище HTML5
0 : Веб-стандарт называется Web Storage, однако большинство сейчас является стандартом (Google, Apple, Microsoft и прочие
компании считают Web Storage стандартным инструментом для
людей просто называют его локальным хранилищем (фактически,
сохранения содержимого локально в браузере).
браузеры как раз и предоставляют данный API-интерфейс посред­
ством объекта localStorage). Web Storage — не самое удачное
название для стандарта (поскольку элементы сохраняются в вашем
браузере, а не в Интернете). Тем не менее мы придерживаемся
& Что произойдет, если я вызову setltem в отношении од­
ного и того же ключа несколько раз? Скажем, дважды вызову
setltem в отношении «sticky_1». В итоге в локальном хранилище
его. Вы увидите, что мы будем использовать термин «локальное
у меня окажутся два ключа «sticky_1»?
хранилище» чаще, чем название стандарта Web Storage.

Насколько широко поддерживается API-интерфейс Web


0 : Нет. Ключи являются уникальными в localStorage, по­
этому set item будет перезаписывать первое значение вторым.
Storage? Можно ли рассчитывать на такую поддержку? Например, если вы выполните этот код:
localStorage.setltem("sticky_l", "Get Milk")
0 : Да, можно. На самом деле это один из наиболее поддер­ localStorage.setltem("sticky_l", "Get Almond Milk")
живаемых API-интерфейсов, даже в версиях вплоть до Internet var sticky = localStorage.getltem("sticky_l")
Explorer 8, причем на текущий момент — в большинстве мобиль­
ных браузеров. Кое-где имеются предостережения, и мы обратим значением sticky будет "Get A l m o n d Milk".
на них ваше внимание. В плане поддержки Web Storage вам, как
всегда, следует провести тест, прежде чем пытаться использовать Кто сможет сохранять данные в моем локальном хра­
данный API-интерфейс. Вот как можно проверить, поддерживается
f t
НИЛИ
нилище?
Л И localStorage:
if (window["localStorage"] ) {
// your localStorage code here.
0: Управление локальным хранилищем осуществляется в со­
ответствии с источником (вы можете рассматривать источник как
свой домен) происхождения данных. Таким образом, к примеру,
}
каждая страница wickedlysmart.com сможет «увидеть» элементы,
Обратите внимание, что при тестировании мы выясняем, имеется ли сохраненные другими страницами на этом сайте, однако код с
у глобального объекта w i n d o w свойство localStorage. Если других сайтов, скажем, с google.com, не будет иметь доступа к
оно присутствует, то мы будем знать, что браузер поддерживает данному хранилищу (он сможет получить доступ только к элементам
localStorage. в своем собственном локальном хранилище).

5 =В самом начале главы вы упоминали о 5 Мбайтах хранили­


ща eв каждом браузере. Это общий объем, который приходится
на в
все приложения?
В.
этод
Когда я загружаю страницу со своего компьютера, как мы
это делали в упражнениях, что является моим источником?

0 ::! Хороший вопрос. В данном случае вашим источником будет


0 : Нет, по 5 Мбайт приходится на каждый из доменов. Local Files {локал ьн ы е ф айлы ), и он отлично подходит для про­
ведения тестирования. Если у вас будет доступ к серверу, где вы
Т5-
| у * Вы сказали, что участие сервера не требуется, а потом также сможете протестировать свои файлы, то тогда источником

начали вести разговор о доменах. будет соответствующий домен.

Локальное хранилище не будет


0 : Все верно, поскольку управление хранилищем полностью ])удыпе функционировать должным об­
осуществляется на стороне клиента. Домен вступает в дело потому,
о£-Щор>оЖНь1 , разом, если вы используете file://.
что 5 Мбайт хранилища выделяются всем страницам, исходя­
щим из одного и того же домена. Pet-R-Us.com получает 5 Мбайт, Э т о е щ е один случай , ко гд а н еко т о­
PetEmporium.com — еще 5 Мбайт и т. д., на всех ваших компьютерах. р ы е б р а у зе р ы т р еб ую т , чт обы вы загруж али с во и
ст ран и ц ы , и сп о л ьзуя lo ca lh o st:// или о н л а й н -с е р в ер ,
TJJi *-
А если сравнить данный механизм с Google Gears (или а н е д е л а л и э т о из ф а й л а . Е сл и ваш и к л ей к и е з а ­
с другой технологией локального хранения данных)? м ет ки н е б удут р а б о т а т ь , п р и б е гн и т е к з а г р у зк е
с с е р в е р а или в о с п о л ьзу й т е с ь др уги м б р а узер о м .
456 глава 9
сохраняем данные локально

Итак, я м о гу сохранять данные в localStorage. А если потре­


буется сохранить числовое значение? Я полагал, что см о гу использовать
localS torage для сохранения целочисленны х значений ито го в о го количества элемен­
тов и цен с плавающ ей точкой для такого приложения, как электронная корзина, кото­
рое хочу написать. Та л и это техн о ло ги я, которая мне требуется?

Это именно та технология, которая вам нужна.


Верно, в ситуации с localStorage вы сможете использовать только строки
в качестве клю чей и значений. Однако здесь все не настолько ограничено, как
может показаться. Допустим, вам нужно сохранить целочисленное значение
5. Вы можете вместо этого сохранить строку «5», а затем преобразовать ее об­
ратно в целое число при извлечении из локального хранилищ а. П осмотрим,
как это можно сделать в случае с целочисленны ми значениями и значениями с
плавающей точкой. Скажем, вам требуется сохранить целочисленное значение
с ключом "numitems". Для этого вы написали бы следующее:
Разве мы н е говорили, что
localStorage . setltem( " n u m i t e m s " , 1 ); сохранять целочисленные
значения нельзя?
М ожет показаться, что здесь вы сохраняете целочисленное значение, одна­
ко JavaScript знает, что это должна быть строка, поэтому преобразует за вас
данное значение в строку. В действительности s e t l t e m увидит строку " 1 ",
а не целое число. Однако JavaScript окажется не так умен, когда вы будете из­
влекать значение с помощью getltem:
var numitems = l o c a l S t o r a g e .g e t l t e m (" n u m i t e m s ");
ОЭЛЬ
В даппом коде мы присваиваем numitems строку " 1 ", а пе целочислеппое зпа­
чепие, как бы пам хотелось. Ч тобы numitems было числом, потребуется приме-
пить JavaScript-фупкцию p a r s e l n t для п реобразования строки в целое число:
Обертываем значение в вызов p arselnt,
^ — что преобразует ст року в целое число.

var numitems = p a r s e l n t ( l o c a l S t o r a g e .g e t l t e m ("numitems "));


numitems = numitems + 1; __ З а т е м МЫ опять
сохраняем его, при
l o c a l S t o r a g e .s e t l t e m (" n u m i t e m s ", n u m i t e m s )
Mы можем прибавить э т о м Ja v a S c rip t
X к н е м у , поскольку снова обеспечит
это число. преобразование.
Если вы будете сохрапять зп ачеп ия с плаваю щ ей точкой, то взамеп вам п отре­
буется использовать фупкцию parse Float при извлечепии элемептов price из
localStorage: Здесь все то же самое-, мы
сох р ан яе м значение с п л а ва­
ющей т о ч к ой, к о т о р о е пре
localStorage .s e t l t e m ("price" , 9.99) ; о б р а з у е т с я в Строку.
var price = p a r s e F l o a t ( l o c a l S t o r a g e .g e t l t e m ("pr i c e " ));

И преобразуем э т у ст року об- --------- >7


ратно в значение с плавающей
точкой с помощ ью parseFloat.
дальше ► 457
чем локальное хранилище схоже с массивом

Были ли локальное хранилище и массив разделены при роЖдении?


Локалыгое храпилищ е им еет и другую сторону, которой вы еще пе видели. массие
localStorage пе только предусматривает методы получателя и установщ и­
ка (то есть g e t l t e m n setltem), по также позволяет обращ аться с объектом
localStorage как с ассоциативпы м массивом. Ч то это озпачает? Вместо того
чтобы использовать метод setltem, вы сможете п рисвоить ключу зпачепие
в храпилищ е, как показало далее:
localStorage [" s t i c k y _ 0 " ] = "Pick up dry cleaning";

S "
Здесь ключ выглядит как индекс
\\ А вот наше значение, р а сп о л а -
для массива хранения. ™ " Р * 6 у " сторону
0 г от оператора присваивания.

Используя даппы й подход, мы также можем извлечь зпачепие, сохрапеппое


в ключе:
4^ Это работ ает точно т ак же, как ис~
var sticky = localStorage [ "sticky_0 " ] ; пользование вызова метода qetltem.
т f
Присваиваем н а - значение ключа "sticky-О
шей переменной в локальном хранилище,
sticky...

Н еплохо, правда? Таким образом, вы мож ете прим епять лю бой сиптаксис, поскольку опи оба допусти­
мы. А если вы привы кли использовать ассоциативпы е массивы па JavaScript, то даппы й сиптаксис мо­
ж ет показаться вам более компактпым и удобочитаемым.

ПодоЖдите, это еще не все!


API-иптерф ейс localStorage предусматривает еще два иптереспы х ипструмепта: свойство le n g th и ме­
тод key. Свойство le n g th содерж ит количество элемептов в локальпом храпилищ е. А что делает метод
key, вы мож ете увидеть чуть пиже: 4 л 1Лл. #_1л ./
Общая ка р т и на : мы используем length
Свойство length, позволяет для осуществления итераций по с о -
О сущ ест вляем ит ерацию у 3натЬ) сколько элемент ов держимому localStorage (как в случае
по каждому элементу. содержится в localStoraae с Maccu®0M) и обращаемся к каждому
| ключу (например , ”sticky_0") по коду
V V процесса. Зат ем мы сможем исполь-
for (var i = 0; i < l o c a l S t o r a g e .length; i++) { 3овать данный КЛЮЧ для извлечения
var key = localStorage.key(i) ; соот вет ст вую щ его значения.
var value = localStorage [key] ; ^ ЛЯ каж^ого элемент а в localStorage
. м ет од key дает нам определенный ключ
} alert (val^ue) ; ("sticky О", "Sticky_l" и т. д.).

Проведите т е ст и п о с м о т р и т е , выво- З а т е м с помощ ью имени ключа


дится ли на экране диалоговое окно alert мы сможем извлечь с о о т в е т -
относительно каждого из элементов? ст вую щ ее значение.

458 глава 9
сохраняем данные локально
Чаапо
Задаваем ы е
B olIpoC bX

Если я стану осуществлять итерации по


f t
localStorage с использованием localStorage.length
0 : Вообще-то порядок элементов не является опре­
деленным. То есть вы сможете увидеть каждую пару
и localStorage.key, то каким при этом будет порядок «ключ — значение» в хранилище посредством соверше­
элементов? Таким же, каким я записывал их в хра­ ния итераций, однако не следует при этом рассчитывать

ч нилище?

И г р а в скорлупки
на какой-то определенный порядок в коде. Фактически
разные браузеры могут предусматривать различный
порядок для одного и того же кода и элементов.

Готовы испытать удачу (или, скорее, сноровку)? Данная игра позволит проверить, насколько хорошо
вы знаете localStorage, однако вам потребуется проявить решительность, Используйте свои
знания об извлечении и сохранении пар «ключ — значение» в localStorage, чтобы уследить за
горошиной, когда она будет перемещаться от одной скорлупки к другой.
Можете использовать
это прост ранст во для
function shellGame() {
отслеживания сост оя­
l o c a l S t o r a g e .s e t l t e m (" s h e l l l " , " p e a " ) ;
ния localStorage.
l o c a l S t o r a g e .s e t l t e m (" s h e l l 2 ", "empty");
l o c a l S t o r a g e .s e t l t e m (" s h e l l 3 ", "empty");
localStorage["shelll"] = "empty";
localStorage["shell2"] = "pea";
localStorage["shell3"] = "empty";
var value = l o c a l S t o r a g e .g e t I t e m (" s h e l l 2 ");
l o c a l S t o r a g e .s e t l t e m (" s h e l l l " , v a l u e ) ;
value = l o c a l S t o r a g e .g e t l t e m (" s h e l l 3 ");
l o c a l S t o r a g e [" s h e l l 2 "] = value;
var key = "shell2";
localStorage[key] = "pea";
key = "shelll"; Под какой скорлупкой
localStorage[key] = "empty"; находится горошина
key = "s h e l l 3";
(«реа»)? Свой о т в е т
напиш ите здесь•
localStorage[key] = "empty";

for (var i = 0; i < localStorage.length; i++) {


Клю ч Значение
var key = l o c a l S t o r a g e .k e y ( i ) ;
var value = l o c a l S t o r a g e .g e t l t e m ( k e y ) ; s h e lll
alert(key + ": " + value); slnellZ
she Из
н а т ь т1 Т 5ратЬ Эт°' 4Mo6bl пР ° ^ р и т ь свой о т в ет и ч з ~
m*, под какой скорлупкой будет находиться горошина

дальше ► 459
беседа технологий хранения данных

Беседа у камина У ч а стн и к и сегодняшнего разговора:


ф айлы cookie и локальное хранилище
Сегодня мы станем свидетелями разговора текущей распространенной
технологии хранения данных в браузере, называемой «файлы cookie»,
и новым кандидатом на лидерство, имя которого «локальное хранилище».

Ф айлы cookie: Л окальное хранилищ е:


А вот и паш «золотой мальчик» — локальпое хра-
пилищ е. Мы в этом деле уже более десяти лет,
и Вы думаете, что мож ете вот так просто добиться
успеха? Да у Вас еще молоко па губах пе обсохло!
К опечпо, па это можпо и так посмотреть
либо сказать, что я создало па оспове опыта,
извлечеппого из ваших ошибок.
Да Вы хоть имеете представлепие о том, со сколь­
кими страпицами мы используемся? А п а свою
статистику Вы когда-пибудь смотрели?
П одождите песколько лет, и тогда посмот­
рим. Реальпость такова, что я помогаю за­
действовать целое повое поколепие веб-
прилож епи й в браузере. М погие из страпиц,
о которы х вы упомянули, являю тся всего лишь
страпицами.
Эй, мы вездесущи, повсеместпы, пас можпо встре­
тить везде! Мы пе думаем, что в пастольпом или
мобильпом сегмепте существует браузер (певаж-
по, пасколько старой оп версии), где пельзя было
бы пас пайти. Я быстро догопяю вас по популярпости. С ре­
ди всех техпологий HTM L5 я являю сь одпой
из паиболее хорош о поддерживаемых.
Это мы еще посмотрим. А что имеппо Вы мож ете
предлож ить сверх того, что можем предлож ить
мы? Мы прекраспо обеспечиваем храпепие дап-
пых.
Ч то ж, я пе уверепо, что хочу упомипать об
этом па нублике, по у вас проблем ы с объемом.
Мы п опятия пе имеем, о чем Вы здесь говорите.

Эй, вы сами это пачали, а пе я. Вам отличпо


известпо, что вы ограпичепы 4 Кбайтами
храпилищ а, а в моем случае опо более чем в
1 2 0 0 раз больше!

460 глава 9
сохраняем данные локально

Ф айлы cookie: Л окальное хранилищ е:


Мы легки, проворпы , можпо даже сказать,
гибки.
Вот это забавпо. Вы когда-пибудь общались
с разработчиками? Вы какие угодпо, по толь­
ко пе гибкие. У вас, если вы так лю бите ста­
тистику, есть даппы е о количестве часов, ко­
торы е разработчики п отеряли из-за глупых
ош ибок и заблуждепий при использовапии
файлов cookie?
Да бросьте, мы как откры тая кпига —простое
храпилищ е, в которое можпо поместить все,
что вам потребуется.
Н а самом деле у вас, по сути, отсутствуют ка-
кие-либо ф орм аты даппых, из-за чего разра­
ботчикам приходится запово изобретать схе­
му сохрапепия ипф орм ации в файлах cookie.
А разве пары «ключ — зпачепие» являю тся
каким-то большим повшеством?
Нужды в каких-либо больших повш ествах в
храп еп и и даппы х пет; пары «ключ — зпаче­
пие» прекраспо работают, опи просты и под­
ходят для мпогих вы числительны х прилож е­
ний.
<Хихикапье> Ах, да, Вы же сохрапяете все в
виде строки! О тличпая работа! </Х и хи ка-
пье>.
И з строк можпо извлечь мпого пользы,
а если вам потребуется что-то более сложпое,
то для этого есть соответствующ ие нути.
Да, да, позовите мепя через десять лет, и мы
посмотрим, выдерж али ли Вы проверку вре-
мепем.
О, будьте уверепы. П осм отрите правде в гла­
за: вы с самого пачала были обречепы . Кто
захочет пазвать своих детей в вашу честь?
Вы увидите, как еще будете в слезах звать
мепя, когда Вам скажут: «Ха-ха, пять мега­
байт —и это все, что у Вас есть?».

дальше ► 461
приложение для работы с клейкими заметками

Серьезно о клейких зам етках


Итак, вы пемпого поиграли с Web Storage, а теперь продолжим пашу
реализацию . Мы создадим прилож епие N ote to Self для работы с элек-
троппы м и клейкими заметками, чтобы вы смогли увидеть свои заметки
и добавить к пим повые. П осмотрим, что мы собираемся сделать, п ре­
жде чем приступим к работе. localStorage

Наше приложение Note to Self


будет отображать клей­ Если у нас в хранилище уже
кие заметки, сохраненные будут заметки, то мы хо­
Нам нужен способ добавления g localStorage, а также позволит тим, чтобы они отобража­
новых клейких заметок. По- нам добавлять новые заметки, лись на экране после загрузки
этому мы создадим форму страницы. Как, например,
с полем ввода икнопкой. эти две заметки, которые
уже у нас есть.
Я ^ Г> Note to Self
I *• ►| + J0hr.p/jIcq.iosiv-Bcih/Hcad -irsi HTVLSKhasiersrnoiEicso'i’it/nl
__ J
(Add Sticky No:c то Self j
При щелчке
на кнопке Add
Sticky Note Дляотобра­
to Self (Доба­ Pick up dry Cancel жения заме­
вить клей­ ток мы будем
кую замет­
cleaning cable tv, совершать
ку для себя) who needs итерации по
в localStorage it now? всем заметкам
будет до­ в localStorage
бавляться и добавлять их
заметка. в объектную
модель докумен­
та (РОМ).
Мы также уви­
дим появление
новых клейких
заметок на Мы стилизуем электронные
экране, что клейкие заметки с использова­
Как вы помните, ключами для этих нием CSS, чтобы они были по­
будет происхо­
дить благодаря двух заметок являются sticky_0 " " хожи на настоящие листочки!
добавлению но­ и "stickyЛ ". Мы будем придерживаться
вого элемента нашего соглашения и создадим ключи для
заметок, используя целые числа с воз­
в объектную
модель доку­ растанием: sticky_Z, sticky т. д. м
мента (РОМ)
для каждой за­
метки.

462 глава 9
сохраняем данные локально

Создание интерфейса
Для пачала пам пеобходимо пайти способ вводить текст клей­
ких заметок. И было бы здорово, если бы мы могли видеть
их па страпице, поэтому пам потребуется элемепт, в котором
будут содерж аться все заметки, отображ аемы е па страпице.
Н апиш ем соответствующ ий код, пачав с HTM L-разметки. О т­
кройте свой HTM L-файл и добавьте элем епт <form>, элем епт
<ul> и CSS-ссылку п а пего, как показало пиже:

Вот наш основной HTML-ф айл

/
< ! doctype html>
Mw добавили небольшое количество
CSSj чтобы наши электронные з а ­
<html> м е т к и выглядели более похожими
на настоящие листочки. Эта книга
<head>
не посвящена C SS, но вы можете з а ­
<title>Note to Self</title> глянут ь для справки в данный файл!
Cmeta c h a r s e t = " u t f -8">

<link r e l = ffstylesheet" href = " n o t e t o s e l f .c s s "> . Поместим весь наш


Ja vaS crip t-код в файл
<script s r c = " n o t e t o s e l f .js"></script>
notetoself.js.
</head>

<body>
Мы добавили ф о р м у в качестве интерфейса
<f orm> пользователя для ввода новых заметок.
< input type="text" i d = " n o t e _ t e x t ">

< input t y p e = " b u t t o n " id="add_button" v a l u e="Add S ticky Note to Self">


</form>

Нам также нужно где-т о


<ul i d = " s t i c k i e s ">
ра зм ещ а т ь наши зам ет ки
< /ul> в инт ерф ейсе, поэт ом у мы
</body> собираемся п о м е с т и т ь их
^4 в неупорядоченный список.
</html>
Благодаря CSS каждый
э лем ент списка будет
выглядеть более похожим
на записку -напоминание.

дальше ► 463
написание javascript-кода для заметок

Теперь добавим JavaScript


У пас уже есть все пеобходимое па страпице, а также п ара клейких заметок в localStorage, ожидающих
своего отображ епия. Д авайте сделаем так, чтобы опи появились па страпице, для чего спачала считаем
их из localStorage, а затем поместим в пеупорядочеппы й список (элемепт <ul>), которы й мы только
что создали:
Когда страница загрузит ся, ...которая счит ает осе с у щ е­
мы вызовем функцию (n i t .. ст вую щ ие клейкие зам ет ки
из localStorage и добавит их
в <ul> посредством РОМ.
wi n d o w . o n l o a d = init;
Д ля этого мы будем осу-

Г
щ ест влят ь итерации по всем
function i n i t () { элем ент а м в хранилище.
for (var i = 0; i < l o c a l S t o r a g e .length; i++ Извлекаем каждый ключ.
var key = l o c a l S t o r a g e .k e y (i ) ;
А за т е м убеждаемся, что
if (key.s u b s t r i n g (0, 6) == "sticky") { данный элем ент является
var value = l o c a l S t o r a g e .getltem(key)
за м е т к о й , п у т е м проверки,
начинается ли его ключ со
addStickyToDOM(value);
"sticky". Зачем мы это делаем?
Что Ж, в localStorage м о г у т
' V находиться и другие э л ем е н ­
}
Если это клейкая за м е т к а , ты помим о наших клейких
то мы извлекаем ее значение зам ет о к (подробнее об эт о м
и добавляем на нашу страницу мы поговорим позже).
(посредством РОМ).

И так, теперь пам пеобходимо паписать фупкцию addStickyToDOM,


которая будет вставлять заметки в элемепт <ul>:
Нам передается т е кс т заметки. Необ­
ходимо создать элем ент неупорядочен­
ного списка, а за т е м вст авит ь его.
function addStickyToDOM(value) {
Извлечем элем ент <ul> с id
var stickies = d o c u m e n t .getElementByld (" s t i c k i e s "); ^--
в виде "stickies".
var sticky = d o c u m e n t .c r e a t e E l e m e n t (" l i " );
Создаем элем ент списка
var span = d o c u m e n t .c r e a t e E l e m e n t (" s p a n " ); и присваиваем ем у имя класса
sticky" (чтобы его можно было
span.setAttribute("class", "sticky") ,
стилизовать).
span.innerHTML = value; Задаем содержимое span, где
находится т е кс т заметки.
s t i c k y .a p p e n d C h i l d ( s p a n ) ;

s t i c k i e s .a p p e n d C h i l d ( s t i c k y ) ;
И добавляем span в элем ент списка
"sticky"j который, в свою очередь, добав­
ляем в элем ент <ul> с id в виде "stickies".

464 глава 9
сохраняем данные локально

Время еще одного mecm-gpauBa!


Н аберите приведеппы й выше код в своем элемепте < s c r ip t> и загрузите
его в браузере.
Вот что получилось у пас, когда мы загрузили страпицу в браузере:
О ГЛ О Мои 10 Self
[А *1 + г;юа.м<ш/-eeth/Hcad -1гл HTVLS/ctooiciS'noincce'nuTil d ip
('лад sackv noic 10 srtfj

Pick up dry Cancel


cleaning cable tv,
who needs
it now?

Завершаем создание интерфейса пользователя


О сталось лиш ь активировать форму, чтобы у пас появился способ добавлять повы е заметки.
Д ля этого пеобходимо добавить обработчик, которы й будет вы зы ваться п ри щ елчке па кпопке
A dd Sticky N ote to Self (Добавить клейкую заметку для себя), а также паписать код для создапия
повой заметки. Вот паш код для добавлепия обработчика:
Извлечем ссылку на к н о п ­
ку A d d Sticky Note to Self
Добавьте э т о т новый код (Добавить клейкую з а ­
в свою функцию init: м е т к у для себя).
f u n c tio n i n i t () { у/
var button = document.getElementByld("add_buttonn)
button, onclick = creates ticky; ^___________

И добавим обра­
/ / f o r lo o p goes h e re ботчик., который
Остальная часть кода будет вызываться
в init будет такой же, при ее нажатии.
как раньш е, мы просто Д а нном у об­
экономим м ест о, не п р и ­ работчику мы
водя ее здесь повторно. присвоим имя
createSticky.

дальше ► 465
создание заметок с помощью кода

А вот код для создапия п овой клейкой заметки:


_______ Данный обработчик
^ будет вызываться при Сначала происходит изв ле-
function createsticky о { щелчке кнопкой мыши. чение т е к с т а , введенного
в поле ввода формы.
var value = document.getElementByld("note_text") .value;

var key = ,,sticky_11 + localStorage.length; З а т е м нам нужно создать


localStorage.setltem(key, v a l u e ) ;
уникальный ключ для заметки.
Воспользуемся "s tic k y j', к о н­
катенированным со значением
addstickyToDOM (value); length всего локального х р а н и ­
Д а лее мы добавля­ лища; оно продолжит ув е л и ч и ­
ем новую за м е т к у в ват ьсяj не т ак ли?
%
И наконец, добавляем новый localStorage с использо­
т екст в объект ную модель ванием нашего ключа.
документа для пр едст авле­
ния клейкой заметки.

Теперь вы можете от правлят ься


U еще один те ст-д р а й в ! в п ут еш ест вие на фиджи, а когда

Обязательно попробуйте закрыть окно


браузера, а за т е м сова о т кр ы т ь его. Ну как,
вы по-преж нему видите свои замет ки?

466 глава 9
сохраняем данные локально
4acm°
^адаВ аеМ ы е
B o llp o C b l

Т5
JJ *-
Зачем нам проводить проверку для того, чтобы узнать, Т5-
y j • Я всего лишь перезагрузил страницу, и теперь мои заметки
начинается ли ключ каждого из элементов со строки "sticky"? располагаются в другом порядке!

0 : Как вы помните, все страницы из одного домена (например, 0 : Когда вы добавляете новую заметку, ее элемент добавляется
apple.com) смогут «увидеть» любой элемент, сохраненный другими путем внедрения его в список заметок, поэтому такой листок всегда
страницами в этом домене. Это означает, что если мы не будем будет оказываться в конце списка. Когда вы перезагружаете стра­
внимательно подходить к присваиванию имен нашим ключам, то ницу, заметки добавляются в том порядке, в котором они обнару­
можем вступить в конфликт с другой страницей, которая использует живаются в l o calStorage (а как вы помните, определенный
аналогичные ключи иным путем. Таким образом, это наш способ порядок расположения элементов здесь не гарантируется). Вы
убедиться в том, что элемент является заметкой (а не, к примеру, могли бы подумать, что порядок будет таким же, в каком элементы
порядковым номером или игровым уровнем), прежде чем мы ис­ добавлялись в хранилище, либо они окажутся в каком-то другом
пользуем его значение для своей заметки. обоснованном порядке, однако рассчитывать на это нельзя. По­
чему? Причина заключается в том, что соответствующая специ­
Т5
JJ *-
А что, если в localStorage окажется большое количество фикация не определяет порядок, в силу чего разные браузеры
элементов, включая те, которые не являются клейкими замет­ могут реализовывать его по-своему. Если окажется так, что ваш
ками? Разве будет эффективным осуществление итераций по браузер будет возвращать элементы в порядке, который имеет
всему этому набору элементов? для вас смысл, можете считать, что вам повезло, но не стоит рас­
считывать на данный порядок, поскольку браузер пользователя
0 : Что ж, если речь не идет об очень большом количестве эле­ может упорядочивать ваши элементы по-другому.
ментов, то мы сомневаемся, что вы заметите разницу. Вместе с
тем вы правы, это будет неэффективным, и, возможно, существуют Т5
J; •-
Я часто использую форму for in цикла for. А здесь он
более оптимальные подходы к управлению нашими ключами (о не­ сработает?
которых из них мы вскоре поговорим).

T i-Меня удивило использование значения localStorage.length


в качестве номера заметки в ключе, например:
О ! Сработает. Все будет выглядеть следующим образом:
for (var key in localStorage) {
var value = l o c a l S t o r a g e [ k e y ] ;
nsticky_n + localStorage.length

Зачем мы так поступили?

0 : Нам необходим способ создания новых, уникальных ключей.


Мы могли бы использовать что-то вроде значения времени или
в Можно ли удалять клейкие заметки?

0 : Да, удалять элементы из localStorage можно с помощью


генерировать целое число, которое увеличивалось бы с каждым метода localStorage.remove Item Вы также можете делать
разом. Либо, как отмечалось ранее, можно использовать значение это напрямую, используя консоль браузера. В данной главе мы
length локального хранилища (которое увеличивается каждый продемонстрируем оба этих способа.
раз, когда мы добавляем элемент). Если вы считаете, что такой
подход может оказаться сомнительным, то мы еще вернемся к этой
теме. А если вы так не считали, не беспокойтесь, мы все равно
вернемся к данному вопросу.
ШТУРМ
Т5
Jу -•
Я создал набор заметок в браузере Safari, а затем пере­ Учитывая способ реализации клейких за­
шел на Chrome, но не смог увидеть их в этом браузере. В чем меток, с нашей схемой присваивания имен
причина? возникнет проблема, если пользователь бу­
дет иметь возможность удалять заметки по
f l -• Каждый браузер поддерживает свое собственное локальное своему усмотрению. Как вы думаете, в чем
хранилище. Так что если вы создадите клейкие заметки в Safari,
именно будет заключаться эта проблема?
то сможете увидеть их только в этом браузере.

дальше ► 467
диагностика браузерного хранилища

Прервемся для небольшого запланированного мероприятия


Было бы здорово, если бы существовал ипструмепт для про­
см отра элемептов в вашем localStorage папрямую? Л ибо
ипструмепт для удалепия элемептов или даже для полпой
Сегодняшнее
очистки храпилищ а, чтобы пачать все запово, когда вы будете
спецпредложение
запиматься отладкой?
очистка
Все осповпы е браузеры располагаю т встроеппы м ипструмеп-
localStorage
тарием разработчика, позволяю щ им папрямую исследовать вашего браузера
содерж имое вашего локальпого храпилищ а. Д аппы й ипстру-
м ептарий разпится от браузера к браузеру, поэтому вместо его
полпого исследовапия мы укажем вам правильпое паправле-
пие, после чего вы сможете сами покопаться и узпать, какова
специф ика вашего собствеппого браузера. В качестве прим ера
взгляпем па то, что предлагает браузер Safari:

Mw щелкнули на вкладке Не говоря уже о новых


Resources (Ресурсы), чтобы п р о ­ версиях браузеров, к о т о ­ И нст рум ент а рий р а з р а ­
инспект ироват ь localStorage. рые появляются быстрее, ботчика в браузере Safari
чем мы пиш ем страницы!
n o n Web Inspector —httpi/ZlDcalbDst^Beth/HTMLS^crealStarage/no-tetobJeirhtml i
[ {>s a im
и СПСМ5. Network Scipts Nmeiirst Frcfles Auzls. Cwrata
Key VjJje
Ot Q\mr ■Пара « к а н о и — з на
Hbrty j ftuydMfelr Apple gaNSig^Tl
чение» для каждого
►| | Uatasues
IslitIr.o
▼j у L « jI Si игдд* own t ыж? элемента в хранилище
l o c a l h o '« I
находимся здесь.
►ЩSession
► _? Cpokiev Щелкнув здесь, вы увидите Щелкнув правой кнопкой
►Ш A pfktauS an Cache хранилище! ассоциированное мыши на одном из элемен­
с данным источником. тов хранилища , вы сможе­
те отредактировать или
I
Од этом мы пого­ удалить этот элемент
ворим позже. прямо в данном окне.
Старомодные файлы
cookie на случай, если В браузере Safari мы можем использовать
они вам потребуются. данные инструменты для перезагрузки пред­
ставления Storage (Хранилище) и удаления
С X
выбранного элемента.

Источник хранилища. Здесь мы и споль­ Для активации или доступа к ипструмептарию раз­
зуе м локальные файлы , загружаемые работчика, как мы уже говорили, в разпы х браузерах
из http ://lo c a lh o st, однако это может п ридется поступать по-разпому. П осетите страпицу
быть и доменное и м я, если вы проводи­ h ttp :/ /w ickedlysm art.com /h fh tm l5 / devtools.htm l, что­
т е тестирование на онлайн-сервере. бы узпать, как это сделать имеппо в вашем браузере.

468 глава 9
сохраняем данные локально

По 99ер)кка типа «сделай сам»


Существует еще о д и п способ очистки храпилищ а от ваших элемептов (а также,
как мы вскоре увидим, способ удалепия их поодипочке), которы й потребует от
вас самостоятельного обеспечепия пеболы иой поддержки, прямо из JavaScript.
API-иптерф ейс localStorage вклю чает удобпый метод clear, которы й удаляет
все элементы из вашего локальпого храпилищ а (по крайп ей мере, элементы из
вашего домепа). П осмотрим , как можпо использовать вызов даппого метода па
JavaScript, создав повы й ф айл maintenance.html. Сделав это, добавьте туда при-
ведеппы й пиж е код, и мы пош агово разберем, как оп работает. Это Хороший
< ! doctype html> и н с т р ум е н т для
<html> вашего набора
<head>
Mw добавили одну кнопку
<title>Mainten a n c e < / t i t l e >
на ст р аниц у, а э т о т ^
<meta c h a r s e t = " u t f - 8 ">
код добавит для данной
<script>
кнопки обработчик собы­
w i n d o w . o n l o a d = f u n c t i o n () {
т и й л инициируемых при
var clearButton = d o c u m e n t .g e t E l e m e n t B y l d ("clear_button" ;
c l e a rButton.onclick = clearStorage;
ее нажатии.
}
При щелчке на кнопке будет происхо­
function c l e a r S t o r a g e () { дить вызов функции clearStorage.
l o c a l S t o r a g e .c l e a r () ;
} Данная функция лишь вызывает м ет од localStorage.
</script> clear. Используйт е ее осторожно, поскольку она уд а ­
</head> л и т все элем ент ы , ассоциированные с источником
<body> данной страницы Maintenance!
<form>
<input type= "button" id="clear_button" v a lue="Clear storage" />

</body>
</html>
</form>
Г
А вот наша кнопка. Используйт е
файл m aintenance.htm l всякий р а з,
когда вам понадобится ст ерет ь
все содержимое localStorage (хо р о ­ Данный код уда­
шо подходит для тестирования). лит все элемен­
|Аыпе ты в вашем до­
оаг*ороЖ Н Ь 1
мене!
Н абрав даппы й код, загрузите его в своем браузере.
Теперь у вас есть возмож пость безопаспо (в случае с Если у вас име-
паш им прилож ением для работы с электроппы м и за­ ется сверхценное локальное хранилище
метками N ote to Self) очистить localStorage, поэто­ °гЛ 3аИТ е ° другим проектом в том же
самом домене, то выпишитесь всех своих
му попробуйте это сделать! Н о спачала убедитесь в
элементов, если выполните данный код.
том, что вы разобрались в своем ипструмептарии раз­ просто имейте это в виду...
работчика, чтобы увидеть измепепия.

дальше ► 469
проблема с приложением note to self

У меня возникла проблема. Выполняя упражнения в книге,


я воспользовался своим и знаниями для создания новой электрон­
ной корзины для нашей ком пании. М ое приложение N ote to S e lf перестало
работать. Заглянув в localStorage с пом ощ ью инструментария разработчика
в браузере S a fa ri, я увидел, что нумерация всех м о и х заметок стала беспо­
рядочной: "sticky_ 0 ", "s tic k y _ l" / "sticky_ 4 ", "sticky_ 8 ", "sticky_15", "sticky_16",
s ticky_ 2 3 ", "sticky_ 4 2 ". У меня такое чувство, что причина в том, что я создаю
в localStorage и другие элементы одновременно с заметками.
Что же происходит?!

Вы столкнулись с основным недостатком проектирования.


Ладно, приш ло время сказать все начистоту: ранее мы создали отлич­
ное небольш ое прилож ение, которое должно безупречно работать
довольно долгое время, пока вы не начнете вставлять какие-либо дру­
гие элементы в localStorage (как поступил Джоэль в случае со своей
электронной корзиной). Как только вы сделаете это, вся наша схема
отслеж ивания клейких зам еток перестанет работать или, по крайней
мере, больше не будет нормально работать. h с этиМ>
Если бы еду
П ричина в следующем.

Прежде всего наши клей кие заметки нумеруются от нуля до числа, которое
обозначает общее и х количество (минус один):

ооооо
Ms tic k y _ 0 " "s tic k y _ 1 " "s tic k y _ 2 " "s tic k y _ 3 " "s tic k y _ 4 "

Пять за м ет о к с м е т ка м и от О до 4.
Чтобы добавить новую заметку, м ы подсчиты ваем количество элементов
в локальном хранилищ е и создаем новый кл ю ч исходя из получивш егося
количества:

var key = "sticky " + localStorage.lengt


"s tic k y _ 5 "

А чтобы отобразить все клейкие заметки, м ы осуществляем итерацию


от нуля до значения length л о кал ьного хранилищ а (м инус один):

^ ^ ^ ^ ^ ^
"s tic k y _ 0 " "s tic k y _ 1 " ,,s tic k y _ 2 " "sticky_Z" ,,s tic k y _ 4 ” " s tic k y .S ”
ч * 4 2
Значением length на данный м о м е н т является
поэт ом у мы осуществляем ит ерацию от О до 5,
отображая зам ет ки от "sticky_0" до "sticky_S".

470 глава 9
сохраняем данные локально

Вот элем ент ы , которые


Теперь добавим элементы из электронной корзины Джоэля Джоэле? использует в коде
в localStorage! своей электронной корзины.
ь/

'sticky_0" "sticky_1" "sticky_2" "sticky_3" "sticky_4" "sticky_5" "элемент 1 "элемент 2 "элемент 3


_____________________________________________________________ электроннойэлектроннойэлектронной
— - - ________ корзины" корзины" корзины"
Теперь у нас в localst„rae , в су м м е имеете* d e t , m
элементов.


var key = "sticky_n + localStorage.length; - ' о
"sticky_9”
При создании новой за м ет ки значением length локального
хранилища будет <?, поэт ом у мы создаем за м е т к у с именем
sticky_я". Х м , не похоже, что это будет правильным.
Когда нам потребуется совершить итерацию по заметкам для того, чтобы
отобразить их, у нас возникнет проблема:

QQ Q Q Q Q
"sticky_0” "sticky_1" "sticky_2" ”sticky_3" ”sticky_4" “sticky_5” — ’ ------- ^ — J '— v— '
Q
“sticky_9”
4 Я 3 Ч -Л
Теперь значением length является НО (мы только что
добавили новую за м е т к у ), поэт ом у итерация будет \■ # T
осуществляться от О до Я с отображением каждой О >" s t ic k y ^ , s ic у_
зам ет ки от "sticky_0" до "sticky_4". WAU "st'C^yS У нас Иет'

Возьми в руку карандаш

Отметьте флажками, какие проблемы может вызывать наша текущая реализация:

[ | Отображение клейких заметок будет происходить неэффективно, если в localStorage


присутствует большое количество элементов, которые не являются заметками.

j [ Клейкая заметка может быть перезаписана методом setltem, если объем localStorage
уменьшится, несмотря на то что другое приложение удалит все свои элементы.

Сложно быстро сказать, сколько имеется клейких заметок; вам придется осуществлять
итерацию по каждому элементу в localStorage, чтобы извлечь все заметки.

□ Используйте файлы cookie, поскольку такой подход должен оказаться проще!

дальше ► 471
сохранение массивов

Если бы тол ько м ож но бы ло со­


хранить массив в localStorage. М ы м о г­
ли бы использовать его для размещения всех
кл ю ч е й заметок, а также без труда узнать
количество хранящихся у нас заметок. Одна­
ко всем известно, что в localStorage можно
сохранять только строки, поэтому об этом
можно лишь мечтать...

472 глава 9
сохраняем данные локально

У нас есть технология...


Мы пе обмапывали вас, когда отмечали, что вы сможете сохрапять только строки в качестве зп ачепий
элемептов localStorage. Одпако это пе вся правда, поскольку у вас всегда будет возможпость преоб­
разовать массив (или объект) в строку, прежде чем сохрапять его. Похоже паж ульпичество, одпако это
абсолю тпо легитим пы й способ сохрапепия в localStorage типов даппых, которы е пе являю тся string.
Мы зпаем, что вам ужаспо хочется п ерей ти к рассм отрению п одробностей сохрапепия массивов,
по прежде, чем мы это сделаем, взгляпем п а то, как массив сможет реш ить паши (и Джоэля) проблемы.

Вернемся немного назад и представим, что у нас имеется шесть клейких за­
меток В localStorage:

"sticky_0" "sticky_1" "sticky_2" "sticky_3" "sticky_4" "sticky_5”

И зам ет ки , и массив
Шесть клейких зам ет ок с м е т к а м и от О до 5 "stickiesArray" располагаются
localStorage.

И, допустим, у нас в localStorage есть массив "stickiesArray":


Каждый элем ент
"sticky_0" "sticky_1" "sticky_2" "sticky_3" "sticky_4" "sticky_5" массива "stickiesArray"
"stickiesArray" является ключом для
зам ет ки в localStorage.
Теперь добавим новую клейкую заметку. Назовем ее "sticky_815". Почему
такое большое число? А потому, что нас больше не будет волновать, как она
называется, пока ее ключ является уникальным. Таким образом, чтобы доба­
вить заметку, мы просто вносим "sticky_815" в массив, а затем сохраняем
элемент для данной заметки точно так же, как делали раньше. Например:
У нас появилась
еще одна зам ет ка
в localStorage.

"sticky_0" "sticky_1" "sticky_2" "sticky_3" ,,sticky_4" "sticky_5"


"sticky_815"

Семь клейких заметок: их ключи дольше неважны, Мы также р а с ­


они просто должны быть уникальными. ширили массив
"stickiesArray"
sticky_0" "sticky_1" ,,sticky_2" "sticky_3" ,,sticky_4" "sticky_5" "sticky_815
на одно значение.
"stickiesArray"

дальше ► 473
переписываем приложение с использованием массива

Дорабаты ваем наше приложение с использованием массива


Итак, мы приблизительно зпаем, как собираем ся отслеж ивать паш и заметки с помощью массива. Одпа­
ко пойдем пемпого дальше и убедимся, что мы сможем осуществлять и терац и и и отображ ать все клей­
кие заметки. В текущем коде мы отображ аем все заметки в фупкции init. А мож по ли переписать ее с
использованием массива? Спачала взгляпем па имею щ ийся код, а затем посмотрим, как оп изм епится
(падеемся, в лучшую сторону) п ри использовании массива. П ока пе печатайте даппы й код; мы сосредо­
точим ся па измепепиях, которы е пам пеобходимо впести сейчас, а пе па том, чтобы сделать этот код
«нулепепробиваемым». Таким мы его сделаем чуть позже.

Д о... Вот наш старый код, который полагается


function init () { на т о > Что У зам е т о к будут специфические
// b u t t o n code here. . . ^ ЫШНа: ^ у . О , S t k k y . l и т. д.
for (var i = 0; i < localStorage.length; i++) {

var key = localStorage.key(i) ; ^ ^ ^ ^ |Д0 HeaKKypamH0,


if (key.substr (0 , 6) == "sticky") { е с л и вдуматься.
var value = l o c a l S t o r a g e .g e t I t e m ( k e y ) ;

addstickyToDOM(value); л К ак мы т еперь знаем, здесь возможны бреши


} ^ поскольку нельзя рассчит ывать на то, что все
} зам ет ки обязательно будут при сут ст воват ь
} т а м , если присваивать им имена исходя из
одщего количества элемент ов в localStorage.

Новый Ц улучшенный Начинаем с извлечения stickiesArray


из localStorage.
function i n i t () {
// but t o n code here...
var stickiesArray = localStorage["stickiesArray"];
4 Нам необходимо удостовериться
в т о м j что в localStorage есть
if (!stickiesArray) { ______________
массив- Если его т а м не будет ,
stickiesArray = [] ; т0 у\ды создадим пустой массив.
localStorage.setItem("stickiesArray" , stickiesArray);
) Совершаем ПРИМЕЧАНИЕ: fa все
рации, по м а с с в у .— V 1Щ‘ He З н а е т е , как с°~
Г ^ хранят ь и извлекать
for (var i = 0; i < stickiesArray.length; i+ + ) { м а с с и в ы , содержащ ееся
var key = stickiesArray[i] ; в localStorage, п о эт о м у
var value = localStorage [key] ; ^ р а с с ма тр и в а й те эт о
addstickyToDOM (value) ; "*) как псе&докод, пока Мы
Каждый элем ент массива яв л я- вам все не покажем.
^ ется ключом клейкой за м ет к и, Нам пот ребует ся вн е-
} . „ п оэт ом у мы используем его для ст и совсем небольшое
Добавляем со от вет ст у ю щ е е з извлечения соот вет ст вую щ его дополнение, чтобы он
в объектную модель документа (Р ОМ) элеМента мз locaisto ra g e. р а6отал.
точно так Же, как делали это раньше.

474 глава 9
сохраняем данные локально

Нам по-прежнему нужно выяснить, как ф актически осущ ествляется


ПрЗЖНСШС со хр ан ени е м ассива в lo c alS to ra g e.
Вы уже могли догадаться, что у нас есть возможность использовать JSON для создания
строкового представления массива. И если так и было, то вы правы. Располагая таким пред­
ставлением, ВЫ сможете сохранить его В localStorage.
Как вы помните, в API-интерфейсе JSON имеются только два метода: s tringify и parse.
Задействуем данные методы и завершим функцию ini t (посмотрите решение данного
упражнения в конце главы, прежде чем двинетесь дальше):

function i n i t () {

// but t o n code here...

var sticki e s A r r a y = l o c a l S t o r a g e [" s t i c k i e s A r r a y " ];


if (!stickiesArray) {

sticki e s A r r a y = [];
l o c a l S t o r a g e .s e t l t e m (" s t i c k i e s A r r a y " , __________ ,(stickiesArray)) ;

} else {
s ticki e s A r r a y = ____________ (stickiesArray) ; Me?/ добавили данное предложе­
} ние else, поскольку вам п о т р е ­
буется кое-чт о п редпринят ь,
for (var i = 0; i < s t i c k i e s A r r a y .length; i++) {
если вы извлечете массив из
var key = s t i c k i e s A r r a y [ i ] ; localStorage (поскольку это
var value = l o c a l S t o r a g e [ k e y ] ; будет строка, а не массив).
addStickyToDOM(value);

Внесение изменений в createSticky с целью использования массива


Мы п о ч т и п о л п о с т ь ю рассм отрели паше прилож епие. Осталось лишь доработать метод createSticky,
которы й, как вы помпите, извлекает текст для клейкой заметки из формы , сохрапяет его локальпо, а за­
тем отображает. Взгляпем па текущую реализацию , преж де чем впесем в пее измепепия:
Вместо использования значе-
function c r e a t e S t i c k y () { ния length локального хр а н и ­
var value = d o c u m e n t .g e t E l e m e n t B y l d (" n o t e _ t e x t " ).v a l u e ; лища для генерирования ключа
var key = "sticky_" + localStorage.length;
(что, как мы уже видели,
' <- может ст а т ь причиной п р о ­
l o c a l S t o r a g e .setltem(key, value)

addStickyToDOM(value);
) блем) нам пот ребует ся соз­
дать более уникальный клю ч.

Нам также нужно dot...


stickiesArray и сохранить э т о т массиЬ

дальше ► 475
добавление уникального идентификатора Часто
ЧаДаВаеМые
В опросы
Ч то именно необходимо изменить?
Что это за значение в виде количества
f t
Есть две вещи, которы е пеобходимо изм епить в createSticky. мил;
миллисекунд, прошедших с 1970 года?
Во-первых, пам потребуется п овы й способ геп ери ровап ия упи-
кальпого клю ча для каждой клейкой заметки. Во-вторых, пам
будет пужпо изм епить код, чтобы оп сохрапял определеппую
О:' Вы, возможно, уже знаете, что миллисекун­
да представляет собой тысячную долю секунды,
а метод getTime возвращает значение, ко­
заметку в stickiesArray в localStorage.
торое является общим количеством миллисе­

ф Создание уникального ключа для клейкой заметки. кунд, прошедших с 1970 года. Почему именно с
1970 года? Данное поведение унаследовано от
Существует масса способов создапия упикальпых клю­ операционной системы Unix, которая определя­
чей. Мы могли бы использовать зп ачеп ия даты и време- ла время таким способом. Несмотря на то что
пи, либо геперировать причудливые случайпые 64-бит- такой подход неидеален (например, значения
пые числа, либо задействовать в сочетапии с пашим времени до 1970 года представляются в виде
п рилож епием API-иптерфейс, связаппы й с атомпы ми отрицательны х чисел), он окажется кстати,
часами. И спользование зп ачеп ий даты и врем епи пред­ когда вам потребуется уникальное число или
ставляется хорош им и легким реш епием. JavaScript под­ возникнет необходимость отслеживать время
в JavaScript-коде.
держ ивает объект Date, которы й возвращ ает зпачепие в
виде количества миллисекупд, прош едш их с 1970 года;
даппое зпачепие должпо оказаться достаточпо упикаль- Разве применение методов parse и
пым (если только вы пе собираетесь создавать свои за­ stringify в случае с JSON-типами не явля­
ется довольно неэффективным с точки
метки с очень высокой скоростью):
зрения производительности? А если мой
— Создаем объект P a te, а за т е м извлекаем массив сильно разрастется, то не окажется
^ значение текущего времени в миллисекундах. ли так, что и сохранение будет осущест­
var currentDate = new Date() ; ^ л w _ вляться неэффективно?
Наш новый код для
var time = currentDate .getTime () ; > генерирования уни -
„ ^. . „ , ^.
var key = "sticky_" + time; J\ кального клю ча. 0 : Теоретически, да, по обоим упомянутым
вами пунктам. Однако в случае с типичными за­

А за т е м генерируем ключ п у т е м добавления получен­ дачами программирования веб-страниц обычно


ного значения в миллисекундах в ст року " stickyj1. это не является проблемой. Вместе с тем, если
вы занимаетесь реализацией серьезного при­
ф Сохранение новой заметки в массиве. ложения с высокими требованиями относитель­

Теперь, когда у пас имеется способ геп ери ровап ия упи- но сохранения данных, то можете столкнуться
с проблемами, используя JSON для преобразо­
кальпого ключа, пам пеобходимо сохрапить текст заметки
вания элементов в строки и обратно.
с этим клю чом и добавить даппы й ключ в stickiesArray.
П осмотрим , как это можпо сделать, а потом объедипим
весь код. Вместо того чтобы повт орят ь весь код
Сначала извлечем массив stickiesArray. для извлечения и проверки stickiesArray,
как мы это делали в функции init (на п р е ­
var stickiesArray = getStickiesArray(); дыдущей странице), мы создадим новую
функцию. Д о этого мы дойдем позже.
localStorage.setltem(key, value)
З а т е м сохраняем ключ с его значением,
stickiesArray.push(key);
как делали раньше (только речь здесь
localStorage.set l t e m ("stickiesArray" идет о нашем новом ключе).

JSON.stringify(stickiesArray) -Д алее используем мет од push,


который добавляет ключ в конец
IT
И сохраняем массив обратно в localStorage, предвари­ массива stickiesArray.
тельно преобразовав его с помощ ью метода stringify.
476 глава 9
сохраняем данные локально

О тлично, как только все это зара­


ботает, я аналогичны м образом доработаю
свою электронную корзину, и эти два прилож е­
ния см о гут функционировать из од н о го и то го
же источника без проблем. Мне также нравится
использовать массив; он значительно облегчает
отслеживание всего!

Соединяем все воедино


П ора и птегрировать весь новы й код на основе массива, вклю­
чая фупкции init и createSticky. Д ля этого мы сначала абстра­
гируем небольш ой ф рагм ент кода, которы й необходим в обе­
их фупкциях, — это код, извлекаю щ ий массив stickiesArray
из localStorage. Вы видели его в функции init, и он снова
пам понадобится в createSticky. П оместим данны й код в метод
get Stickies Array — on уже долж еп быть вам зпаком, если исхо­
дить из того кода, которы й мы с вами уже рассмотрели:

Сначала мы и з ­
влекаем э лем е нт
"stickiesArray" из
localStorage.
function getStickiesArray() {
Г
var stickiesArray = localStorage.ge t l t e m ("stickiesArray" И если все-т аки массив
Если это будет первая наша будет о т с у т с т в о в а т ь ,
if (!stickiesArray) загрузка данного приложения, то мы создадим пустой
то элем ент "stickiesArray" массивj а за т е м сохраним
stickiesArray = []
может от сут ст воват ь. его в localStorage.
localStorage.set l t e m ("stickiesArray" JSON.stringify(stickiesArray)

Не забудьте сперва п р е ­
} else {
образовать его с п о м о ­
щью метода stringify!
stickiesArray = JSON.parse(stickiesArray);.
3 прот ивном случае мы все же
находим в localStorage массив,
в отношении которого нам п о ­
return stickiesArray; т ребует ся прим ени т ь мет од
3 любом случае parse, чтобы преобразовать его
в итоге у нас 6ydev в JavaScript-Maccu6.
массив, который
мы возвратим.

дальше ► 477
интеграция всего кода

Соединяем все воедино (продолжение...)


Написав getStickiesArray, взгляпем паупрощ еппы е, ф ипальпы е версии фупкций init и createSticky.
Н аберите приведеппы й далее код:
. Как вы поллните, мы т а к -
function init о { у' же задали здесь, в методе
init обработчик событий,
var button = document. getElementByld (" add_button") ; к а с а И ) 1 ц и Х С Я button.
button.onclick = createSticky;
Д алее мы извлекаем массив
с ключами зам ет ок, которые
var stickiesArray = getStickiesArray () ; ^ ----- — б нем содержатся.
Теперь мы будем о сущ ест -
влять итерацию по м а е -
f o r (var i = 0; i < stickiesArray.length; i++) { cug stickiesArray (не no
var key = stickiesArray [i] ; -------- ^ э л е м е н т а м localStorage!).
Каждый элем ент в массиве является
var value = localStorage [key] ; клю чом для заметки. Извлечем их.
addstickyToDOM (value) ; т а к же извлечем его
ч значение из localStorage.
} И добавим в объектную модель документа
(РОМ) точно т ак же, как делали раньше.

Закопчив с init, пам остается лиш ь разобраться с createSticky:

Начинаем с извлечения
function createSticky () { массива stickiesArray.
var stickiesArray = getStickiesArray () ; Л а л е ес о з д а д и м уникальныи
-X к л ю ч для нашей новой заметки.
var currentDate = new Date() ;

var key = "sticky_" + currentDate . getTime () ; ) — _ Добавляем пару


var value = document.getElementByld ("note_text"). v a lue; «КЛЮЧ значение»
/ зам ет ки в localStorage.
localStorage.setltem(key, value); ^ ----

stickiesArray .push (key) ; ч И добавляем новый ключ в массив stickiesArray...


localStorage.setltem("stickiesArray" , JSON.stringify(stickiesArray) ) ;

addstickyToDOM(value); с А за т е м применяем м ет од
j stringify для преобразования
Наконец, обновляем страницу массива и записываем его
с использованием новой за м ет ки обратно в localStorage.
п у т е м ее добавления в РОМ.

478 глава 9
сохраняем данны е локально

Тест-драйв!
(Aaatdcfcyncaiataf-,
Н а б е р и т е весь и р и в е д е и п ы й в ы ш е к о д , о ч и с т и т е
у себя l o c a l S t o r a g e , ч т о б ы п а ч а т ь с ч и с т о г о л и ста . Pick up dry Cancel Buy another
З а гр у з и т е д а п п ы й ко д , в резул ьта те ч е го в ы д о л ж - cleaning сable tv, Apple
п ы у в и д е ть т о ч п о т а к о е ж е п о в е д е п и е , к а к и в п р о ­ who needs gadget
it now?
ш л ы й раз. Д ж о эль, т ы у в и д и ш ь , ч т о т е п е р ь т в о й
к о д р а б о та е т д о л ж п ы м о б р а зо м !
J
Часш °

^адаВ аеМ ы е
B o llp o C b l

Tj J5*- Мы используем вить план относительно того, какие име­ Выбирайте схему
"sticky_" как на вы будете присваивать элементам.
префикс для имен наших элементов присваивания имеи
localStorage. А существует ли согла­
1Если у меня будет много клейких
шение относительно схем присваи­
заметок, то мой массив stickiesArray
для своих элементов
вания имен элементам localStorage?
станет очень длинным. Это будет про­
блемой?
localStorage, которая ие
! Соглашения, касающегося присваи­
вания имен элементам l o c a l S t o r a g e ,
! Если только вы не создадите тыся­
приведет к конфликтам
не существует. Если ваше приложение
располагается на небольшом сайте в
чи заметок. В противном случае это не
должно превратиться в проблему (а если
с другими приложениями
домене, который находится под вашим
контролем, то с присваиванием имен не
вы все же создадите тысячи заметок, то
нам хотелось бы узнать, как вам уда­
в том же самом домеие.
должно возникнуть проблем, поскольку
лось оказаться столько продуктивным!).
вы будете осведомлены обо всех именах,
В наши дни JavaScript работает довольно
которые используются разными страни­
цами на данном сайте. Мы считаем, что
быстро.
Если вам потребуется
хорошей идеей будет использовать имя,
которое является индикатором страницы
или веб-приложения, полагающегося
на элемент с данным именем. Таким
& Просто чтобы прояснить ситу­
ацию: мы сможем сохранить любой
объект в localStorage, всего лишь
сохранить массивы и м
объекты в localStorage,
образом, " s t i c k y _ " помогает нам предварительно преобразовав его
запомнить, что такие элементы связаны с помощью метода stringify A P I- используйте JSON.
с приложением Note to Self для работы интерфейса JSON?
с электронными заметками. stringify для создания
& Если мое приложение Note to
Self является лишь одним из многих
приложений в домене, то мне нужно
0 : Все верно. JSON-строки пред­
ставляют собой упрощенные версии
JavaScript-объектов, а наиболее простые
JavaScript-объекты могут быть преоб­
значения, которое
можно буцет сохранить,
беспокоиться о потенциальных кон­ разованы в строки с помощью JSON и
фликтах? сохранены в l o c a l S t o r a g e . Сюда и задействуйте
относятся массивы (в чем вы убедились
0 : Да. Вам (или тому, кто управляет ранее), а также объекты, содержащие JSON.parse иосле того,
веб-сайтами в соответствующем домене) имена свойств и значения, как вы вскоре
в данном случае будет полезно соста­ увидите. как извлечете его.
дальш е ► 479
еще одна т ребуемая ф ункция: удаление

—' Трудно разобраться во всех \


своих делах, если после того,
как и х сделаешь, нельзя избавить­
ся от листочков, на которы х они были
записаны. Нельзя л и снабдить и х
ф ункцией удаления? >

Buy another
Pick UP dTY Apple
cleaning gadget

Learn tWW
db -clutter
Go grocery < vi d e o >
shopping
my d e ^ works

Find my
Order
mobile
Tweetshirt
phone
t-slni*

Learn how
Drink more
Get rid of to meditate
coffee
some of
these sticky

Б удьт е осторожны
Удаление клейких заметок с ост рыми предмет ами!

Она нрава: дан ное н рнлож енне не будет иметь большого уснеха,
если он о н е но зв о лит удалять заметки. Мы уже уноминали метод
l o c a l S t o r a g e . re m o v eltem , однако не беседовали о нем. М етод
remove I t e m нриним ает ключ элемента и удаляет данны й элемент
и з lo c a lS to r a g e :

lo c a l S t o r a g e . re m o v eltem (k ey );

r e m o v e l t e m и м е е т один
Д а н н ы й м е т о д у д а л я е т с о дер­ п а р а м е т р : кл ю ч э л е м е н т а ,
жащийся в localStorage э л е ­ подлежащего у д а л е н и ю ,
м е н т с о пр еделен ны м к л ю ч о м .

Все это кажется довольно нросты м, не так ли? Н о если задуматься,


то удаление клейкой заметки не ограничивается лишь вы зовом м етода
r e m o v e lt e m —нам также нотребуется разобраться со s t i c k i e s A r r a y . . .

480 глава 9
сохраняем данны е локально

^Возьми в руку карандаш


Давайте удалим клейкую заметку!
Ниже приведено сод ерж им ое l o c a l S t o r a g e . У вас имеется весь необходи­
мый JavaScript-код наряду с методом rem oveltem . Набросайте карандаш ом
на бумаге то, что нуж н о сделать, чтобы удалить s t ic k y _ 1 3 0 4 2 2 00 0 6342 из
l o c a l S t o r a g e . Сделав это, напиш ите внизу псевдокод, чтобы показать, ка к вы
собираетесь писать свой настоящ ий код.

"sticky_1304294652202" "sticky_1304220006342" "sticky_1304221683892" "sticky_1304221742310" "элемент 1 "элемент 2


электронной электронной
корзины" корзины"

"sticky_1304294652202" "sticky_1304220006342" "sticky_1304221742310" "sticky_1304221683892"


"stickiesArray"

Свой псевдокод
н а п и ш и т е здесь.

дальш е ► 481
реш ение упражнения

Возьми в руку карандаш


Решение Давайте удалим клейкую заметку!
Ниже приведено сод ерж им ое l o c a l S t o r a g e . У вас имеется весь необходи­
мый JavaScript-код наряду с методом rem oveltem . Набросайте карандаш ом
на бумаге то, что нуж н о сделать, чтобы удалить s t ic k y _ 1 3 0 4 2 2 0 00 6342 из
l o c a l S t o r a g e . Сделав это, напиш ите внизу псевдокод, чтобы показать, ка к вы
собираетесь писать свой настоящ ий код. Вот наше реш ение этого упр аж н е н ия.

l o c a l S t o r a g e r e m o v e i t e m C s > t i c k y ^ 0 4 Z Z 0 0 0 ^ 3 4 Z ),

I'lAXOQiieCOOnO" "s tic k y /l304220^)6342” ",,sticky_1304221683892"


"sticky_1304294652202" c tin l/u "sticky_1304221742310" 'Ч п а м А и т 41
"элемент ’Ч п о и о м т 2
"элемент
/ электронной электронной
корзины" корзины"

sticky_1304294652202" "s [006342" "sticky_1304221742310" "sticky_1304221683892


"stickiesArray"

1). Удалить клейкую зам ет ку с ключом "stickyjL304ZZ000<b34-Z"


из localStorage с помощью метода localStorage.removeltem.
2). Извлечь stickiesArray.
3). Удалить элемент с ключом- 'sticky jL304-ZZ000<b34-Z"
из stickiesArray.
4). Записать stickiesArray обратно в localStorage (предварительно
преобразовав его с помощью метода stringify).
5). Найти "sticky_1304ZZ000<Z>34Z" в объектной модели
документа (РОМ) и удалить ее.

482 глава 9
сохраняем данны е локально

Функция deleteSticky
В ы с о с та в и л и п л а н т о г о , к а к будет о с у щ е с тв л я ть с я удаление к л е й к и х
за м е т о к, н о э т о м у да в а й те в згл я н е м н а ф у н к ц и ю d e l e t e S t i c k y :

Сначала мы у д а ля е м з а м е т к у И спользуем функцию


из localStorage с п о м о щ ь ю м е т о д а ts tic k ie s A r r a y для из
r e m o v e lte m , передав е м у кл ю ч за лечения stickiesA rray
м е т к и , подлежащей удалению .
из localStorage.
fu n ctio n d e le te S tic k y (k e y ) { £ Убеждаемся в т о м , чт о
у нас и м е е т с я stickiesA rray
lo c a l S t o r a g e . rem o v eltem (k ey ); (на всякий слу ч а й ), а з а ­
var s tic k ie s A r r a y g e t S t i c k i e s A r r a y (); т е м со вер ш аем и т е р а ц и ю
по м а ссиву в поисках клю ча,
if (stick iesA r ra y ) {
к от ор ы й х о т и м уд а ли т ь .
for (var i = 0; i < s t i c k i e s A r r a y . l e n g t h ; i+ +b)
) {
if (key == s t i c k i e s A r r a y [ i ] ) { ^Отыскав требуемый ключ, удаляем
s t ic k ie s A r r a y . s p l i c e ( i , 1);
его из массива с помощью splice.

} sPllce удаляет элементы из массива, начиная с пози -


} ции, обусловленной первым аргументом (Г), при этом
количество удаляемых элементов окажется таким,
как указано во втором аргументе (г).

lo c a l S t o r a g e . s e t lt e m ( " s t ic k ie s A r r a y " , J S O N .s t r in g if y ( s tic k ie s A r r a y ) );

Наконец, сохраняем stickiesArray


(при этом соответствующий
ключ из него уже удален) обратно
в localStorage.

Я разобралась в коде, однако


не м о гу понять, как м ы извлекаем
кл ю ч для передачи d e le te S tic k y . Если вду­
маться, то как пользователь вообще см о­
жет выбрать заметку для удаления?

дальш е ► 483
в ы бо р замет ок с п ом ощ ью h tm l и ja va s c rip t

Как выбрать заметку для удаления?


Н а м н е о б х о д и м о о б е с н е ч и т ь для п о л ь з о в а те л я с н о с о б в ы ­
Pick up dry Cancel
б и р а т ь за м е т ку для удал ения. М ы м о гл и б ы н о й т и з а т е й ­ Buy another
cleaning cable tv,
л и в ы м п у те м и д о б а в и т ь н о н е б о л ь ш о й н и к т о гр а м м е уда­
Apple
who needs gadget
л е н и я для к а ж д о й з а м е т к и , о д н а ко в н а ш е м н р и л о ж е н и и it now?
N o te to S e lf м ы н о с т у н и м н а м н о го н р о щ е : будем н р о с т о уда­
л я ть о н р е д е л е н п у ю зам етку, е сли п о л ь зо в а те л ь щ е л к н е т н а
н е й . Э то , в о з м о ж н о , н е самая л уч ш а я р е а л и за ц и я с т о ч к и
з р е н и я уд об ства н о л ь з о в а н и я , о д н а ко н р о с т а я .
Д л я р е а л и з а ц и и э т о го н а м сначала п о т р е б у е т с я в н е с т и Когда мы щ е л к н е м на к л е й ­
и з м е н е н и я в н а ш и к л е й к и е за м е т ки , ч т о б ы м ы с м о гл и в ы ­ кой з а м е т к е с п о м о щ ь ю
я в л я ть , когда п о л ьзо в а те л ь щ е л ка е т н а за м е тке , н о сл е ч е го м ы ш и , она б удет удалена.
не р е д а д и м ее ф у н к ц и и d e l e t e S t i c k y . М н о г о е и з э т о го
д о л ж н о н р о и с х о д и т ь в ф у н к ц и и addStickyToDOM:

т е , пр
замет ку. ^ ^ в и з ° ве ° т п р о м -
и
f u n c t i o n addStickyToDOM(key, v a l u e ) {

v a r s t i c k i e s = docum ent. g e tE le m e n tB y ld (" s t i c k i e s r

v a r s t i c k y = docum ent. c r e a t e E le m e n t (" l i Д о б а в л я е м уни ка льны й и д е н т и ф и к а т о р


в случае с э л е м е н т о м <li>> ко т о р ы й
sticky.setAttribute ("id" , key) ;
п р е д с т а в л я е т к л е й к у ю з а м е т к у в РОМ.
v a r sp an = d o c u m e n t . c r e a t e E l e m e n t ( "span М ы д ела ем э т о для т о го , чтобы ф у н к ­
ция d e le te S tic k y зн а ла , на какой з а м е т к е
s p a n .s e t A t t r i b u t e (" c la s s " , " s t ic k y " ) ;
вы щ елкн ули. Поскольку на м уже и з -
span.innerHTML = s t i c k y O b j . v a l u e ; ве с т но , ч т о клю ч з а м е т к и у никал е н,
s t i c k y . ap p e n d C h ild (sp a n ); будем п р о с т о и с п о ль з о ва т ь его как
идент ификат ор.
s t i c k i e s . a p p e n d C h ild ( s t i c k y ) ;
Мы также добавляем обработчик
sticky.onclick = deleteSticky; событий click для каждой
клейкой
з а м е т к и При щ елчке на з а м е т к е б у ­
дет п р ои с хо д и т ь вызов deleteS ticky.

*^ т пражненке
аЖ н Ваша задача — обновить весь код таким образом, чтобы везде, где мы будем вызывать
addStickyToDOM, мы передавали ключ, а также значение. Вам не должно составить тру­
да найти эти места. Выполнив данное задание, посмотрите его решение в конце главы,
чтобы проверить свои результаты.
Не п р о п у с к а й т е э т о у п р а ж н е -
ние, иначе п р е д с т о я щ и й т е с т -
драйв окажется неудачным!

484 глава 9
сохраняем данны е локально

Как извлечь заметку зля удаления, используя объект event


Для каждой заметки у нас на данны й момент имеется обработчик собы тий, ведущий нрослушивание со­
бы тий c l i c k . Когда вы щелкнете на заметке, н р ои зой дет вызов функции d e l e t e S t i c k y , к оторой будет
нередан объект e v e n t с и нф орм ацией о соответствую щ ем собы тии, нанрим ер на каком элем енте щелк-
пул пользователь. Мы мож ем обратиться к e v e n t . t a r g e t , чтобы сказать, на какой заметке нроизош ел
щелчок. Давайте бол ее нристально носм отрим , что нроизойдет, когда вы щ елкнете на заметке.
Если вы щелкнете на Если вы щелкне­
желтой части заметки, те на тексте,
то event.target будет эле­ то event.target
мент <(/>. Это именно то, будет <span> < Cancef Buy another
саЫс tv,
что нам нужно, поскольку внутри <//’>, who needs
Apple

<(i> теперь имеет иден­ а это не то, it now?


тификатор в виде ключа что нам нужно.
клейкой заметки.

I
< l i i d = " s t i c k y _ 1 3 0 4 2 70008375"> Э т о HTML для
зам ет ки, к о т о ­
< sp an c l a s s = " s t i c k y " > P i c k up d r y c l e a n i n g < / s p a n >
р у ю м ы создаем
< /li>
в addStickyToD O M .
Так или иначе , о б ъ е к т e ven t,
ta r g e t — э т о э л е м е н т , на к о т о р о м вы щ е л к н у л и
сгенерированный в а ш и м щ е л ч ­
и кот о ры й с генерировал о б ъ е к т event. Мы м ож ем и з ­
к о м > п ер едает ся d eleteSticky.
влечь и д е н т и ф и к а т о р данного э л е м е н т а из свойст ва
target. Если t a r g e t я вля е т ся <(/>, т о все в порядке.
f u n c t i o n d e l e t e S t i c k y (е) { Если ta r g e t окажется <span>,
v a r k ey = e . t a r g e t . i d ; т о нам п о т р е б у е т с я извлечь
if ( e . t a r g e t . tagN am e. t o L o w e r C a s e () == "span") {' идент ификат ор родит ель­
ского э л е м е н т а , т о е с т ь <(/*>
k ey = e . t a r g e t . p a r e n t N o d e . i d ;
(<Ч> — э т о э л е м е н т с и д е н т и ­
} ф и к а т о р о м , ко т о р ы й я вля ет ся
lo c a lS t o r a g e . rem o v eltem (k ey ); необходимым на м клю чом).
var s t ic k ie s A r r a y = g e t S t i c k i e s A r r a y (); Теперь мы м ож ем в о с ­
if (stick iesA r ra y ) { п о ль зо ва т ь с я к л ю ч о м
for (var i = 0; i < s t i c k i e s A r r a y . l e n g t h ; i+ +) { для удаления э л е м е н т а
из localStorage , а также
if (k e y == s t i c k i e s A r r a y [ i ] ) {
из stickiesArray.
s t i c k i e s A r r a y . s p l i c e ( i , 1);
}
}
lo c a l S t o r a g e . s e t I t e m (" s tic k ie s A r r a y " , J S O N .s tr in g ify (s tic k ie s A r r a y )
removeStickyFromDOM (key) ; ^ __
Нам также п о т р е б у е т с я у д а л и т ь <li>, с о д е р ­
} жащий к л е й к у ю з а м е т к у , из с т р а н и ц ы , чтобы
данная з а м е т к а исчезла, когда вы на ней щ е л ­
кнет е. Э т и м м ы и з а й м е м с я далее...

дальш е ► 485
удаление замет ок из dom

Удаление заметки такЖе из DOM


Ч т о б ы з а в е р ш и ть удаление, н а м н о н а д о б и т с я р е а л и зо в а ть ф у н к ц и ю remove S t ickyFromDOM. Ранее м ы
о б н о в и л и ф у н к ц и ю addstickyToDOM с ц е л ью д о б а в л е н и я к л ю ч а к л е й к о й з а м е т к и в ка ч е с т в е и д е н т и ­
ф и к а т о р а эл е м е н та < l i > , к о т о р ы й с о д е р ж и т зам етку, п р и с у т с т в у ю щ у ю в о б ъ е к т н о й м о д е л и д о ку м е н та .
П о э т о м у м ы с м о ж е м в о с п о л ь з о в а ть с я d o c u m e n t . g e t E l e m e n t B y ld для н о и с к а к л е й к о й з а м е т к и в D O M .
М ы и з в л е ч е м p a r e n tN o d e з а м е т к и и н р и м е н и м м е то д re m o v e C h ild для ее удал ения:

Передаем ключ (также яв л яю -


щийся идент иф икат ором) клей - ~ X Извлекаем элем ент <Н>
кой за м ет ки, кот орую ищ е м . ^ --- ^
из РОМ...
f u n c t i o n г emoveStickyFromDOM(key) { у
v a r s t i c k y = d o c u m e n t . g e t E l e m e n t B y l d (key) ; ...и удаляем , для чего сначала
s t i c k y .p a r e n tN o d e . r e m o v e C h ild ( s t i c k y ) ; ^ извлекаем его p arentN od e ,
} <(i> ^<ul> удалит^Ъчерний узел \ l i > а 3at/vxe,M применяем
removeChild.

-V Отличная работа! А не X
Umak, проведем т е с т .
м о гл и бы вы теперь сделать
Н а б е р и т е весь п р и в о д и в ш и й с я в ы ш е к о д , з а гр у зи т е с т р а н и так, чтобы я см огла раскрашивать
цу, доб авьте и удал ите н е с к о л ь к о к л е й к и х за м е т о к. З а в е р ш и свои заметки? Ну там, знаете, ж ел­
те р а б о ту браузера, за те м сн о в а з а п у с ти те е го и х о р о ш е н ь к о ты м цветом те, на которы х записаны
протести руйте прилож ение срочные дела, синим — на которы х
помечены идеи, розовым — заметки
I со второстепенны ми делами.
В таком духе? у
I г.
t-ihirt

Теперь мы можем
удалять заметки!

Конечно моЖно!
У ч и т ы в а я ваш о н ы т в э т о м деле, м ы с м о ж е м с п р а в и т ь с я с д а н н о й зад ачей. К а к
и м е н н о м ы э то сделаем? Ч т о ж , м ы созд адим о б ъ е к т для р а зм е щ е н и я т е к с т а за­
м е т к и и ее ц в е та , а за те м с о х р а н и м е го к а к з н а ч е н и е эл е м е н та за м е т ки , п р е д в а р и ­
т е л ь н о зад ействов а в JSON. s t r i n g i f y для п р е о б р а з о в а н и я е го в стр о ку .

486 глава 9
сохраняем данны е локально

Обновление интерфейса пользователя для выбора цвета заметок


Н а д а н н ы й м о м е н т все н а ш и з а м е т к и и м е ю т ж е л т ы й цвет. А н е будет л и л у ч ш е , е сли н а м
с т а н е т д о с т у н е н для в ы б о р а ц е л ы й д и а н а з о н ц ветов?

Sx* ЮI;If
1+ л;tijttmi
Cotof: I у»ИвшЯ

Мы м о г л и бы Pick up dry C ancel Buy a n o th e r


добавить сюда cleaning cable tv , Apple
who needs gadget
м е н ю выбора, it now? t- F
чтобы вы с м о гли Л
вы бират ь для Так луч ш е,
своей з а м е т к и не правда ли?
лю бой цвет.

С начал а н р и м е м с я за л е гк у ю ча с ть: о б н о в и м H T M L , ч т о б ы у нас н о я в и л о с ь м е н ю в ы б о р а


ц в е то в , и з к о т о р о г о п о л ь зо в а те л ь с м о ж е т в ы б р а т ь п у ж н ы й цвет. О т р е д а к т и р у й т е ф айл
n o t e t o s e l f . h tm l и о б н о в и т е с в о ю ф о р м у с ц е л ью д о б а в л е н и я ц в е то в , к а к н о к а з а н о далее:

Мы вносим изм енения О б р а т и т е вним ание на и д е н т и ф и -


< h tm l> т о л ь к о в ф о р м у , а все к а м о р <select>j он н а м п о т р е б у е т с я
ос т а ль н о е о с т а н е т с я для извлечения значения выбранного
<form> прежним. п а р а м е т р а на Java Scrip t.
M w добавили ч е т ы р е
Добавим
ме^кудля
< ia b e l fo r = " n o te c o lo r " > C o lo r : < / la b e l>
~ _
у а лЛ ъля
для зз аа М
ц ве т а оля м ^е ттОо Кк ,,g
текста < _______
s e le c t _ i d_= " n o t e c o l o r " .> uw
которых м о ж н о ду-
замет- . выбрать нужный
ки чтобы < o p t i o n v a lu e = " L ig h tG o ld e r iR o d Y e llo w n> Y e l l o w < / o p t i o n > Otm г
пользова- < o p tio n v a l u e = nP a le G r e e n n> g r e e n < / o p t i o n > Каждое значение я в л я -

для чего C o- p tio n v a lu e = " L ig- h t P i r i k " > p i n k < / o p t io n > ' е т с я и м е н е м ц в е т а , ко
ю еднаыа- , т о р о е мы мож ем в с т а -
реоназна < o p t io n v a lu e = " L ig h t B lu e n> b lu e < / o p t io n > п,,, . А п
чено данное о и т ь п р я м о в с т и л ь для
поле. < /se le c t> наш их за м е т о к .
^ ^ < l a b e l f o r = " n o t e _ t e x t n> T e x t : < / l a b e l > <i n p u t t y p e = " t e x t " i d = " n o t e _ t e x t ">
< i n p u t t y p e = " b u t t o n " id = " a d d _ b u t to n " valu e= "A d d S t i c k y N o te t o S e l f " >
< /fo r m > jk
•О с т а л ь н а я ч а ст ь ф о р м ы о с т а н е т с я прежней.

< /h t m l>

М ы и с н о л ь з о в а л и CSS для о н р е д е л е н и я ц в е та н о у м о л ч а н и ю . Т е н е р ь н е о б х о д и м о с о х р а н и т ь ц в е т вм есте


с са м о й з а м е т ко й . В о з н и к а е т в о н р о с : к а к м ы будем с о х р а н я т ь ц в е т для з а м е т к и в l o c a l S t o r a g e ?

дальш е ► 487
использование js o n для сохранения цвета

Метод JSON.stringify — не только для массивов


Для сохранения цвета заметки вместе с ее текстом у нас есть возмож ность
нрибегпуть к той ж е м етодике, которую мы иснользовали со s t i c k i e s A r r a y :
м ож но сохранить объект, содерж ащ ий текст и цвет, как значение для заметки
в lo c a lS to r a g e .

Color: [pink Text: [Cancel cable tv, who needs it now? ~] (Add sticky Note to S eif) |

t
Мы будем д р а т ь введенные п о л ь з о в а т е ­ И мы с охра ни м его
л е м значения для ц ве т а и т е к с т а з а м е т к и в localStorage с и с ­
и « у п а к о в ы в а т ь » их в п р о с т о и объект . поль зо ва ни е м клю ча
клейкой з а м е т к и . localStorage
Точно т а к же, как и
в случае со stickiesA rray,
var stick yO b j = {
н а м п р и д е т с я вы зва т ь
" v a lu e " : "C an cel c a b l e t v , who n e e d s i t now?",
JSO N .strin gify в о т н о - ‘
" c o l o r " : " L ig h tP in k "
илении значения з а м е т к и ,
};
прежде чем м ы вызовем
loc a lStorage.setltem для с о ­
хранения данного значения.
П е р е н и ш е м ф у н к ц и ю c re a te S tic k y для с о х р а н е н и я ц в е та вм е сте с т е к с т о м к л е й к о й за м е т к и .
Д л я н р е д с та в л е н и я т е к с т а и ц в е та будем и с н о л ь з о в а т ь н а ш у д о б н ы й о б ъ е кт:

f u n c t i o n c r e a t e S t i c k y () {
var s t ic k ie s A r r a y = g e t S t i c k i e s A r r a y (); Мы делаем т о , чт о
v a r c u r r e n t D a t e = new D a t e ( ) ; обычно п р и н я т о для
var colorSelectObj = document.getElementByld("note_color") извлечения значения
выбранного цвета.
var index = colorSelectObj.selectedlndex;
var color = colorSelectObj[index].value;
v a r k ey = " s t i c k y _ " + c u r r e n t D a t e . g e t T i m e ( ) ; З а т е м и с п о л ь з у е м данное
значение ц в е т а для соъда
var v a lu e = docum ent. g e t E l e m e n tB y ld (" n o t e _ t e x t " ) . v a l u e ;
ния S t i c k y O b j - объект а.
var stickyObj = { содержащего два с в о й с т в а ,
"value11: value, т ек ст зам ет ки и цвет ,
вы бранный п о л ь з о в а т е л е м .
"color": color
}; П реобразуем stickyO bj
у с пом ощ ью мет ода JSON
localStorage.set Item (key, JSON.stringify (stickyObj )) ; Stringify прежде чем
s t i c k i e s A r r a y . p u s h (key) ; м е с т и м его в localStorage.
l o c a l S t o r a g e . s e t lt e m ( " s t ic k ie s A r r a y " , J S O N .s t r i n g if y ( s t i c k ie s A r r a y ) );
addStickyToDOM (key, stickyObj); / Передаем о б ъ е кт в м е с т о т е к с т о в о й с т р о к и ф ун кц и и
addStickyToD O M . А э т о означает , ч т о ва м также п о ­
т р е б у е т с я обновит ь a d d S tic k y T o D O M , не т а к ли ?

488 глава 9
сохраняем данны е локально

использование нового объекта stickyObj


Когда мы нередаем stickyObj функции addstickyToDOM , нам необходим о обновить эту функцию, чтобы
иснользовать объект вместо строки, которую мы нередавали нреж де, а также чтобы задать цвет ф она
для заметки. Эти изм енения довольно легко внести: НуЖН0 w3MeHumt, здесь п а р а м е т р ,
чтобы и м был stic k y O b j, а не т е к ­
ст овое значение з а м е т к и .
f u n c t i o n addstickyToD O M (key, stick y O b j) {
v a r s t i c k i e s = d o c u m e n t . g e t E l e m e n t B y l d ("s t i c k i e s
И звл е ка е м ц в е т из о б ъект а
var s t i c k y = docum ent. c r e a t e E le m e n t (" l i " );
stickyObj, ко т о р ы й передаем
s t i c k y . s e t A t t r i b u t e (" id " , k e y ); addstickyToD O M .
Объекты
элементов
О б р а т и т е внимание: к о г ­
HTML обла- s t i c k y . sty le.b a ck g ro u n d C o lo r stic k y O b j.c o lo r ;
дают свой да м ы указы вае м с во й с т во ,
стволл style, ■связанное с ц в е т о м фона,
которое вы ( v a r sp an = d o c u m e n t . c r e a t e E l e m e n t ( " sp a n " ) на J a v a S c r ip t, мы оп ре д е ля е м
можете ис­ s p a n . s e t A t t r i b u t e ( " c l a s s ", " stic k y " ); его как backgroundColor, а НЕ
пользовать b a c k g ro u n d -c o lo r, как на CSS.
span.innerHTML = s t i c k y O b j . v a l u e ; £
Эля доступа
к стилю s t i c k y . a p p e n d C h ild (sp a n ); З а т е м нужно извлечь т е к с т о в о е
соответ - s t i c k i e s . a p p e n d C h ild (stick y ); значение, ко т о р о е м ы со б и р а ­
ствующего емся и с п о ль з о ва т ь для з а м е т к и ,
элемента. s t i c k y . o n clic k = d e le te S tic k y ;
из объекта.
}

Есть ещ е одно м есто, где нам н еобходи м о обновить код. И находится оно в функции
i n i t , где мы извлекаем заметки и з l o c a l S t o r a g e и нередаем их addstickyToDOM, когда
в нервый раз загружаем страницу.

f u n c t i o n i n i t () {
v a r b u t t o n = d o c u m e n t . g e t E l e m e n t B y l d ( " a d d _ b u tt o n " )
b u tto n . o n click = crea teS tick y ;
Теперь, когда мы будем и з ­
var s t ic k ie s A r a y = g e t S t i c k i e s A r r a y (); влекат ь значение за м ет к и из
localStorage, нам по т реб ует ся
преобразоват ь его с помощ ью
for (v a r i = 0; i < s t i c k i e s A r r a y . l e n g t h ; i+ +) { JSO N .parse, поскольку эт о
v a r k ey = s t i c k i e s A r r a y [ i ] ; больше не строка а объект.
var v a lu e = J S O N .p a r se (lo c a lS to r a g e [k e y ])
И м ы передадим данный о б ъ е кт
addstickyToD O M (key, v a l u e ) ; 4 ------------------
ф ункци и a d d stick y T o D O M в м е с т о
} с т р о к и (код вы глядит т а к же, одна­
ко п ередаем м ы уже ч т о - т о другое).

дальш е ► 489
т ест ирование цвет ны х замет ок

Тест-драйв цвета заметок


П реж де чем снова вынолнять нрнлож енне N ote to Self, вам нотребуется -
Вы можете восполь­
очистить l o c a l S t o r a g e , носкольку нредыдущие версии наших клейких за­
зоваться файлом
меток не имели никакого цвета, и сейчас мы иснользуем другой ф ормат
maintenance'ktml
для значений наш их заметок. Ранее мы иснользовали строки, а тенерь —
для очистки своего
объекты. П оэтом у очистите у себя l o c a l S t o r a g e , перезагрузите страницу
localStorage либо об­
и добавьте несколько заметок, выбрав нри этом разны й цвет для каждой
ратиться к консоли.
из них. Вот как выглядят наши заметки (кроме того, мы заглянем в наше
локальное хранилищ е).

Мы выдрали желтый, розовый и синий цвет для заметок.

Wrccic S:11
j j | + I* Ч-и 1-~У1гЧ-.1тг:у|па1:к1й‘ '-г,а С | '<Хг G z c j i

Г ; ГоГ. wllttft 7 »Т«М. f A s f e l кч- tun* IK W )

Pick up dry Ca ncef Buy another


cleaning cable tv, Apple
who needs gadget
it now
1

1 - ___ _ J
<s>инч-а- ^ wit Cl"j
n |*-п-*нч ’ •.r
n | ;*-«***■ Г" AI^J U.I№MI.2 11чМуг. >A'i U.1J 4dll|l||i' JW
j>
b U.tU W. .1 J'r I UMlft *>, i tJJ*Hl4Aa
■ >/ I ЫЛ& W I
I' 'llfl J*i tj; u.Sl»*«.+ u; l »V*‘ '»U'’JV,4'* i
* -j : "iintv

*■.. Vui'lm
*■ _•ЕнММ
*■^ Л1**

m *5________

Значение каждой заметки теперь является


объектом (преобразованным с помощью метода
JSON.stnngify), который содержит текстовое
значение и цвет соответствующей заметки.

490 глава 9
/ Я д ум а л ; раз м ы м ожем сохра- \
нять объекты и массивы, то почему q
. бы просто не сохранить все заметки в \
самом массиве, зачем нам нужны все эти I
остальные элементы? П о хо ж е , все только
усложняется, хотя м ы м о гл и бы просто /
у вложить и х в один элемент /
в localStorage. У

В некоторых ситуациях так поступать весьма разумно.


И с н о л ь з у я с в о и з н а н и я , м ы , н е с о м н е н н о , см о гл и б ы р а з­
р а б о та ть к л е й к и е з а м е т к и т а к и м о б р а зо м , ч т о б ы о н и п р е д ­
с та в л я л и с о б о й о б ъ е кт ы , в л о ж е н н ы е в м ассив. В д а л ьн е й ш е м
в ы м о гл и б ы и м е н н о т а к и п о с т у п и т ь . Э то т а к ж е им е л о б ы
см ы сл в случае с э л е к т р о н н о й к о р з и н о й . Е д и н с т в е н н ы й н е ­
д о с т а т о к за кл ю ч а е тс я в то м , ч т о м е то д а м JSON. s t r i n g i f y и
JS O N .p arse н р и х о д и т с я п р о д е л ы в а т ь массу д о п о л н и т е л ь н о й
р а б о т ы в с я к и й раз, к о гд а в ы в н о с и т е и з м е н е н и я : н а п р и м е р ,
ч т о б ы д о б а в и т ь зам етку, на м п р и д е т с я п р е о б р а з о в а ть с п о ­
м о щ ь ю JS O N .p arse ц е л ы й н а б о р за м е т о к, п о т о м д о б а в и т ь
зам етку, а за те м с н о в а п р е о б р а з о в а ть все з а м е т к и у ж е с п о ­
м о щ ь ю JSON. s t r i n g i f y , п р е ж д е че м за п и с ы в а т ь и х о б р а т н о
в х р а н и л и щ е . У ч и т ы в а я к о л и ч е с т в о д а н н ы х в н а ш е м случае,
э то н е д о л ж н о ста ть п р о б л е м о й (о д н а к о зад ум айтесь о м о ­
б ил ьны х устр о й ств а х с не очень м о щ н ы м и пр о це ссо р а м и и о
в л и я н и и и с п о л ь з о в а н и я р е с у р с о в н р о ц е с с о р а н а у р о в е н ь за­
ря д а а кк у м у л я т о р а ).

Т а к и м о б р а зо м , р е ш е н и е о т о м , «унаковать» вам все в о д и н


о б ъ е к т и л и ж е в м а сси в в l o c a l S t o r a g e , будет за в и с е ть о т к о ­
л и ч е с т в а э л е м е н то в д а н н ы х , к о т о р о е вам н о т р е б у е т с я с о х р а ­
н и т ь , а т а к ж е о т т о г о , н а с к о л ь к о б о л ь ш и м я в л я е тс я к а ж д ы й
и з н и х и о б р а б о т к у к а к о г о р о д а в ы с о б и р а е те с ь о с у щ е с тв л я ть
в о т н о ш е н и и э т и х эл е м е н то в .

Н е с м о т р я н а т о ч т о н а ш а р е а л и за ц и я м о ж е т б ы т ь с л е гка
гр о м о з д к о й для о г р а н и ч е н н о г о к о л и ч е с т в а за м е т о к, м ы н а ­
деем ся, ч т о о н а о т л и ч н о н о м о гл а вам н о н я т ь , ч т о т а к о е A P I-
и н т е р ф е й с l o c a l S t o r a g e и к а к о б р а щ а ть с я с и м е ю щ и м и с я
в н е м э л е м е н та м и .
Ш ПЫТАЙТЕСЬ СДЕЛАТЬ ЭТО ДОМА
(И ЛИ КАК РАЗИКСТИ В ПУХ II ПРАХ ВАШ И 5 МБАЙТ)
Как мы уж е говорил и, в сумме у вас будет 5 М байт хранилищ а для браузера ка ж д ого из пользователей.
Несмотря на то что такой объем может показаться больш им, все ваши данные сохраняю тся в виде стро к,
а не в байтовом формате. Возьмите, к прим еру, размер госуд арственного долга: если вы разить его в виде
значения с плавающей то чко й , то для его размещ ения в хранилищ е потребуется не м н ого места, од н ако
если вы разить его в виде стр о ко в о го значения, то для его сохранения потребуется гораздо больш ий объ ­
ем. Таким образом , хранилищ е разм ером 5 М байт спо соб н о вместить не так м ного, ка к могло показаться.

Так что же произойдет, когда вы исчерпаете 5 Мбайт? К сож алению , это од но из поведений, которы е не
определяю тся специф икацией HTML5, и браузеры м о гут поступать по-разном у, когда вы превы сите свой
лимит. Браузер может спр оси ть у вас, хотите ли вы увеличь объем хранилищ а, либо сген ер и рует и скл ю че­
ние QUOTA_EXCEEDED_ERR, которое м ож но перехватить следую щ им образом :

Вызов s e t l t e m в с е р е д и ­
не блока t r y ; если ч т о -
нибудь п о й д е т не т а к
' try { f и s e t l t e m с ге н е р и р у е т
l o c a l S t o r a g e . s e t l t e m (шуКеу, myValue)
и ск л ю ч е н и е , т о будет
t ru/catck пере _ c a t c h (е) {
задейст вован блок catch.
i f (e == QUOTA_EXCEEDED_ERR) {
и с к д к н е н и я , ге н е р и ­ a lert(" O u t o f sto ra g e !" )
руемое 6 блоке try- }
П р о ве р я е м , ошибка ли э т о квот ы х р а н и л и щ а (а не
к а к о й - т о другой т и п и склю ч ен ия ). Если т а к оно
Э т о о бласт ь J a v a S c rip t,
и е с т ь j м ы выведем для п о л ь з о в а т е л я диа л о го ­
к о т о р у ю мы не з а т р а ­
вое окно ale rt с с о о т в е т с т в у ю щ и м сообщением.
ги в а л и , и вы м ож ет е
Вы, скорее всего, з а х о т и т е с д е ла т ь ч т о - т о более
з а х о т е т ь исследоват ь
зн а ч и т е л ь н о е , чем п р о с т о вывод окна alert.
э т о т вопрос подробнее.

Не все браузеры настоящий м о ­


м е н т г е н е р и р у ю т исклю чение QUOTA_
EXCEEDED_ERR. Однако они все же
с г е н е р и р у ю т исклю чен ие, когда вы
п р е вы с и т е свой л и м и т , п о э т о м у н е ­
л и ш н и м б удет р азоб ра т ь с я с общ им
с лу ч а е м исклю чения п ри сохранении
т ого или иного э л е м е н т а в х р а н и л и щ е

492 глава 9
сохраняем данные локально

Давайте попробуем довести свой браузер до предела, посмотреть, из чего он


сделан и как далеко может пойти, узнать, ка к он себя поведет в стрессовой си ­
туации. Напишем н ем ного кода, которы й заставит ваш браузер выйти за лимит
объема его хранилищ а:

ОПАСНО
Взрывное
<html>
задание
<head> Начнем с односимвольной
с т р о к и с к л ю ч о м "fuse".
< scrip t>

И п р о с т о будем , не ост а н а вл и -
lo c a lS to r a g e . se tlte m ( "fuse", ; ваясь, у в е л и ч и в а т ь ее размер...
w h ile(tr u e ) { ..п у т е м удваивания э т о й
v a r f u s e = l o c a l S t o r a g e . g e t l t e m ("f u s e с т р о к и (п о с р е д с т в о м к о н к а ­
try { т ена ции ее с сам ой собой).

l o c a l S t o r a g e . s e t l t e m ( " fu se " , f u s e + f u s e ) ; ^ З а т е м попытаемся записат ь


} catch (e) { ее обратно в localStorage.
a l e r t ( " Y o u r b r o w s e r b l e w up a t" + f u s e . l e n g t h + " w i t h e x c e p t i o n : " + e);
break;
Если браузер аварийно
} заверш ит работ у —
He будем о с т а в ­ дело сделано! В ы в е ­
л я т ь беспорядок дем для п о л ь з о в а т е л я
l o c a l S t o r a g e . r e m o v e I t e m ( "f u s e ” и у д а л и м да н ­ диалоговое окно ale rt
< /sc rip t> ный э л е м е н т с соот вет ст вую щ им
< /h e a d > из localStorage. С' •
сообщ ением и выйдем
из данного цикла.
<body>
< /b o d y >
Ес-ли у вас х в а т
< /h t m l> ит духу во
зобат ься ОЛЬ- ь
э ^ и м кодом, Вы и спол ь зу­
здесь свои ^ о опи -
буд ьте ете этот код
Р езу л ь т а т ы .
Наберите этот код, «зажгите фитиль», загрузи в его, на свой страх
о С Г О о |> о Ж Н ь х
и поразвлекайтесь! Испытайте его в разны х браузерах. и риск!
Данный код способен вызвать серьез­
ный сбой браузера, из-за чего операци­
онная система «очень расстроится»,
что может привести к потере резуль­
татов вашей работы. Используйте
его на свой страх и риск!

дальш е ► 493
инф орм ация о sessionstorage

Я провожу бета-тестирование своей


электронной корзины. П ользователи
не хотят, чтобы содержимое и х корзины
оставалось в браузере. Как м ож но удалить
все элементы электронной корзины , когда
пользователь закрывает браузер? Я вы­
брал не ту те хн о л о ги ю ?

Нет, Люк, есть еще один Скайуокер.


О ка з ы в а е тс я , у l o c a l S t o r a g e и м е е тс я «сестра»
п о и м е н и s e s s i o n S t o r a g e . Е сли в ы п о д с та в и те
гл о б а л ьн ую п е р е м е н н у ю s e s s i o n s t o r a g e везде,
где и с п о л ь зо в а л и l o c a l S t o r a g e , то ва ш и эле­
м е н т ы будут с о х р а н я т ь с я т о л ь к о в т е ч е н и е сеан­
са браузера. Т а к и м о б р а зо м , к а к т о л ь к о д а н н ы й
сеанс з а к о н ч и т с я (д р у ги м и сл о в а м и , п о л ь зо в а ­
тел ь з а к р о е т о к н о б р а узе р а ), с о х р а н е н н ы е эле­
м е н т ы будут удалены .

О б ъ е к т s e s s i o n s t o r a g e п о д д е р ж и в а е т т о ч н о та ­
к о й ж е A P I-и н т е р ф е й с , ч т о и l o c a l S t o r a g e , но-
э то м у вам у ж е и з в е с т н о о н е м все н е о б х о д и м о е .

В о с п о л ь зу й те с ь и м !

494 глава 9
сохраняем данны е локально

На данный момент вы полностью изучили API-интерфейс l o c a l S t o r a g e . Чуть ниже приведены


главные действующие лица данного API-интерфейса, скрытые под масками. Посмотрите, сможете
ли вы разобраться, кто из них для чего используется. В качестве примера мы соотнесли одно из
описаний с нужной позицией.

dear И с п о л ь з у й т е м е п я для с о х р а п е п и я э л е м е п то в п а д л и т е л ь п ы й с р о к .

Я п р и п и м а ю к л ю ч и и з п а ч е п и я , к о т о р ы е за те м з а п и с ы в а ю
feffionStorage в l o c a l S t o r a g e . И м е й т е в виду, ч т о е сли в l o c a l S t o r a g e у ж е и м е ­
е тся т а к о й к л ю ч , я п е буду п р е д у п р е ж д а ть вас об э то м , а п р о с т о
п е р е з а п и ш у е го , п о э т о м у вам следует п о п и м а т ь , о ч е м в ы п р о с и т е .

key Е сл и в ы с та п е те з л о у п о т р е б л я т ь г о с т е п р и и м с т в о м в l o c a l S t o r a g e
и и с п о л ь зо в а ть с л и ш к о м м п о го п р о с т р а н с т в а , то будет с ге п е р и р о -
в а п о и с к л ю ч е н и е и в ы п о л у ч и т е о т м е п я и з в е с ти е .

setltem
Н у ж п о уд а л ить элем епт? Я а к к у р а т п о в ы п о л п ю э ту работу.

removeltem П р о с т о д а й те м п е к л ю ч , и я о т ы щ у эл е м е п т с д а п п ы м к л ю ч о м и п е ­
редам вам е го зп а ч е п и е .

Я — р а з п о в и д п о с т ь х р а п и л и щ а п а к о р о т к и й с р о к : буду с о х р а п я т ь
length в а ш и д а п п ы е , п о к а о т к р ы т о о к п о браузера. З а к р о й т е о к п о браузе­
р а и — бац! — все в а ш и д а п п ы е и с ч е зл и .

К о гд а все э л е м е п ты в l o c a l S t o r a g e б о льш е вам п е н у ж п ы , я па-


getltem в о ж у п о р я д о к и в ы б р а с ы в а ю и х , о ста в л яя вам ч и с т о е и н у с т о е л о ­
ка л ь н о е х р а п и л и щ е (и м е й т е в виду, ч т о я м о гу п а в о д и т ь п о р я д о к
т о л ь к о в св о е м с о б с т в е п п о м и с т о ч п и к е ).

localStorage Н у ж п о у зп а ть к о л и ч е с т в о эл е м е п то в в ваш ем l o c a l S t o r a g e ? Я п о ­
м о гу вам с э ти м .

QUOTAJXCEEDEDJRR Д а й т е м п е и п д е к с , и я п р е д о с та в л ю вам к л ю ч о т п е го в l o c a l S t o r a g e .

дальш е ► 495
вариант ы использования web storage

Теперь, когда Вы изучили localStorage,


как Вы собираетесь использоВать его?
С ущ еств уе т масса с п о с о б о в и с п о л ь з о в а н и я l o c a l S t o r a g e . В п р и л о ж е п и и N o te to S e lf для р а б о ­
т ы с э л е к т р о п п ы м и за м е т ка м и м ы и с п о л ь з о в а л и е го т а к и м о б р а зо м , ч т о п а м п е п о тр е б о в а л с я
се р в е р , п о даж е п р и п а л и ч и и се р в е р а l o c a l S t o r a g e м о ж е т п р и п е с т и д о в о л ь п о м п о го п о л ь з ы .
Н и ж е пр иве д е п ряд д р у ги х вариа пто в, к о т о р ы м и пользую тся р а зр а б о тч и ки :

В своем новом Твиттер-клиенте я буду


кэшировать с помощ ью localStorage поисковы е
результаты Твиттера для повышения производитель-
0 /* ности. Когда м ои пользователи будут выполнять
поиск, я сначала проверю локальны е результаты.
Все это по-настоящ ему поможет м оим м обильны м
пользователям.

Я буду сохранять п л е йл исты с мета­


данны ми для своих пользователей. Они
см огут сохранить свои л ю б и м ы е кл и п ы
вместе с временным кодом, указы ваю ­
щим, где они прервали просмотр.

Я испо льзую sessionStorage


для своей новой электронной корзи­
ны в ком мерческой интернет-библио­
теке. Если пользователь закрывает
окно браузера, необходим о, чтобы со ­
держимое его корзины удалялось.

496 глава 9
сохраняем данны е локально

У меня есть
действительно класс­
ная игра, которая работает
в двух разных окнах браузера, и я
использую localStorage для син­
хронизации состояния.

Я сохраняю множество л о ­
кальных данны х, чтобы сделать
приложения м о и х клиентов бы стры ­
ми на м обильны х устройствах. Н аличие
больш ого хранилищ а на клиентской
стороне дает огр о м н ы й выигрыш.

Я испо льзую новый способ сохранения состо­


яния пользователей. Зачастую мне требовалось
своего рода сеансовое хранилищ е на стороне
сервера. Теперь я м о гу просто сохранять состоя­
ние м о и х пользователей локально и задейство­
вать код на стороне сервера, только когда мне
приходится это делать.

дальш е ► 497
обзор web storage

КЛЮЧЕВЫЕ
-------------------------- МОМЕНТЫ
■ Web Storage — это хранилище в вашем браузере и API- пункт Delete (Удалить) (данный подход работает не во
интерфейс, который вы можете использовать для всех браузерах).
сохранения и извлечения элементов из хранилища. ■ Вы можете удалять элементы из l o c a l S t o r a g e
■ Большинство браузеров обеспечивают по крайней мере в коде, используя методы r e m o v e l t e m ( к л ю ч - ) и
по 5 Мбайт хранилища на каждый источник. c l e a r . Следует отметить, что метод c l e a r удаляет

■ Web Storage состоит из l o c a l S t o r a g e и все элементы в l o c a l S t o r a g e в том источнике, где


s e s s io n s to ra g e . вы проводите очистку.
■ Локальное хранилище сохраняет данные на постоянной ■ Ключи для всех элементов l o c a l S t o r a g e должны
основе, даже если вы закроете окно браузера или во­ быть уникальными. Если вы примените тот же ключ,
обще завершите его работу. который уже имеется у существующего элемента, то
■ Элементы в s e s s i o n S t o r a g e будут удалены, если перезапишете значение данного элемента.
вы закроете окно браузера или завершите его работу. ■ Сгенерировать уникальный ключ можно с использова­
s e s s i o n S t o r a g e хорошо подходит для временных нием значения текущего времени в миллисекундах, про­
элементов, но не годится как хранилище для данных шедших с 1970 года, прибегнув к методу g e t T i m e ( )
на более длительный срок. объекта D a t e .
■ И lo c a lS to ra g e , и s e s s io n S to ra g e исполь- ■ Важно разработать схему присваивания имен для своих
зуют один и тот же API-интерфейс. приложений, которая по-прежнему сможет работать,
■ Web Storage предусматривает организацию по источни­ если элементы будут удалены из хранилища либо
ку (считайте — домену). Источник — это местоположе­ если другое приложение поместит элементы в данное
ние документа в Интернете (например, wickedlysmart. хранилище.
com или headfirstlabs.com).
■ Web Storage в текущий момент поддерживает сохране­
■ Каждый домен располагает отдельным хранилищем, ние строк как значений для ключей.
в силу чего элементы, сохраненные в одном источнике,
■ Вы можете преобразовывать числовые значения, со­
не будут видны веб-страницам в другом источнике.
храненные в l o c a l S t o r a g e как строки, в числовые
■ Используйте l o c a l S t o r a g e . s e t l t e m (ключ-) значения, используя p a r s e l n t или p a r s e F l o a t .
для добавления значения в хранилище.
■ Если вам потребуется сохранить комплексные данные,
■ Используйте l o c a l S t o r a g e . g e t l t e m ( ключ) можете воспользоваться JavaScript-объектами и пре­
для извлечения значения из хранилища.
образовать их в строки перед сохранением, прибегнув
■ Вы можете использовать тот же синтаксис, который при­ к j s o n . s t r i n g i f y , а после извлечения преобра­
меняется в случае с ассоциативными массивами, для со­ зовать их снова в объекты с помощью J S O N . p a r s e .
хранения элементов в хранилище и извлечения их отту­
■ Локальное хранилище может оказаться особенно по­
да. Используйте для этого l o c a l S t o r a g e [ клю ч] .
лезным на мобильных устройствах для снижения тре­
■ Используйте метод l o c a lS t o r a g e . k ey () для бований к пропускной способности канала.
перечисления ключей в l o c a lS to ra g e .
■ Сеансовое хранилище подобно локальному хранилищу
■ l o c a l S t o r a g e . le n g th — это количество эле­ за исключением того, что элементы, которые в него
ментов в l o c a lS to ra g e в определенном источнике. помещены, не сохраняются там на постоянной основе
■ Используйте консоль в своем браузере для просмотра и удаляются, если вы закрываете вкладку, окно или
и удаления элементов в l o c a l S t o r a g e . выходите из браузера. Сеансовое хранилище подходит
■ Вы мож ете у д а л я ть элем енты напрям ую из для сохранения элементов на короткий срок, например
l o c a l S t o r a g e , щелкнув правой кнопкой мыши на во время сеанса, связанного с посещением интернет-
том или ином элементе и выбрав в появившемся меню магазина и использованием электронной корзины.

498 глава 9
сохраняем данны е локально

U I M L 5 - K f ° CCB ° r A
Ц ^ Ф V tTA Trи
TTте
T»^ п
ТТ^Т^/ЛТ’
Уд ел е к о т оПГЧ/ЛА
р о е кТ/П
о лТТиТТчТТА
е с/'Т
т’
вЮ/Л
о врем епи тестир о ва ­
н и ю с в о е го с о б с т в е п п о го л о к а л ь п о го х р а п и л и щ а .

а
г г п ■ ■
м ■ ■ ■ ■ ■

По горизонтали По вертикали
4.Имя сестры Люка Скайуокера. 1. Мы создаем___________ для размещения текста заметки и ее
5.Когда мы использовали значение____________ l o c a l S t o r a g e цвета в одном элементе l o c a l S t o r a g e .
для генерирования имен ключей, то столкнулись с проблемой — 2. У файлов c o o k i e имеется проблема с _____________ .
в последовательности имен наших клейких заметок оказались 3. Мы использовали_____________ для размещения ключей
бреши. всех наших клейких заметок, благодаря чему отыскать их
7. l o c a l S t o r a g e позволяет сохранять только____________. в l o c a l S t o r a g e не составит труда.
9. Мы можем выяснить, на какой заметке щелкнул пользователь, 6. Сеансовое хранилище подобно локальному хранилищу за ис­
обратившись к e v e n t . _____________. ключением того, что элементы, которые в него помещены, не
10. Нам необходимо преобразовать объект с помощью метода сохраняются там н а _____________ основе и удаляются, если
_____________ , прежде чем сохранять его в l o c a l S t o r a g e . вы закрываете окно браузера.
11. Большинство браузеров предлагает_____________ мегабайт 8. Используйте____________для преобразования строки в цело­
хранилища на каждый источник. численное значение.
12. Данный метод используется для сохранения элементов в 13. Если вы сохраните что-то в своем браузере и полетите на
lo c a lS to r a g e. , то оно по-прежнему будет там, когда вы вер­
14. Мы полагали, что можно лишь мечтать о возможности сохра­ нетесь.
нить ______________ в l o c a l S t o r a g e , но, как оказалось,
она существует, и дает ее JSON.
15. Используйте t r y / ________ для выявления ошибок, возника­
ющих из-за превышения квоты хранилища, в l o c a l S t o r a g e .

дальш е ► 499
реш ение упражнения

Ц гР а В ско р л упки, ^е ^е н и е ________________________________________ £

Готовы испытать удачу (или, скорее, сноровку)? Данная игра позволит проверить, насколько хорошо вы
знаете l o c a l S t o r a g e , однако вам потребуется проявить решительность. Используйте свои знания об
извлечении и сохранении пар «КЛЮЧ — значение» В l o c a l S t o r a g e , чтобы уследить за горошиной, когда
она будет перемещаться от одной скорлупки к другой. Вот наше решение этого задания.

f u n c t i o n s h e ll G a m e ( ) {
l o c a l S t o r a g e . s e t l t e m ( " s h e l l l " , "p ea" );
l o c a l S t o r a g e . s e t l t e m ( " s h e l l 2 ", " e m p t y " ) ;
l o c a l S t o r a g e . s e t l t e m ( " s h e l l 3 " , "em pty"); Под какой с к ор луп к о й н а х о ­
l o c a l S t o r a g e [ " s h e l l l " ] = "empty"; дит ся горош ина ("реа")?
l o c a l S t o r a g e [ " s h e l l 2 "] = "pea";
l o c a l S t o r a g e [ " s h e l l 3 " ] = "empty";
v a r v a l u e = l o c a l S t o r a g e . g e t l t e m ( " s h e l l 2 " ); К люй З н а ч ен и е
lo c a lS to r a g e . s e tlt e m ( " s h e lll" , v a lu e );
v a lu e = l o c a l S t o r a g e . g e t l t e m ( " s h e l l 3 " ); sb e //X e m p ty
l o c a l S t o r a g e [ " s h e l l 2 "] = v a l u e ;
s h d lZ реа
v a r k ey = " s h e l l 2 " ;
l o c a l S t o r a g e [ k e y ] = "pea"; $1ле11з e m p ty
k ey = " s h e l l l " ;
l o c a l S t o r a g e [ k e y ] = "empty";
k ey = "s h e l l 3 "; Горошина ("реа") находится
l o c a l S t o r a g e [ k e y ] = "empty"; под скорлупкой Z ("skellZ")..

for (v a r i = 0; i < l o c a l S t o r a g e . l e n g t h ; i+ + ) {
v a r k ey = l o c a l S t o r a g e . k e y (i ) ;
var v a lu e = lo c a l S t o r a g e . g etltem (k e y ) ;
a l e r t ( k e y + ": " + v a l u e ) ;
}

пражнение Ваша задача заключалась в том, чтобы обновить весь код таким образом,
решение чтобы везде, где мы стали бы вызывать addStickyToDOM, мы передавали
ключ, а также значение.

Вам следовало обновить все вызовы addStickyToDom в i n i t


и c r e a t e S t i c k y , чтобы они выглядели следующим образом:
addStickyToDOM(key, v a l u e ) ;

500 глава 9
сохраняем данные локально

Зозьми в руку карандаш_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


Решение
Отметьте флажками, какие проблемы может вызывать наша текущая реализация:

Отображение клейких заметок будет происходить неэффективно, если в l o c a l S t o r a g e


присутствует большое количество элементов, которые не являются заметками.

Клейкая заметка может быть перезаписана методом s e t l t e m , если объем l o c a l S t o r a g e


0 х уменьшится, несмотря на то что другое приложение удалит все свои элементы.

Сложно быстро сказать, сколько имеется клейких заметок; вам придется осуществлять
итерацию по каждому элементу в l o c a l S t o r a g e , чтобы извлечь все заметки.

□ Используйте файлы cookie, поскольку такой подход должен оказаться проще!

пражненне Нам по-преж нем у нуж но вы яснить, как ф акти чески осущ ествл яется
решение со хр ан ени е м ассива в lo c alS to ra g e
Вы уже могли догадаться, что у нас есть возможность использовать JSON для создания строкового
представления массива. И если так и было, то вы правы. Располагая таким представлением, вы сможете
сохранить его в l o c a l S t o r a g e .

Как вы помните, в API-интерфейсе JSON имеются только два метода: s t r i n g i f у и p a r se . Задействуем


данные методы и завершим функцию i n i t :

Извлекаем массив из localStoraae. Если в localStorage не окажемся массива, то мы создадим


\ пустой
пусто массив I*и присвоим его переменной stickiesArray.
сд телики
] 8 данный момент переменная stickiesArray будет строкой
f u n c t i o n i n i t () {
' I Если
ЕГ/> л и нам
и л а лпридется
i/o#i А о мл />сг создать
/'л з И л м
// з д е с ь б у д е т код, касающийся b u t t o n . .*
массив, то мы воспользуемся
var s t ic k ie s A r r a y = lo c a lS to r a g e [" s tic k ie sA r r a y " ] ; JSON.stringifу для генерupова-
if (! s t i c k i e s A r r a ) I / ния строкового представле-
y / ния массива, а затем сохра-
s tic k ie s A r r a y = []; у ним его...
l o c a l S t o r a g e . s e t l t e m ( " s t i c k i e s A r r a y " , JSON. s tr in g ify (stick iesA r ra y ) ) ;
} else { _ Если массив stickiesArray уже бу-
stick ie sA rr a y = J S O N .p a rse ( s t i c k i e s A r r a y ) ; дет сохранен в localStorage (в виде
строки), нам потребуется преоб­
} разовать егоj используя метод parse
for (var i = 0; i < s t ic k ie s A r r a y . len g th ; i+ + ) { ^\ A P I -интерфейса JSON. После этого
в нашем распоряжении окажется
v a r k ey = s t i c k i e s A r r a y [ i ] ; массив ключей, присвоенный пере-
v a r v a l u e = l o c a l S t o r a g e [key] ; I менной stickiesArray.
addStickyToDOM ( v a lu e ) ; Чтобы вам все было ясно: мы берем строку, на которук, указывает
} stickiesArray, преобразовываем ее в массив с помощью метода parse
а затем снова присваиваем этот массив переменной stickiesArray. '

дальш е ► 501
реш ение упражнения

Ш ПЫТАЙТЕСЬ СДЕЛАТЬ ЭТО ДОМА


(И ЛИ КАК РАЗНЕСТИ В ПУХ II 1IPAX ВАШ И 5 МБАЙТ)

Как мы уже говорили, в сумме у вас будет 5 Мбайт хранилища для браузера каждого из пользователей.
Несмотря на то что такой объем может показаться большим, все ваши данные сохраняются в виде строк,
а не в байтовом формате. Возьмите, к примеру, размер государственного долга: если выразить его в виде
значения с плавающей точкой, то для его размещения в хранилище потребуется не много места, однако
если выразить его в виде строкового значения, то для его сохранения потребуется гораздо больший объ­
ем. Таким образом, хранилище размером 5 Мбайт способно вместить не так много, как могло показаться.
Так что же произойдет, когда вы исчерпаете 5 Мбайт? К сожалению, это одно из поведений, которые не
определяются спецификацией HTML5, и браузеры могут поступать по-разному, когда вы превысите свой
лимит. Браузер может спросить у вас, хотите ли вы увеличь объем хранилища, либо сгенерирует исключе­
ние QUOTA_EXCEEDED_ERR, которое можно перехватить следующим образом:

В о т вызов s e t l t e m в с е ­
редине блока t r y ; если
ч т о -н и б у д ь п о й д е т не
try { т ак и setltem сгенери­
l o c a l S t o r a g e . s e t lt e m ( m y K e y , m y V a lu e ) ; р у е т исключение, т о
W c a t c k пере-
catch(e) { будет задейст вован
x6aw t>i6aew АУС блок catch.
и-
и скл ю ч е н и я , г Р if (e == QUOTA_EXCEEDED_ERR) {
руелльл 6 блоке 9 a lert(" O u t o f sto ra g e
Г )У
}
П р о ве р я е м , ошибка ли э т о квот ы х р а н и л и щ а (а не
J к а к о й - т о другой т и п исключения). Если т а к оно и
е с т ь , м ы выведем для п о л ь з о в а т е л я диалоговое окно
a le rt с с о о т в е т с т в у ю щ и м сообщением. В ы , скорее
всего; з а х о т и т е сд е ла т ь ч т о - т о более з н а ч и т е л ь ­
ное, чем п р о с т о вывод окна alert.

Не все браузеры в н а ст о я щ и й м о ­
м е н т г е н е р и р у ю т исклю чение QUOTA_
EXCEEPEP_ERR. Однако они все же
с г е н е р и р у ю т и с к л ю ч ен и е , когда вы
п р е в ы с и т е свой л и м и т , п о э т о м у н е ­
л и ш н и м будет р азоб р ат ь ся с общ им
с лу ч а е м исклю чения при сохранении
т о го или иного э л е м е н т а в храни лищ е.

502 глава 9
сохраняем данны е локально

Давайте попробуем довести свой браузер до предела, посмотреть, из чего он


сделан и как далеко может пойти, узнать, как он себя поведет в стрессовой си­
туации. Напишем немного кода, который заставит ваш браузер выйти за лимит
объема его хранилища:

<html>
<head>
Начнем с односимвольной
< scr ip t>
строки с клю чом "fuse".
И просто будем, не останавливаясь,
l o c a l S t o r a g e . s e t l t e m ( " f u s e ", ;
увеличивать ее размер...
w h ile(tr u e ) {
...путем удваивания этой с т р о ­
v a r f u s e = l o c a l S t o r a g e . g e t l t e m ("f u s e " )
ки (посредством конкатенации
try { ее с самой собой)..
lo c a lS to r a g e . se tlte m (" fu se " , fuse + fu se ); З а т е м попытаемся записат ь
} catch(e) { ее обратно в localStorage.
a l e r t ( " Y o u r b r o w s e r b l e w up a t" + f u s e . l e n g t h + " w i t h e x c e p t i o n : " + e);
break;
}
- Если браузер аварийно з а ­
Не будем ост авлять верш ит работ у — дело
} сделано! Выведем для
беспорядок и уда ­
l o c a l S t o r a g e .r e m o v e l t e m ( " fu s e " ); л и м данный элем ент пользователя диалоговое
< /sc rip t> из localStorage. окно alert с с о о т в е т с т в у ­
ю щ им сообщением и вы й­
< /h e a d >
дем из данного цикла.
<body>
< /b o d y >
< /h t m l> Результат ы, получившиеся
у нас при использовании брау­
Наберите этот код, «зажгите фитиль», загрузив его, зеров Safari и Chrome.
и поразвлекайтесь! Испытайте его в разных браузерах.

h ttp './/lo c a lh o s t The page at focathost says:


Y o u r brow ser blew up a t 2 0 9 7 1 5 2 w ith excep tio n : Your browser blew up at 2 0 9 7 1 5 2 with exception:
Error: QUOTA_EXCEEDED_ERR: D O M Exception 2 2 Error: QUОТA_EXCEEDED_ERR: DOM Exception 22

( ok ) ( o* )

дальш е ► 503
решение упражнения

-------------------------------------------------------------------------------------------------- + К Т 9 И

РЕШЕНИЕ
На данный момент вы полностью изучили API-интерфейс l o c a l S t o r a g e . Чуть ниже приведены глав­
ные действующие лица данного API-интерфейса, скрытые под масками. Посмотрите, сможете ли вы
разобраться, кто из них для чего используется. В качестве примера мы соотнесли одно из описаний
с нужной позицией.

И с п о л ь з у й т е м е п я для с о х р а п е п и я э л е м е п то в п а д л и т е л ь п ы й с р о к .

Я п р и п и м а ю к л ю ч и и з п а ч е п и я , к о т о р ы е за те м з а п и с ы в а ю
ieiiion$tora?e в l o c a l S t o r a g e . И м е й т е в виду, ч т о е сли в l o c a l S t o r a g e у ж е и м е ­
ется т а к о й к л ю ч , я п е буду п р е д у п р е ж д а ть вас об э то м , а п р о с т о
п е р е з а п и ш у е го , п о э т о м у вам следует п о п и м а т ь , о ч е м в ы п р о с и т е .

Е сли в ы с та п е те з л о у п о т р е б л я т ь г о с т е п р и и м с т в о м в l o c a l S t o r a g e
и и с п о л ь з о в а т ь с л и ш к о м м п о го п р о с т р а н с т в а , т о будет с ге п е р и р о -
в а п о и с к л ю ч е н и е и в ы п о л у ч и т е о т м е п я и з в е с ти е .

Н у ж п о уд а л ить элем епт? Я а к к у р а т п о в ы п о л п ю э ту работу.

removeltem П р о с т о д а й те м п е к л ю ч , и я о т ы щ у э л е м е п т с д а п п ы м к л ю ч о м и п е ­
редам вам е го з п а ч е п и е .

Я — р а з п о в и д п о с т ь х р а п и л и щ а п а к о р о т к и й с р о к : буду с о х р а п я т ь
в а ш и д а п п ы е , п о к а о т к р ы т о о к п о браузера. З а к р о й т е о к п о браузе­
р а и — бац! — все в а ш и д а п п ы е и с ч е зл и .

К о гд а все э л е м е п ты в l o c a l S t o r a g e бо льш е вам п е н у ж п ы , я па-


getltem в о ж у п о р я д о к и в ы б р а с ы в а ю и х , о с та в л я я вам ч и с т о е и н у с т о е л о ­
ка л ь н о е х р а п и л и щ е (и м е й т е в виду, ч т о я м о гу п а в о д и т ь п о р я д о к
т о л ь к о в св о е м с о б с т в е п п о м и с т о ч п и к е ).

localStorage Н у ж п о у зп а ть к о л и ч е с т в о эл е м е п то в в ваш ем l o c a l S t o r a g e ? Я п о ­
м о гу вам с э ти м .

QUOTA EXCEEDED ERR Д а й т е м п е и п д е к с , и я п р е д о с та в л ю вам к л ю ч о т п е го в l o c a l S t o r a g e .

504 глава 9
сохраняем данные локально

\Ш Ш /£ 1 П Ш - 1Т восВТ А - Г « т ен и е

дальш е ► 505
10 гриМеняеМ JavaScript на ДеЛе #

API-интерфейс Web Workers +


Да, я не см о гу
справиться здесь со ВСЕМ
мне потребуется неболь­
Я м о гу помочь тебе
шая помощь.
разобраться с этой
шахтой лифта.

Медленный сценарий — хотите продолжить его выполнение? Если вам доводилось


тесно работать с JavaScript или путешествовать по Интернету, то вы, вероятно, сталкивались
с диалоговым окном Slow Script (Медленный сценарий). Но как же сейчас, когда в компьютерах
устанавливаются многоядерные процессоры, сценарии могут выполняться слишком медленно?
Все потому, что JavaScript поддерживает выполнение только одного действия за раз. Однако
с появлением HTML5 и Web Workers все изменилось. Теперь у вас есть возможность создавать
собственные множественные JavaScript-объекты w o rk e r для одновременного выполнения
нескольких действий. Независимо оттого, пытаетесь вы создать более отзывчивое приложение
либо просто хотите по максимуму использовать возможности центрального процессора —
API-интерфейс Web Workers придется кстати. Итак, надевайте шляпу директора предприятия
под названием JavaScript и заставьте своих подчиненных w o rk e r попотеть!
ja v a s c rip t-пот оки

Устрашающее диалоговое окно Slow Script (Медленный сценарий)


О д п о й и з п р и м е ч а т е л ь п ы х о с о б е п п о с т е й J a v a S c rip t я в л я ­

е тся т о , ч т о о п п о д д е р ж и в а е т в ы п о л п е п и е т о л ь к о о д п о го
д е й с т в и я за р аз — м ы о б ы ч п о п а зы в а е м э то о д п о п о т о ч -
п о с т ь ю . П о ч е м у д а п п а я о с о б е п п о с т ь п р и м е ч а те л ь п а ?
А п о то м у, ч т о о п а делает п р о ц е с с п р о гр а м м и р о в а н и я
п р о с т ы м . К о гд а у вас и м е е т с я м п о ж е с т в о п о т о к о в , п р о ­
т е к а ю щ и х о д п о в р е м е п п о , п а п и с а п и е к о р р е к т п о р а б о та ­
ю щ е й п р о гр а м м ы м о ж е т п р е в р а т и т ь с я в с л о ж н у ю задачу.

Н е д о с т а т о к о д п о п о т о ч п о с т и з а кл ю ч а е тс я в т о м , ч т о е сли в зв а л и ть н а Ja va S crip t-n p o rp a M M y с л и ш к о м


м п о г о р а б о т ы , о п а м о ж е т п е ус п е в а ть с п е й с п р а в л я ть с я , и в и т о г е п а э к р а п е м ы у в и д и м о к п а Slow S c rip t
(М е д л е п п ы й с ц е п а р и й ). Д р у го е п о с л е д с т в и е о д п о п о т о ч п о с т и с о с т о и т в т о м , ч т о е сли у вас и м е е т с я
J a v a S c rip t-код , к о т о р о м у п р и х о д и т с я и п т е п с и в п о р а б о та ть , т о будет о ста в а ть с я п е о ч е п ь м п о го в ы ч и с ­
л и т е л ь н ы х р е с ур с о в для и н т е р ф е й с а п о л ь з о в а те л я и л и в з а и м о д е й с т в и й п о л ь з о в а те л е й , и ваш е п р и л о ­
ж е н и е м о ж е т п о ка з а т ь с я м е д л е п п о р а б о т а ю щ и м и л и п е о т з ы в ч и в ы м .

Как JavaScript проводит сбое Время


Д а в а й те п о с м о т р и м , ч т о э то все о зп а ча е т, в згл я н у в , к а к J a v a S c rip t
о б р а б а т ы в а е т за д а чи , ка с а ю щ и е с я т и п и ч п о й в е б -с тр а п и ц ы :

JavaScript-nom ok
Я здесь только один,
но взгляните, сколько
всего я делаю , обрабатывая

Г В ы пол нение ф ункц ии in it


11
Обработка события clic k
ИТ
по одной задаче за раз.

В о т ч т о мы и м е е м
в виду под о д н о п о т о ч -
сI Значение времени
таймера исте кло j
носты-о. J a v a S c r ip t
пошагово вы п о л н яе т
всеj ч т о е м у нужно
С Обработка собы тия subm it '

с д е л а т ь , одно за д р у ­ ^ Обработка массива данны х \


гим. Никакого п а р а л ­
Обработка с л е д ую щ е го |
лельного выполнения ^ | собы тия c lic k В случае с неско льки м и веЬ-
здесь нет.
О бновление объектной
прилож ениям и т а ко й подход

С
\ м одел и документа (D O M ) д е й с т в и т е л ь н о э ф ф е к т и ве н .
Все вы п о л н я е т с я , и и н т е р ­
Выборка данны х ф ормы ф ейс п о л ь з о в а т е л я вы гляди т
быстро ф у н к ц и о н и р у ю щ и м
I П роверка введенных
пользователем данны х * и от зы вчивы м .

508 глава 10
применяем ja v a s c rip t на деле

Когда однопоточность — это ПЛОХО


Д е й с т в и т е л ь н о , во м п о г и х с и т у а ц и я х д а п п ы й о д п о п о т о ч п ы й р е ж и м в ы ч и с л е п и й с и с п о л ь з о в а н и е м
J a v a S c rip t о т л и ч п о р а б о та е т и , к а к м ы у ж е о тм е ч а л и , делает п р о ц е с с п р о гр а м м и р о в а н и я п р о с т ы м .
О д п а к о если в ы п а п и ш и т е ко д , к о т о р ы й будет тр е б о в а ть п а с т о л ь к о б о л ь ш о го о б ъ ем а в ы ч и с л е п и й ,
ч т о э то п а ч п е т о т р и ц а т е л ь н о с ка зы в а т ь с я п а с п о с о б н о с т я х J a v a S c rip t, о д п о п о т о ч п а я м одель с т а п е т
ра зва л и ва ть ся.

JavaScript-nom ok

В ы полнение ф ункции in it

Обработка собы тия clic k


г I .. Значение времени
<
таймера истекло
I I
Обработка события subm it

ж -ж -ж

О й, обработ ка большого
Все б удет з а м е ч а ­
Обработка массива данны х м ассива з а н и м а е т м ного
тельно работ ат ь
врем ени!
до т е х п о р , пока ч а с т ь
J a v a S c r i p t -кода не н а ч ­
Ж-Ж-Ж
н е т т р е б о в а т ь много
врем ени на о б р а б о т к у ,
ж -ж - ж Кто это прибрал к ру­
к о т о р о е будет з а ­
кам все время на обра­
бират ься у работ ы
ботку?
J a v a S c r ip t по в з а и м о ­
д е й с т ви ю с п о л ь з о в а ­ Обработка сл е д ую щ е го
^ собы ти я c lic k __ л Что у вас там
т елем и инт ерфейсом. наверху происходит? Задачи
Обновление объектной не выполняю тся!
1 ^ о д е л и докум ента ( D O M ) ^

Выборка данны х ф ормы 0 Q П ользователи уходят!


> - --------------------------------- Н Интерфейс не обновляется!
Г Проверка введенных 4
пользователем данны х О
Все, м ы сдаемся, выво­
дите диалоговое окно Slow S c rip t
(М едленны й сценарий).

дальш е ► 509
api-инт ерф ейс ja v a s c rip t web w orkers

Добавление еще одного потока управления в качестве помощника


Д о п о я в л е п и я H T M L 5 м ы п р и д е р ж и в а л и с ь п о д х о д а п а о с п о в е о д п о го п о т о к а у п р а в л е п и я для с в о и х
с т р а п и ц и п р и л о ж е п и й , о д п а ко б л а го д а р я W eb W o rk e rs у п а с п о я в и л с я с п о с о б созд ать еще о д и п п о т о к
у п р а в л е п и я для о к а з а п и я п о м о щ и гл а в п о м у п о то к у . Т а к и м о б р а зо м , е сли ваш к о д будет о т п и м а т ь м п о го
в р е м е п и п а о б р а б о тку , в ы с м о ж е те созд ать ф о п о в ы й в е б -с ц е п а р и й w o r k e r (б л о к J a v a S c rip t-кода, в ы п о л ­
н я ю щ и й с я в ф о п о в о м р е ж и м е ), к о т о р ы й за й м е тс я о б р а б о т к о й за д а чи , п о к а гл а в п ы й J a v a S c rip t-п о т о к
у п р а в л е п и я будет з а б о т и т ь с я о т о м , ч т о ка с а е тс я бр а узе р а и п о л ьзо в а те л я .

В м е с т о т ого чтобы замедлять? вы полнение з а ­


дач и з - з а большого объем а вычислений J a v a S c rip t,
мы м ож ем создат ь веб -сц ен а ри й w o r k e r , к о т ор ы й
JavaScript-nom ok будет вы п о л нят ь с я в о т д е л ь н о м п о т о к е и з а н и ­
м а т ь с я всей тяжелой работой. i f

i В ы пол нение ф ункции in it П о то к Веб-сценария worker


( Ребята,
Обработка собы тия c lic k 1 делайте все
начение времени необходимое, чтобы
На э т о т таймера истекло пользователь был
ра з все и д е т ( Worker доволен, а я зай-
гладко, в е б - ^Обработка события onsubm ilj мусь этой задачей;
сценарии
w o r k e r забо Создание веб-сценария
w o rk e r _____■
т ит ся о вы­
числениях:, Обработка с л е д ую щ е го
со 41JX ■
за н и м а ю щ и х
продолж и­ Обновление объектной
т е л ь н о е вре _ ^ J м одели документа (Р О М ) 7
Обработка массива данны х
мя...
С Выборка данны х ф ормы

i фоверка введенных
пользователем данны х

^И спользование массива

Выборка данны х ф ормы

С j П роверка введенны х^ А когда задача б удет вы полнена, веб -сц ен а ри й


| пользователем данны х w o r k e r даже см ож ет п р и с л а т ь нам данные,
над к о т о р ы м и он р а б о т а л , а м ы сможем в к л ю ­
ч и т ь их в наше прилож ение .

М ы о со б о п о д ч е р к и в а л и в а ж п о с т ь т о г о ф а кта , ч т о о д и п п о т о к у п р а в л е п и я о б е с п е ч и в а е т п р о с т о т у и л е г­
к о с т ь п р о ц е с с а п р о гр а м м и р о в а н и я , и э то правда. К а к в ы ещ е у в и д и т е , A P I-и п т е р ф е й с W e b W o rk e rs б ы л
тщ а те л ь п о п р о р а б о т а л , ч т о б ы все о с та в а л о сь п р о с т ы м и п а д е ж п ы м для п р о гр а м м и с т а . Ч у т ь п о з ж е м ы
узп а е м п а с к о л ь к о .

510 глава 10
применяем ja v a s c rip t на деле

J A V A S C R IP T (С Й 0 1 3 А )
Интервью недели:
Где JavaScript проводит свое время?

Head First: С в о зв р а щ е н и е м , J a v a S c rip t, п р и я т п о Вас в и д е ть.


JavaScript: Рад б ы ть здесь, п о да ва й те п р и д е р ж и в а т ь с я м о е го гр а ф и к а , а т о у м е п я еще о ч е п ь м п о го дел.
Head First: И м е п п о п а э то м , к а к я по л а га л , м ы и м о гл и б ы с о с р е д о т о ч и т ь с я во в р е м я с е го д п я ш п е го ра з­
го в о р а . В ы ста л и с в е р х у с п е ш п ы м п а р п е м , у Вас т а к м п о го в с е го п р о и с х о д и т — к а к В ам удается со всем
справляться?
JavaScript: Ч т о ж , у м е п я есть ф ило со ф ия: я делаю что -то од п о за раз, п о делаю это п о -п а сто ящ е м у х о р о ш о .
Head First: К а к э то В ы делаете т о л ь к о ч т о -т о о д п о за раз? К а к п а м к а ж е т с я , в ы и з в л е ка е те д а п п ы е , о т о ­
б р а ж а е те с т р а п и ц ы , в за и м о д е й ств у е те с п о л ьзо в а те л е м , уп р а в л я е те та й м е р а м и и д и а л о го в ы м и о к п а м и
a l e r t , п е о ста н а в л и в а я сь...
JavaScript: Д а , я все э то делаю , п о в о п р е д е л е п п ы й м о м е п т в р е м е п и то л ь к о ч т о -т о о д п о . Т а к и м об р а зо м ,
если я в за и м о д е й с т в у ю с п о л ьзо в а те л е м , то э т и м все и будет о гр а н и ч и в а т ь с я до т е х п о р , п о к а я п е р а з­
берусь с д а п п о й задачей.
Head First: Н е у ж е л и э то правда? А если з п а ч е п и е в р е м е п и та й м е р а и с т е ч е т, л и б о п о с е ти п о с т у п я т д а п ­
п ы е , л и б о п р о и з о й д е т ч т о -т о д р у го е — ра зве В ы п е о с т а н о в и т е с ь и п е за й м е те сь этим ?
JavaScript: П р и п а с т у п л е п и и с о б ы т и я вр о д е т е х , о к о т о р ы х в ы у п о м я н у л и , о п и будут д о б а в л е п ы в о ч е ­
редь. Я даж е п е в згл я н у п а п и х , п о к а п е з а к о п ч у т о , пад ч е м р а б о та ю . И с п о л ь з у я т а к о й п о д х о д , я делаю
все п р а в и л ь п о , п а д е ж п о и э ф ф е к т и в н о .
Head First: А сл уча л о сь л и ко гд а -п и б у д ь т а к , ч т о В ы с о п о з д а п и е м д о б и р а л и с ь до о д п о й и з т е х зад ач
в очере д и?
JavaScript: О , т а к бы вает. К сч а с т ь ю , я я в л я ю с ь т е х п о л о г и е й , с то я щ е й за б р а у зе р п ы м и в е б -с тр а п и ц а м и ,
п о э т о м у ч т о у ж т а к о г о п л о х о го в т о м , е сли я буду п е м п о г о запазды вать? В ам луч ш е п о г о в о р и т ь с п а р п я -
м и , к о т о р ы м п р и х о д и т с я в ы п о л п я т ь ко д , у п р а в л я ю щ и й р а б о т о й д в и га т е л е й к о с м и ч е с к и х к о р а б л е й и
к о п т р о л л е р о в а т о м п ы х э л е к т р о с т а п ц и й ... Э т и р е б я та в ы н у ж д е п ы ж и т ь п о д р у ги м п р а в и л а м — в о т п о ч е м у
о п и м п о г о за р а б а ты в а ю т.
Head First: М п е в се гд а б ы л о и п т е р е с п о у з п а т ь , ч т о п р о и с х о д и т , к о гд а у м е п я в б р а узе р е п о я в л я е т с я
д и а л о го в о е о к п о с с о о б щ е п и е м о м е д л е п п о м с ц е п а р и и и в о п р о с о м о т о м , х о ч у л и я п р о д о л ж и т ь е го вы -
п о л п е п и е . Э то из-за т о г о , ч т о В ы б е р е те п е р е р ы в ?
JavaScript: Б е р у п е р е р ы в ! Х а ! Т а к бы вает, к о гд а к т о -т о п е гр а м о т п о с т р у к т у р и р о в а л с в о ю стр а п и ц у , —
т а к и м о б р а зо м и п а м е п я в зв а л и в а е тся с т о л ь к о р а б о т ы , ч т о я п е м о гу с п е й с п р а в и т ь с я ! Е сл и в ы п а п и -
ш е те п е б о л ы н о й б л о к J a v a S c rip t-код а, к о т о р ы й будет о т п и м а т ь все м ое в р е м я , т о ваш е в з а и м о д е й с т в и е
с п о л ь зо в а те л е м п о стр а д а е т. Я м о гу в ы п о л п я т ь т о л ь к о ч т о -т о о д п о за раз.
Head First: П о х о ж е , В ам тр е б у е тс я п о м о щ ь .
JavaScript: Э та п о м о щ ь м п е о ка зы в а е т с я б л а го д а р я H T M L 5 , п о с к о л ь к у и м е п п о здесь в дело в с ту п а е т
A P I-и п т е р ф е й с W eb W o rk e rs . Е сли вам н у ж п о п а п и с а т ь ко д , т р е б у ю щ и й б о л ь ш о го объем а в ы ч и с л е п и й , —
и с п о л ь зу й т е W eb W o rk e rs , ч т о б ы с п я т ь с м е п я ч а с ть р а б о ты . Б л а го д а р я э то м у я с м о гу с о с р е д о т о ч и т ь с я п а
с в о и х задачах, а ве б -сц е па р и и w o rk e r сделаю т за м е п я п е к о т о р у ю тя ж е л у ю ра б о ту (п е меш ая п р и э то м м п е ).
Head First: Э то и п т е р е с п о , м ы иссл едуем д а п п ы й а с п е кт. А т е п е р ь с л е д у ю щ и й в о п р о с ... П о с т о й т е -к а ,
о п и с ч е з. П о х о ж е , уш ел за п и м а т ь с я с в о е й сл е д ую щ е й зад ачей. С е р ь е з п ы й о п п а р е п ь , п е п р а в д а ли?

дальше ► 511
как работ аю т веб-сценарии w orker

Как работают веб-сценарии worker


Д а в а й те в згл я п е м п а о д и п д е п ь и з ж и з п и в е б -сц е п а р и е в w o rk e r: к а к о п и со зд а ю тс я , о тку д а о п и зп а ю т,
ч т о дел ать, и к а к о п и в о зв р а щ а ю т р е зу л ь та ты ваш ем у о с п о в п о м у б р а у зе р п о м у коду.

Для их использования браузеру сначала потребуется создать один веб-сценарий worker (или
более), который станет помощником в решении задач. Каждый worker определяется посред­
ством своего собственного JavaScript-файла, содержащего весь код (или ссылки на код), необ­
ходимый ему для выполнения своей работы. _ .
Каждый вео -сц енар ии
w o rk e r определяет ся
Я действительно м о г N посредст вом о т д е л ь -
бы воспользоваться по- ) ного Jav a S c rip t -файла.
мощью... создав один w o rke r, \

Браузер

Все веб-сценарии worker живут в очень ограниченном мире; у них нет доступа к множеству объ­
ектов времени выполнения, который имеется у вашего основного браузерного кода, например
к объектной модели документа (DOM) или любым переменным либо функциям в коде.

Н ичего себе! Я не м о гу
получить доступ к DOM или
чем у-либо другом у в основном
браузерном коде.

Так будет намно­


го безопаснее — тебе не
0 3
нужно изменять объектную
модель документа, это моя
работа.
Браузер

512 глава 10
применяем ja v a s c rip t на деле

Чтобы worker начал работать, браузер обычно отправляет ему сообщение.


Код worker получает данное сообщение, изучает его на предмет каких-либо
особых инструкций и приступает к работе.

В твоем сообщении
сказано, что тебе нужно просчитать
се кц и ю изображения, создаваемого
У меня есть для тебя
методом трассировки лучей, размером
работа.
200 х 200 пикселов. Я м о гу сделать
это для тебя.

сообще­
ние

Worker

Браузер

Когда worker сделает свою работу, он отправит сообщение обратно вместе


с результатами того, над чем трудился. Основной браузерный код затем возь­
мет эти результаты и включит их в страницу определенным образом.

Вот работа,
которую ты просил
сделать.

Спасибо, что взялся за нее. Все


Браузер выглядит хорошо. Возможно,
чуть позже я снова приш лю тебе
задание...

дальш е ► 513
дост уп к dom

П очем у бы не разре­
шить веб-сценариям w o rke r доступ
к объектной модели документа? П о х о ­
же, отправка сообщ ений туда-сю да доста­
вит массу х л о п о т, если все веб-сценарии
w o rke r будут выполняться в одном
и том же браузере.

Отсутствие у них доступа к DOM объ ясня­


ется стремлением обеспечить эф ф ектив­
ность.
П р и ч и н а , п о к о т о р о й о б ъ е ктн а я модель д о к у ­
м е н та и Ja v a S c rip t я в л я ю тс я с то л ь у с п е ш н ы м и ,
за кл ю ч а е тс я в то м , ч т о м ы м о ж е м з н а ч и т е л ь н о
о п ти м и зи р о ва ть операци и с D O M , поскол ьку
у нас и м е е тс я т о л ь к о о д и н п о т о к с д о с т у п о м
к D O M . Е сли м ы п о з в о л и м сразу н е с к о л ь к и м
вы числительны м потокам одноврем енно вно­
с и т ь и з м е н е н и я в D O M , э то с е р ье зн о у д а р и т
п о у р о в н ю п р о и з в о д и т е л ь н о с т и (а р а зр а б о т­
ч и к а м б р а узе р о в п р и ш л о с ь б ы п р и л а га т ь б о л ь­
ш и е у с и л и я , ч т о б ы уб е д и ть с я в б е з о п а с н о с т и
в н е с е н и я и з м е н е н и й в о б ъ е к т н у ю м одель д о к у ­
м е н т а ). Ч е с т н о го в о р я , если р а з р е ш и т ь о д н о ­
врем енное внесение ку ч и и зм е н е н и й в D O M ,
э то м о ж е т п р и в е с т и к с и т у а ц и я м , ко гд а D O M
о к а ж е т с я в н е с о гл а с о в а н н о м с о с т о я н и и , а э то
плохо. О чень плохо.

Т о >чего мы к о т и м
избежать!

514 глава 10
применяем ja v a s c rip t на деле

-Возьми в руку карандаш


Взгляните на потенциальные варианты применения веб-сценариев w orker,
приведенные ниже. Что из перечисленного могло бы улучшить дизайн
и производительность приложения?

□ Кэширование данных для исполь­


зования в ваших страницах.
□ Проверка орфографии при вводе
пользователем текста на странице.

□ Обработка большого количества


данных в массивах или объемных
□ Опрос веб-служб и предупрежде­
ние основной страницы, когда что-
JSON-ответов, поступающих от веб­ то случается.
служб.

□ Управление подключениями к ба­


□ Обработка изображений в ca n v a s.

зам данных наряду с добавлением


и удалением записей на основной □ Подсветка синтаксиса
иного текста.
кода или

странице.

□ Автоматизированный агент для ста­ □ Предварительная выборка данных


в зависимости от того, что делает
вок на ипподроме.
пользователь.

□ Анализ видео.
□ Управление
странице.
рекламой на вашей

□ □
□ □
□ □
Свои идеи н а п и ш и т е здесь!

( - г - \ м п о ш о эн v f r ig o o g ‘ a w i i a g w i w o w ' v w o d p o v i v m v h rtyig vwio a w i v v v p v


‘m h n w d w o п о г о н ю i q m g o w ts v g w o ^ R o o vmhfiv <oh>kowso9 'рэиэх&умниэ n ппф»Жоф
- do fadzgodu -.awmdouoovi oh>kow э ж xmh ем nodvu о ow hqo ‘л щ л о г л gvndvHZh^psg
HYiH?H?wndu iciwiHvndvg vnmodox nogoo wicHXvgvwiogvdu iqwivqwio ■smiag эмнн ?vJYih?d?Ll

дальш е ► 515
будьт е вним ат ельны с браузерной поддержкой

Вы такж е м ож ет е в о с ­
Браузер Google Chrome предусматривает п о ль з о ва т ь ся п е р е к л ю ч а ­
л дополнительные ограничения (для обе- т е л е м врем ени вы полнения
|^ у Д Ы 1 1 6 I спечения безопасности), которые не по- C h ro m e - - a llo w -file -a c c e ss-
о с гц о Р оЖ Н ы ! зволят вам запускать веб-сценарии worker fr o m - file s , однако м ы р е к о ­
напрямую из файла. Если вы попытаетесь м е н д у е м в а м и с п о ль з о ва т ь
данный п а р а м е т р т о л ь к о
это сделать, станица не будет работать и вы не получите никаких
при т е с т и р о в а н и и кода.
уведомлений о причинах такого поведения (в том числе никаких
сообщений об ошибках, где будет сказано, в чем дело!).
Поэтому для приведенных здесь примеров рекомендуем вам ис­
пользовать другой браузер или свой собственный сервер и за­
пускать их с http://localhost. Либо можете загрузить их на онлайн-
сервер, если у вас имеется к нему доступ.

а Почти все современные браузеры поддерживают API-интерфейс


Web Workers, но есть одно исключение — Internet Explorer 9. Хоро­
]) у д ь щ е шая новость заключается в том, что в версии 10 (и выше) этого веб-
o c r n o p o ^ H b i! обозревателя вы можете рассчитывать на Web Workers, однако для
Internet Explorer 9 и всех предшествующих версий вам придется ис­
кать альтернативное решение.
Вы можете легко проверить и узнать, поддерживает ли тот или иной браузер API-интерфейс
Web Workers:
Если API - и н т е р ф е й с W eb W o rkers под - ^ если свойст во W o r k e r
держ ивается, т о с войст во W o rk e r б у д е м не определено, т о т а к а я
определено в глобальном о б ь е к т е w in do w , у поддержка в браузере 5 у -
^ дет от сут ст воват ь.
if (window["W orker"]) {
v a r s t a t u s = d o c u m e n t . g e t E l e m e n t B y l d ( " s t a t u s ") ;
s t a t u s . innerHTML = "Bummer, no Web Workers";

8 подобной с и т у а ц и и ва м п р и д е т с я п о с т у п и т ь
т а к , как б удет нужно для вашего прилож ения.
Здесь м ы п р о с т о у в е д о м л я е м п о л ь з о в а т е л я п у т е м
р а зм е щ е н и я сообщения в э л е м е н т е с id="status".

516 глава 10
применяем ja v a s c rip t на деле

Ваш первый веб-сценарий worker...


Д а в а й те созд ад им w ork er. Д л я э т о го п а м п о т р е б у е т с я с т р а п и ц а ,
в к о т о р о й все будет р а зм е щ а ть ся. М ы п а п и ш е м сам ую п р о с т у ю
Н Т М Ь б -р а з м е тку , к о т о р о й с м о ж е м о б о й т и с ь в д а п п о м случае;
в п е с и т е в p in g p o n g .h t m l т о , ч т о п о к а з а п о далее:

< ! d o c t y p e h tm l>
<htm l la n g= " en " >
<head>
< title > P in g P o n g < /title >
<meta c h a r s e t = " u t f - 8 ">
< s c r i p t s r c = " m a n a g e r .j s " > < / s c r i p t >
< /h e a d > \ ___^ Д а н н ы й J a v a S c r i p t -код создаст
<body> все веб -сцен а ри и w o r k e r и б удет
<p i d = " o u t p u t " > < /p > осущ ест влят ь управление и м и .
< /b o d y >
Г е н ери ру е м ы й в е б -с ц е н а р и ем w o r k e r
< /h t m l> вывод мы будем р а з м е щ а т ь здесь.

Как создать Веб-сценарий worker


П е р е д п а ч а л о м р е а л и з а ц и и m a n a g e r . j s в згл я п е м п а т о , к а к ф а к т и ч е с к и
со зд ается в е б -с ц е п а р и й worker:

Д л я создания нового w o r k e r м ы г е н е р и р у е м
новый о б ъ е к т Worker.
)
v a r w ork er = new W o r k e r ( " w o r k e r . j s " ); В еб-сц ена ри й
w orker
П рисваиваем новый ...Ja v a S c rip t- ф а й л worker.js будет
W o rk e r J a v a S c r i p t - содержать код для w orker,
п е р е м е н н о й worker.

В о т к а к созд ается о д и п w o rk er. О д п а к о вам п е о б я за т е л ь п о п а э т о м о с та н а в л и в а т ь с я —


м о ж е т е созд ать с т о л ь к о w o rk er , с к о л ь к о н у ж п о : д д ^ ^ е м легко с о з ­
дат ь два д о п олнит ель ны х
v a r w ork er2 = new Worker ( " w o r k e r . j s ") ; w o r k e r , ко т о р ы е б удут
v a r w o r k e r 3 = new W o rk er( " w o r k e r . j s " ); и с п о ль з о ва т ь т о т же код ,
ч т о и наш первы й worker.

v a r a n o t h e r _ w o r k e r = new W o r k e r ( " a n o t h e r _ w o r k e r . j s " ); Ч у т ь позже м ы п о ­


с м о т р и м j как и с п о л ь ­
Либо мы м ож ем создат ь д о п олнит е ль ны е зо в а т ь в м е с т е сразу
w o r k e r , основанные на др у го м J a v a S c r i p t -ф айле. несколько worker...

дальше ► 517
написание кода для управления w orker

Написание manager.js
Т е п е р ь , к о гд а в ы зп а е те , к а к созд ать w o rk er (и п а с к о л ь к о л е гк о э то д е л а е тся ), п о р а б о т а е м пад к о д о м
m a n a g e r . j s. О п будет п р о с т ы м , и се й ч а с м ы с ф о р м и р у е м т о л ь к о о д и п w ork er. С о зд а й те ф айл с и м е п е м
m a n a g e r . j s и доб авьте в п е го с л е д у ю щ и й ко д :

Мы дождемся полной
w in d o w .o n lo a d = f u n c t i o n () { загрузки страницы.
v a r w o rk er = new Worker ( " w o r k e r . j s ; ✓ л ^ ^
J 4— А з а т е м создадим
} новый worker.

Э то о т л и ч п ы й ста р т, о д п а ко т е п е р ь п а м п е о б х о д и м о сделать т а к, ч т о б ы w o rk er за п я л ся р а б о т о й .
К а к у ж е о тм е ч а л о с ь р а п е е , ч т о б ы за с т а в и ть w o rk er ч т о -т о сделать, н у ж п о о т п р а в и т ь ему со о б щ е п и е .
Д л я э т о го м ы во сп о л ьзу е м с я м е то д о м p o s t M e s s a g e о б ъ е кта w ork er. В о т к а к о п п р и м е п я е т с я :

w in d o w .o n lo a d = f u n c t i o n () {
v a r w o rk er = new W o rk er( " w o r k e r . j s ")

Используем м ет од
w o r k e r . p o s t M e s s a g e ( " p in g " ) ; ^ postMessage объекта
worker для отправки Хот ит е от прав­
т ему сообщения. Н аш е"
сообщение п р едст ав­
л ят ь более сложные
Метод postMessage определен для сообщения? Бот как
ляет собой про ст ую это делается...
вас в API -инт ерф ейсе Web Workers.
ст року "ping".

/>
под увеличительным сшекл°м

В ы с м о ж е те о т п р а в л я т ь п е ч т о б о льш ее, ч е м п р о с т о с т р о к и , и с п о л ь зу я
p o s t M e s s a g e . Д а в а й те в згл я п е м , ч т о м о ж п о о т п р а в л я т ь в с о о б щ е п и и :

Вы можете о т пра влят ь с т р о ку...


w o r k e r . p o s t M e s s a g e ( " p in g " ) ;
w o rk er . p o s t M e s s a g e ( [ 1 , 2, 3 , 5, 1 1 ] ) ; ...массив...
w o r k e r . p o s t M e s s a g e ( { " m e s s a g e " : " p in g " , " cou n t" : 5});
..или даже JSON -объект.

О т п р а в л я т ь ф у п к ц и и нельзя:
О т п р а в л я т ь т у или иную ф ункцию нельзя —
w o r k e r . p o s t M e s s a g e (updateTheDOM) ; она МоЖет содержать ссылку на объ ект н ую
модель докум ент а, позволяя w orker вносить
изменения в РОМ!

518 глава 10
применяем ja v a s c rip t на деле

Получение сообщений о т веб-сценария worker


М ы п о к а п е совсе м д о в о л ь п ы к о д о м m anager, j s — п а м ещ е н у ж п а в о з м о ж п о с т ь п о л у ч а т ь с о о б щ е п п я
о т w ork er , если м ы с о б и р а е м с я всецело и с п о л ь з о в а т ь е го т я ж е л ы й труд. Ч т о б ы п о л у ч и т ь с о о б щ е п и е о т
w ork er, п о т р е б у е т с я о п р е д е л и ть о б р а б о т ч и к для с в о й с т в а w o rk er с и м е п е м on m e ssa ge, ч т о б ы к а ж д ы й
ра з п р и п о с т у п л е п и и с о о б щ е п и я о т w o rk er п р о и с х о д и л в ы зо в п а ш е го о б р а б о т ч и к а (и п е р е д а ч а ему со-
о б щ е п и я ). В о т ч т о м ы сделаем:

О предел яем ф у н к ц и ю , кот орая будет вы ­


w in d o w .o n lo a d = f u n c t i o n () {
зыват ься всякий раз при получении с о ­
v a r w ork er = new W o r k e r ( " w o r k e r . j s f общения от данного w o rk e r. Сообщение
от w o rk e r будет обернут о в объект e v e n t
w o r k e r .p o stM e s sa g e (" p in g " );

w o r k e r . o n m essage = f u n c t i o n (event) { О б ъ е кт ev en t, п е р е ­
v a r m e s s a g e = "Worker s a y s " + e v e n t . d a t a ; даваемый наш ем у
обработ чику , облада­
d o c u m e n t . g e t E l e m e n t B y l d ( " o u t p u t " ) . innerHTML = m e s s a g e ;
ет свойст вом d a ta ,
содерж ащ им данные
При получении сообщения от сообщения (нуж ны е
w o rk e r м ы п о м ест и м его в э л е ­ нам ), кот оры е о т ­
м ен т <р> в H T M L -ст ранице. правил w o rk er.

/>
oum e^age под ув е л и ч и те л ь н ы м с т е кл а м

К р а т к о р а с с м о т р и м с о о б щ е п и е , к о т о р о е п а ш о б р а б о т ч и к on m e ssa ge п о л у ч а е т о т w ork er.


К а к м ы у ж е г о в о р и л и , д а п п о е с о о б щ е п и е будет о б е р н у т о в о б ъ е к т e v e n t , к о т о р ы й обладает
двум я и п т е р е с у ю щ и м и пас с в о й с т в а м и : d a t a и t a r g e t :

Эт о о б ъ е кт , кот оры й w o rk e r посы лает коду


в вашей ст ранице при от правке сообщения.

Свойст во d ata содерж ит сообщ ение ,


w o r k e r . o n m e ssage = f u n c t i o n (event
кот орое от правил w o rk e r ( н а п р и м ер ,
var m essage = e v e n t .d a t a ; « -------------------- с т р о к у вроде "pong").
v a r w o rk er = e v e n t . t a r g e t ;
ta rg e t - эт о ссылка на w o rk e r, кот оры й
от правил сообщение. Д анное свойст во при -
дет ся к ст а т и , когда вам п о т р еб у ет ся у з ­
нат ь , о т какого w o rk e r исходит сообщение
М ы дудем использоват ь его далее в главе

дальш е ► 519
ваш первы й w orker

А теперь напишем worker


П р и с т у п а я к п а п и с а п и ю w o rk e r, п е р в ы м д ел ом п а м п е о б х о д и м о п о з а б о т и т ь с я о т о м , ч т о б ы п а ш
w o rk er с м о г п р и п и м а т ь с о о б щ е п и я , к о т о р ы е п о с т у п а ю т о т m a n a g e r . j s , — т а к w o rk e r будет п о л у ч а т ь
за д а п и я п о р а б о те . Д л я э т о го п а м т а к ж е п о т р е б у е т с я за д е й с тв о в а ть о б р а б о т ч и к on m e ssa ge, к о т о р ы й
будет в сам ом w ork er. К а ж д ы й w o rk er го т о в к п р и е м у с о о б щ е п и й , вам н у ж п о л и ш ь д ать ему о б р а б о т­
ч и к для и х о б р а б о т к и . С о зд а й те ф айл w o r k e r . j s n д обавьте в п е го п р и в е д е п п ы й далее ко д :

on m e ssa ge = p in g P o n g ;

Присваиваем свойст во Мы собираемся н а п и с а т ь


o n m e ssa g e ^ w orker ф у н к ц и ю pingP ong для
ф ункци и pingPong. обработки всех п о с т у ­
п а ю щ и х сообщений.

Написание обработчика сообщений для worker


Н а п и ш е м о б р а б о т ч и к с о о б щ е п и й p in g P o n g для w ork er. П о п а ч а л у все будет п р о с т о . В о т ч т о будет
п р о и с х о д и т ь (в ы у ж е м о гл и об э т о м д о га д а ть ся, в згл я н у в п а и м я p in g P o n g ): w o rk er будет п р о в е р я т ь
л ю б о е п о л уча е м о е и м с о о б щ е п и е , ч т о б ы у б е д и ть с я в т о м , ч т о о п о с о д е р ж и т с р о к у "p in g", и если
э та с р о к а п р и с у тс т в у е т, т о м ы о т п р а в и м пазад с о о б щ е п и е со с т р о к о й "pong". Т а к и м о б р а зо м , р а б о ­
т а w o rk er в д е й с т в и т е л ь н о с т и будет за кл ю ч а т ь с я л и ш ь в п р и е м е "ping" и о т п р а в к е о тв е т а в вид е
"pong" — м ы п е со б и р а е м с я п р о и з в о д и т ь ка ки е -л и б о и п т е п с и в п ы е в ы ч и с л е п и я , а п р о с т о у б е д и м ся в
т о м , ч т о m a n a g e r . j s и w o rk er о б щ а ю т с я д р у г с д р у го м . Е сл и ж е с о о б щ е п и е п е будет с о д е р ж а т ь с т р о к у
"pin g", м ы п р о с т о п р о и г п о р и р у е м е го .

Т а к и м о б р а зо м , ф у п к ц и я p in g P o n g будет п р и п и м а т ь с о о б щ е п и е и о т в е ч а т ь п а п е го "pong". Д о б а в ь те
п р и в е д е п п ы й далее к о д B w o r k e r . j s :

Когда w o r k e r п о л у ч и т сообщение
о т основного кода, п р о и зо й д е т вызов
ф ун кц и и p in g P o n g , к о т о р о й б удет
передано данное сообщение.
o n m essa ge = p in g P o n g ; EL.
Если сообщение будет содержать
f u n c t io n p in g P o n g (e v en t) {
с т р о к у "p in g ", м ы о т п р а в и м назад с о ­
if ( e v e n t . d a t a == "ping") {
общение со с т р о ко й "pong". О т в е т н о е
p o s t M e s s a g e ( "pong") ;

О б р а т и т е вн им ан и е, ч т о w o r k e r
тоже и с п о л ь з у е т postM essage для
о т п р а в к и сообщений.

520 глава 10
применяем ja v a s c rip t на деле

Проведение тест-драйба
У б е д и те сь в т о м , ч т о в ы п а б р а л и и с о х р а п и л и весь н е о б х о д и м ы й
к о д в p i n g p o n g . h t m l , m a n a g e r . j s и w o r k e r . j s. Т е п е р ь д е р ж и т е э т и
ф а й л ы о т к р ы т ы м и , ч т о б ы м о ж п о б ы л о за гл я д ы в а ть в п и х , и да­
в а й те задумаемся пад те м , к а к все р а б о та е т. С па ча л а m a n a g e r . j s ООП
геперирует повый w ork er, присваивает ему обработчик сообщ е- S j p !^ ^ h tt ^ oca(hpSt/^Be~ ^ -
ПИЙ, а Затем ОТПраВЛЯеТ ЭТОМу w o rk er Сообщепие СО СТрОКОЙ Worker says pong
"ping". В св о ю о че р е д ь, w o rk er уб е ж д а е тся в т о м , ч т о фупкция
p in g P o n g задапа в ка ч е с т в е е го о б р а б о т ч и к а с о о б щ е п и й , после
ч е го п а ч и п а е т ж д а ть . В к а к о й -т о м о м е п т w o rk er п о л у ч а е т со о б ­
щ е п и е о т m anager, j s и п р о в е р я е т е го п а п р е д м е т с о д е р ж а п и я
с т р о к и "ping", к о т о р а я и будет в п е м п р и с у т с т в о в а т ь . З а те м
w o rk e r в ы п о л п я е т м ассу со все м п е м п о г о т я ж е л о й р а б о т ы и о т ­
п р а в л я е т в о т в е т с о о б щ е п и е со с т р о к о й "pong".

В э то т м о м е п т о с п о в п о й б раузерпы й код получает сообщ епие о т


w ork er, к о т о р о е п е р е д а е т о б р а б о т ч и к у с о о б щ е п и й . О б р а б о т ч и к
за те м п р о с т о д о б а в л я е т "Worker s a y s " п е р е д э т и м с о о б щ е п и е м и
в ы в о д и т е го п а э к р а п .

И т а к , п р о в о д и м ы е п а м и в ы ч и с л е п и я г о в о р я т о т о м , ч т о п а с тр а ­
п и ц е д о л ж п а п о я в и т ь с я ф раза "Worker s a y s pong"... Л а д п о , л а д по ,
м ы п о п и м а е м , ч т о в ы б о льш е п е м о ж е т е в ы п о с и т ь п а п р я ж е п п о г о
о ж и д а п и я . З а гр у з и т е ж е , п а к о п е ц , э ту с т р а н и ц у !

П остойте-ка, просто думая на­


перед... Если нам когда-либо придется
создать более одного w orker, лю бящ его играть
в такой « п и н г-п о н г» , то мне действительно
придется попотеть.

дальш е ► 521
СТАНЬбраумром -------------------
ДрхШдо Бремя п ри твориться £раузер°М, «ДениБа1°ЩиМ
JavaScript-Код. |J оп роси те се^я в р°Ли браузера для ^ — Свои о т в е т ы вы
см ож ет е п р о в е р и т ь
КаЖДоГо &л°Ка К«Да, приведенного ниже, и н а -
в р еш ении к э т о м у
пиШише Генерируемый UM ВыВод на стр о ­ заданию в конце главы .

ках справа. ]У[ожете с ч и т а т ь , Чцю дан­


ный код использует т ° т же ^ а й л woikerjg,
Кот°рый Мы т°ЛьКо Чщо написали.

w in d o w .o n lo a d = f u n c t i o n () {
v a r w o rk er = new Worker ( " w o r k e r . j s " );
w o r k e r . o n m e ssage = f u n c t i o n ( e v e n t ) {
a l e r t ( "Worker s a y s " + ev e n t.d a ta );
}
for (v a r i = 0; i < 5; i++ ) {
w o rk er .p o stM essa g e(" p in g " ) ;
}

w in d o w .o n lo a d = f u n c t i o n () {
v a r w o rk er = new W o r k e r ( " w o r k e r . j s " );
w o r k e r . ommessage = f u n c t i o n ( e v e n t ) {
a l e r t ( "Worker s a y s " + ev e n t.d a ta );
}
f o r ( v a r i = 5; i > 0; i - - ) {
w o r k e r .p o stM e ssa g e (" p o n g " );
}

522 глава 10
применяем ja v a s c rip t на деле

w in d o w .o n lo a d = f u n c t i o n () {
v a r w o rk er = new W o r k e r ( " w o r k e r . j s " );
w o r k e r . o n m e ssage = f u n c t i o n ( e v e n t ) {
a l e r t ( "Worker s a y s " + e v e n t . d a t a ) ;
w o r k e r . p o s t M e s s a g e ( " p in g " ) ;
}
w ork er. p o stM essa g e(" p in g " );

a Б у д е т е осторожны с э т и м и блокам и
кода. Возможно , в а м п р и д е т с я п р и н у ­
д и т ель н о з а в е р ш и т ь р а б о т у б р а узе р а ,
чтобы п р е к р а т и т ь их вы полнение ...

w in d o w .o n lo a d = f u n c t i o n () {
v a r w o rk er = new W o r k e r ( " w o r k e r . j s " );
w o r k e r . o n m e ssage = f u n c t i o n ( e v e n t ) {
a l e r t ( "Worker s a y s " + e v e n t . d a t a ) ;
}

se tln te r v a l(p in g e r , 1000);

fu n c tio n p in g e r() {
w o r k e r . p o s t M e s s a g e ( " p in g " ) ;

дальш е ► 523
упражнение на использование компакт ного w orker

-Возьми в руку карандаш


Несмотря на то что обычно веб-сценарии w o rk er получают рабочие задания посред­
ством сообщений, такой подход вовсе не обязателен. Взгляните на данный отличный
и компактный способ сделать необходимую работу с помощью веб-сценариев w ork er
и HTML. Когда вы разберетесь в том, что делает данный код, опишите это внизу. Свой
ответ вы сможете проверить в решении к этому упражнению в конце главы.

< ! d o c t y p e htm l> q u o te .h tm l


<htm l la n g = " en " > ^
<head>
< title > Q u o te < /title >
<meta c h a r s e t = " u t f - 8 ">
< /h e a d >
<body>
<p i d = "q u ot e ">< / p>
< scr ip t>
v a r w o rk er = new W o rk er( " q u o t e . j s " );
w o r k e r . on m e ssage = f u n c t i o n ( e v e n t ) {
d o c u m e n t . g e t E l e m e n t B y l d ( " q u o t e " ) . innerHTML = e v e n t . d a t a ;
}
< /sc rip t>
< /b o d y >
< /h t m l> qwote.js

i-
v a r q u o te s = ["I hope l i f e i s n ' t a j o k e , b e c a u se I d o n ' t g e t i t . " ,
"There i s a l i g h t a t t h e end o f e v e r y t u n n e l . . . j u s t p ray i t ' s n o t a t r a i n ! " ,
"Do you b e l i e v e i n l o v e a t f i r s t s i g h t or s h o u ld I walk by a g a in ? " ] ;
v a r in d e x = M a th .flo o r (M a th .r a n d o m () * q u o t e s . l e n g t h ) ;
p o s t M e s s a g e ( q u o t e s [ i n d e x ] );

П опробуйт е ввест и
Свое описание п р и в е д и т е здесь: вы п о л н и т ь данный код!

524 глава 10
применяем ja v a s c rip t на деле

Г ф З Ж Н бН И б Давайте добавим несколько worker в нашу игру p ingP on g. Ваша задача заключается
в том, чтобы устранить имеющиеся пробелы и завершить приведенный внизу код, чтобы
в результате происходила отправка трех сообщений со строкой "ping" веб-сценариям
worker, а в ответ от них поступали три сообщения со строкой "pong".

w in d o w .o n lo a d = f u n c t i o n () { М и создаем т р и w o r k e r и со
v a r numWorkers = 3; в м ассиве workers.
хр а н я е м wx
var w orkers = [];
for (var i = 0; i < ; i++ ) {
v a r w o rk er = new ( " w o r k e r . j s ")
У с т р а н и т е пробелы,
за п олнив их с о о т ­ w orker. = fu n ctio n (ev en t) {
в е т с т в у ю щ и м кодом .
a l e r t ( e v e n t . ta r g e t + " says "
+ even t.
};
w o rk ers. p ush (w orker);
Здесь м ы добавляем новый
}
w o r k e r в м а с с и в w o r ke r s
for (var i = 0; i < i+ + ) {
w o rk ers[i]. ("p ing" )
}

Ч а ст°
^адаВ аеМ ы е
B o llp o C b l

! / • Можно ли просто передать функцию вместо JavaScript- Если отправить веб-сценарию worker объект
файла при создании worker? Наверняка так было бы проще в сообщении, станет ли он объектом, совместно
и это лучше соответствовало бы стандартному поведению используемым основной страницей и этим worker?
JavaScript.
0 : Нет, когда вы отправляете объект веб-сценарию w o rk er ,
0 : Нет, нельзя. И вот почему: как вы знаете, одно из требо­ он получает его копию. Любые изменения, который вносит worker,
ваний, касающихся веб-сценариев w ork er, заключается в том, не затронут объект в вашей основной странице, w o rk er выпол­
что они не должны иметь доступа к объектной модели документа няется в среде, отличной от вашей основной страницы, поэтому у
(или к любому состоянию главного браузерного потока). Если бы вас не будет доступа к находящимся там объектам. Аналогичным
можно было передать конструктору Worker функцию и при этом образом дело обстоит и с объектами, которые w orker отправляет
оказалось бы, что ваша функция содержит ссылку на DOM или вам: вы будете получать их копии.
другие части основного JavaScript-кодэ, это нарушило бы данное
требование. Таким образом, разработчики API-интерфейса Web
Workers предпочти сделать так, чтобы вы передавали URL-адрес либо возможность совершать запросы с использованием
JavaScript-файла во избежание данной проблемы. XMLHttpRequest?

О Да, у веб-сценариев w o rk er имеется доступ


к l o c a l S t o r a g e и возможность совершать запросы с ис­
пользованием XMLHttpReguest.

дальш е ► 525
вклю чение ja va scrip t-кода в w orker

пражнение Давайте добавим несколько w o rk er в нашу игру p ingP on g. Ваша задача заключает­
решение ся в том, чтобы устранить имеющиеся пробелы и завершить приведенный внизу код,
чтобы в результате происходила отправка трех сообщений со строкой "ping" веб­
сценариям w orker, а В ответ ОТ НИХ поступали три сообщения СО строкой "pong".
Вот наше решение этого упражнения.

М ы и с п о л ь з у е м n u m W o r k e r s для т р е х к р а т н о г о соверш ения


и т е р а ц и и и создания т р е х w o r k e r (вы м ож ет е свободно и з м е ­
н и т ь значение данной п е р е м е н н о й , чтобы их было больше!).

М ы задали о б р а б о т ­
w in d o w .o n lo a d = f u n c t i o n () { чик сообщений в коде
v a r numWorkers = 3; нашей основной
var workers = []; ст раницы , исполь­
зуя свойст во w o r k e r
fo r (var i = 0; i < numWorkers; i+ + ) {
с и м е н е м onmessage.
v a r w o rk er = new Worker ( " w o r k e r . j s
w o r k e r . o n m e ssage = f u n c t i o n ( e v e n t ) {

a l e r t ( e v e n t . ta r g e t + " says "


+ ev e n t.d a ta );
}; И с п о л ь з у е м свойст во d a ta
w o r k e r s .p u s h ( w o r k e r ) для извлечения содержимого
} сообщения.
for (var i = 0; i < w o r k e r s . l e n g t h ; i+ + ) {
w o r k e r s [ i ] . p o s t M e s s a g e ( " p i n g " ) /r \
} t Вы также м ож ет е и с п о л ь ­
О т п р а в л я е м веб -сц е н а р и ю зо ва т ь здесь n u m V J o r k e r s ,
w o r k e r сообщение со с т р о ­ если за х о т и т е .
кой « p i n g » с п о м о щ ь ю
postMessage. г
С ледует о т м е т и т ь , ч т о ^ ^ ^ ^ Т р а д о с т ь ю
независимо т

Д а н н о е диалоговое
окно alert п оя вит ся (
на экране трижды.

526 глава 10
применяем ja v a s c rip t на деле

Интересно, как вклю чить ^


дополнител ьны е J a v a S c rip t-ф айлы в м ой
w orker? У меня имеется несколько связанных
с финансами библиотек, которые я хотел бы ис­
пользовать, однако в результате и х копирования
и вставки в w o rke r получится огром ны й файл,
которы й не очень удобен в сопровождении.

Вам стоит взглянуть на im portScripts.


A P I-и н т е р ф е й с W eb W o rk e rs в к л ю ч а е т гл о б а л ьн ую ф у н к ц и ю
i m p o r t S c r i p t s , к о т о р у ю в ы м о ж е те и с п о л ь зо в а ть для и м ­
п о р т а о д н о го и л и более J a v a S c rip t-ф айлов в ваш w ork er. Д л я
и с п о л ь з о в а н и я ф у н к ц и и i m p o r t S c r i p t s вам н у ж н о н р о с т о
пе р е д а ть е й с п и с о к р а з д е л е н н ы х з а п я т ы м и ф а йл о в л и б о U R L -
адресов, к о т о р ы е в ы х о т и т е и м п о р т и р о в а т ь :

i m p o r t S c r i p t s ( "h t t p : / / b i g s c i e n c e . o r g / n u c l e a r . j s ",
"h t t p : / / n a s a . g o v / r o c k e t . j s ",
" m y l i b s / a t o m s m a s h e r . j s ") ;

П о м е с т и т е в im p o r tS c r ip t s нужное к о ­
ли ч е с т во (или нуль) разделенны х з а п я ­
т ы м и U R L -адресов J a v a S c r i p t -ф айлов.
З а те м , ко гд а ф у н к ц и я i m p o r t S c r i p t s будет вы зв а н а , к а ж д ы й
и з U R L -адресов J a v a S c rip t-ф айлов будет и з в л е ка ть с я и о ц е н и ­
в а ть с я н о н о рядку.

С ледует о т м е т и т ь , ч т о i m p o r t S c r i p t s я в л я е тс я н о л н о ц е н н о й
ф у н к ц и е й , в сил у ч е го (в о т л и ч и е о т о н е р а т о р о в im p o r t во
м н о г и х я з ы к а х ) в ы с м о ж е те н р и н и м а т ь р е ш е н и я об и м н о р т е
в о в р е м я в ы п о л н е н и я , к а к н о ка за н о далее:

if (ta sk T y p e == " s o n g d e t e c t i o n " ) {


im p o r tS c r ip ts(" a u d io .js" );

Поскольку i m p o r tS c r ip t s — ф у н кц и я ,
вы см ож ет е и м п о р т и р о в а т ь код
по м е р с т о го , как эт о го б уд е т т р е
боват ь определенная задача.

дальш е ► 527
м ножест во Мандельброта

Захват виртуальных земель


И с с л е д о в а те л и м н о ж е с т в а М а н д е л ь б р о т а у ж е з а х в а т и л и о б л а с ти в и р т у а л ь н о й с е л ь с к о й м е с т н о с т и
и дал и и м н а з в а н и я вр о д е к р а с и в ы х « Д о л и н а м о р с к и х к о н ь к о в » ( Seahorse Valley), « Р адуж ны е о стр о в а »
( Rainbow Islands) и л и у с тр а ш а ю щ е го « Ч е р н а я ды ра» ( Black Hole). А у ч и т ы в а я с е го д н я ш н и е ц е н ы н а р еаль­
н у ю н е д в и ж и м о с т ь , н о х о ж е , ч т о е д и н с т в е н н ы й н р о с т о р о ста л ся в в и р т у а л ь н о м п р о с т р а н с т в е . П о э т о м у
м ы со б и р а е м с я со зд а ть н р и л о ж е н и е для м н о ж е с т в а М а н д е л ь б р о т а н о д н а з в а н и е м F ra c ta l E x p lo re r, ч т о ­
б ы п о у ч а с тв о в а т ь в э т о м д е й с тв е . В о о б щ е -то м ы д о л ж н ы н р и з н а т ь с я , ч т о у ж е со зд а л и н р и л о ж е н и е , од­
н а к о о н о м е д л е н н о р а б о та е т — н е р е м е щ е н и е н о всем у м н о ж е с т в у М а н д е л ь б р о т а м о ж е т за н и м а ть о ч е н ь
д о л го е в р е м я , н о э т о м у над еем ся, ч т о вм е сте с м о ж е м у с к о р и т ь е го . К а к м ы н о д о зр е в а е м , р е ш е н и е м д а н ­
н о й н р о б л е м ы м о ж е т с та ть A P I-и н т е р ф е й с W eb W o rk e rs .

•* + ^ http /i'lix jlhn'.l,1- Rrlh/HTMl S,1Fr.u1.il/fr.ic1.il.html

He х о т е л и St?i п р и о б р е с т и дом
с видом на пляж у самого края
« Л а зу р н о г о во доворот а»?

Осмотритесь
П о с е т и т е с т р а н и ц у h t t p : / / w i c k e d ly s m a r t . c o m / h f lit m l5 / c h a p t e r l0 / s in g le t h r e a d /
fr a c ta l.h tm l, ч т о б ы ув и д е ть в и з у а л и з а ц и ю м н о ж е с т в а М а н д е л ь б р о та . Щ е л к н и т е в
л ю б о м м есте к н о п к о й м ы ш и — и в ы у в е л и ч и т е с о о т в е т с т в у ю щ у ю о б л а сть к а р т ы .
П р о д о л ж а й т е щ е л ка ть , ч т о б ы иссл е д о в а ть р а з л и ч н ы е о б л а с ти , л и б о п е р е з а гр у з и ­
те с т р а н и ц у и н а ч н и т е все сначала. О с т е р е га й т е с ь о б л а с те й с ч е р н ы м и д ы р а м и ,
н о с к о л ь к у о н и будут п ы т а т ь с я за т я н у ть вас. Н а н а ш взгляд, х о т ь п е й з а ж и и в ы гл я ­
д я т н р е в о с х о д н о , п р о гр а м м а п р о с м о т р а м огл а б ы р а б о та ть н е м н о го б ы с тр е е ... К а к
в ы счи тае те? К р о м е т о г о , б ы л о б ы з д о р о в о , если бы на ш е п р и л о ж е н и е обладало
т а к о й п р о и з в о д и т е л ь н о с т ь ю , ч т о б ы м о ж н о б ы л о р а зв е р н у ть п р е д с та в л е н и е н а все
о к н о браузера! Д а в а й те о б е с н е ч и м все э т о , д о б а в и в в е б -с ц е н а р и и w o r k e r в н р и л о ­
ж е н и е F ra c ta l E x p lo re r.

528 глава 10
применяем ja v a s c rip t на деле

Если вдруг вы математик,


т о вам и з в е с т н о , ч т о м н о ж е с т в о М а н д е л ь б р о т а ге н е р и р у ­
ется н о ср е д ств о м ур а в н е н и я :

% +1 = % 2 + с

и ч т о е го о т к р ы л и иссл е до ва л Б енуа М а н д е л ь б р о т. В ы
т а к ж е зн а е те , ч т о э то н р о с т о м н о ж е с т в о к о м п л е к с н ы х
ч и с е л (ч и с е л с в е щ е с т в е н н о й и м н и м о й ч а с т ь ю ), ге н е р и ­
р у е м ы х с н о м о щ ь ю д а н н о го у р а в н е н и я .

Е сли ж е в ы н е м а т е м а т и к , т о н а и л у ч ш и й с п о с о б п р е д ­
с та в и ть себе м н о ж е с т в о М а н д е л ь б р о т а — э то с ч и т а т ь
е го б е с к о н е ч н о с л о ж н ы м ф р а к т а л ь н ы м и з о б р а ж е н и е м ,
нод к о то р ы м ноним ается изображ ение, ко то р о е м о ж но
у в е л и ч и в а т ь до л ю б о й с т е н е н и и н а х о д и т ь л ю б о п ы т н ы е
с т р у к т у р ы . В з гл я н и т е н а н е к о т о р ы е к а р т и н ы , к о т о р ы е
м о ж н о о т ы с к а т ь п у те м н е р е м е щ е н и я н о м н о ж е с т в у :

П о ч е м у ж е о н о нас т а к и н те р е с у е т? Д а н н о е м н о ж е с т в о
обладает р я д о м л ю б о н ы т н ы х с в о й с т в . В о -н е р в ы х , о н о
ге н е р и р у е т с я п о с р е д с т в о м о ч е н ь н р о с т о г о у р а в н е н и я
(о н о н р и в о д и л о с ь в ы ш е ), к о т о р о е м о ж е т б ы т ь в ы р а ж е н о
в с е го л и ш ь н е с к о л ь к и м и с т р о к а м и ко д а . В о -в т о р ы х , ге н е ­
П окойся С м и р о м ,
р и р о в а н и е м но ж е ства М андельброта заним ает изряд ное
ееН9« М я н Э е л ,б р о т ,
к о л и ч е с т в о в ы ч и с л и т е л ь н ы х ц и к л о в , ч т о делает е го о т ­
скоНыавмийся, когда
л и ч н ы м н р и м е р о м для и с н о л ь з о в а н и я в с о ч е т а н и и с A P I-
Z п и с а л , э т у кн и гу .
и н т е р ф е й с о м W eb W o rk e rs . И н а к о н е ц , э то ж е кл а с с н а я
Нам повезло
вещ ь, с к о т о р о й м о ж н о н о р а б о т а т ь , и у нас е сть зам еча­
зн ако м ы м и с т а к
те л ь н о е н р и л о ж е н и е , ч т о б ы з а к о н ч и т ь и м к н и гу .
челобекоМ , как w w -

дальш е ► 529
вы числение фракталов
С ледует о т м е т и т ь , ч т о наша
цель з а к л ю ч а е т с я не в т о м ,
Как Вычисляется мноЖестВо Мандельброта чтобы с д е ла т ь из вас с п е ц и а л и ­
с т а по ч исленн ом у а на ли зу ( к о ­
П р е ж д е ч е м и с н о л ь з о в а т ь в е б -с ц е н а р и и w o rk e r, в згл я н е м , к а к т о р ы й у м е е т п и с а т ь уравнен и я
о б ы ч н о н р и х о д и т с я с т р у к т у р и р о в а т ь ко д для в ы ч и с л е н и я м н о ж е ­ с и с по ль зо вани ем ко м плек сны х
ств а М а н д е л ь б р о та . М ы не х о т и м удел ять м н о г о в н и м а н и я п о д р о б ­ чисел), а в т о м , чтобы а д а п ­
но стя м в ы чи сл е ни я зн а че н и й ни ксе л о в м нож ества М андельброта, т и р о в а т ь т р е б у ю щ е е большого
т а к к а к у ж е н о л н о с т ь ю н о з а б о т и л и с ь о с о о тв е т с тв у ю щ е м ко д е и
объем а вычислений прилож ение
к испо льзо вани ю веб -сцен а риев
со б и р а е м с я п р о д е м о н с т р и р о в а т ь е го ч у т ь н о з ж е . А се й ч а с м ы н р о -
worker. Если вас и н т е р е с у ю т
с то х о т и м , ч т о б ы в ы р а зо б р а л и с ь в о б щ е й к а р т и н е :
численные а спект ы множ ест ва
Д л я вычисления м нож ест ва М а н ­ М андельбро т а — « В и к и п е д и я »
Г д ельброт а м ы со вер ш а ем цикл
по каждой с т р о к е изображения.
по м о ж ет н а ч а т ь исследование
данного вопроса.
fo r (i = 0; < n u m b e r O fR o w s ; i+ + ) {

va r ro w = c o m p u te R o w ( i) ; И для каждой
d ra w R o w (ro w ); с т р о к и вы числяем
пикселы.

А з а т е м р и с у е м каждую с т р о к у на экране.
Вы, в е р о я т н о , смож ет е у в и д е т ь п о с т р о ч н у ю
о т р и с о вк у изображения, когда з а п у с т иАте
т е с т о в ы й код в браузере.

В т е к у щ и й м о м е н т д а н н ы й ко д н р и з в а н б ы ть н р о с т ы м п с е в д о к о ­
дом . К о г д а ж е дело д о й д е т до н а н и с а н и я ко д а н о -на сто я щ е м у, н а м
н о т р е б у е т с я р а зо б р а ть с я с д о п о л н и т е л ь н ы м и д е та л я м и: н а н р и м е р ,
для в ы ч и с л е н и я с т р о к и н а м н о т р е б у е т с я зн а ть ее ш и р и н у , к о э ф ф и ­ ш ирина
ц и е н т у в е л и ч е н и я , ч и с л е н н о е р а з р е ш е н и е , до к о т о р о г о м ы х о т и м
н р о и з в е с т и ее в ы ч и с л е н и е , а т а к ж е н р о ч и е м е л ки е де та ли. М ы м о ­
ж е м со б р а ть все э т и д е та л и в о д н о м о б ъ е кте ta s k : К оэф фициент
увелич ени я
fo r (i = 0; i < n u m b e r O fR o w s ; i+ + ) {

var ta s k F o r R o w = c re a te T a s k F o rR o w (i ) ;

var ro w = c o m p u te R o w (ta s k F o rR o w );
Объект
ta s k F o rR o w
d ra w R o w (ro w );
t содерж а Уровень т о ч ­
Передаем ta skF o rR ow ф у нкции данные, необхо­
н о ст и для
c o m p u te R o w , к о т о р а я в о з в р а ­ димые Зля вы -
вычисления
т и т вы численную с т р оку. ч и сл ен и я с т р о к и .

Х и т р о с т ь будет з а кл ю ч а т ь с я в следую щ ем : н у ж н о в зя ть все э то и д о р а б о та ть т а к и м о б р а зо м , ч т о б ы р а с­


п р е д е л и т ь в ы ч и с л е н и я м е ж д у н е с к о л ь к и м и w o r k e r , а за те м д о б а в и т ь ко д , к о т о р ы й за й м е тс я о б р а б о т ­
к о й р а зд а ч и зад ач в е б -с ц е н а р и я м w o r k e r , а т а к ж е о б р а б о т к о й д е й с т в и й с р е зул ьта та м и , к о гд а все w o r k e r
за в е р ш а т в ы н о л н е н и е с в о и х задач.

530 глава 10
применяем ja v a s c rip t на деле

Как задействовать сразу несколько веб-сценариев worker


Вы уже знаете, как создавать новые веб-сценарии worker, однако как их использовать для чего-
то более сложного, например вычисления строк множества Мандельброта? Или применения к
изображению эффекта, как в Photoshop? Или генерирования сцены из видеофильма методом
трассировки лучей? Во всех этих случаях мы можем разбить работу на небольшие задачи, над
которыми веб-сценарии worker смогут трудиться независимо друг от друга. Мы будем придер­
живаться множества Мандельброта (однако шаблон, который мы собираемся использовать,
может быть применен к любому из этих примеров).
Для начала браузер создает группу веб-сценариев worker в качестве помощников (но не очень
много, ибо веб-сценарии worker могут дорого обойтись, если создать их слишком много, — по­
говорим об этом позже). В нашем примере мы используем пять worker:

Ьраузерный JavaS cript-код


создает группу w orker для
пол нения некоторой работы.

^ Здесь изображение
ра зб и вает ся на н е -
<г- больш ие област и.
М ы будем р а зд а ва т ь
^ э т и област и в е б -
^ сценар иям w o r k e r
^ для вычисления.

Браузер

Вот р е зу л ь т а т , который мы
х о т и м получит ь п у т е м вы ­
числений. Ъраузерному коду
пот ребует ся разбить работу
по вычислению данного изобра­
жения на несколько небольших
задач, выполнением которых Наши w o r k e r г о ­
зай м ут ся веб-сценарии worker. т овы п р и с т у п и т ь
к вы числениям!

дальш е ► 531
как производит ь вы числения с пом ощ ью w orker

Далее браузерный код начинает раздавать раз­


ные части изображения каждому из веб-сценариев
worker для вычисления:

Б раузер р а зд а е т част и изображения для в ы ­


числения каждым из веб -сц ен а ри ев worker.

Каждый worker работает над своей частью изображения независимо


от других. Как только worker завершает выполнение своей задачи, он упа­
ковывает результат и отсылает его обратно.

R O D Fractal txplorer
[ *I ►j {+ http ,iIionhoM,'-"Beln/MlMLV/FMtUl/f'jcUi 1

Закончив р а б о т у , веб -сц ен а ри и w o r k e r


о т с ы л а ю т об рат но част и изображе­
н и я , кот о ры е они вы ч исляли .

532 глава 10
применяем ja v a s c rip t на деле

По мере того как части изображения поступают обратно от веб-сценариев worker, они
собираются в единое изображение в браузере. И если еще остаются части, вычисление
которых необходимо произвести, эти новые задачи поручаются веб-сценариям worker, ко­
торые не заняты работой.

Все ч аст и изображения, ген е р и р у е


м ы е в е б -сц е н а р и я м и w o r k e r , соби­
р а ю т с я в ит ого во е изображение.

Когда будет вычислена последняя часть изображения, его сборка завершится и веб­
сценарии worker будут бездельничать, пока пользователь не щелкнет кнопкой мыши для
увеличения изображения, после чего все начнется сначала...

[«1►1f+ й] Сек- 1РЭЧ'< Сборка изображения


заверш ена и в е б -
сценарии w o r k e r
м о гу т отдыхать
до т е х n o p , пока
снова не п о я ви т с я
работ а.

дальш е ► 533
как веб-сценарии w orker улучш аю т прилож ения

Что произойдет, если


я разделю работу на части и рас­
пределю и х между веб-сценариями
w orker? Я хочу сказать, что у меня
в компью тере останется все тот же про­
цессор, поэтом у как вычисления см огут
ускориться?

Их ускорение возможно двумя путями...


С н а чал а н р е д с та в ьте себе н р и л о ж е н и е , в к о т о р о м в ы п о л н я ­
ется масса в ы ч и с л е н и й и к о т о р о е д о л ж н о б ы ть о т з ы в ч и в ы м
н о о т н о ш е н и ю к п о л ь з о в а те л ю . Е сл и ваш е н р и л о ж е н и е ста­
н е т о т н и м а т ь у й м у J a v a S c rip t-в р е м е н и , т о п о л ь з о в а те л и с то л ­
кн у тс я с м ед л енной р а б о то й ин терф ейса, ко т о р ы й , но и х
о щ у щ е н и я м , будет н о д т о р м а ж и в а т ь (о н я т ь -т а к и , из-за т о г о
J a v a S c rip t ф у н к ц и о н и р у е т в о д н о н о т о ч н о м р е ж и м е ). Д о б а в л е ­
н и е ве б -сц е н а р и е в w o rk er в т а к о е н р и л о ж е н и е сразу ж е н о л о -
ж и т е л ь н о с к а ж е т с я н а о щ у щ е н и я х п о л ь з о в а те л е й н р и р а б о те
с н и м . П о че м у? А н о то м у , ч т о J a v a S c rip t н о л у ч и т в о з м о ж н о с т ь
р е а ги р о в а т ь н а в з а и м о д е й с т в и е п о л ь з о в а те л е й в п р о м е ж у т ­
к а х м е ж д у п о л у ч е н и е м р е зул ьта то в о т ве б -сц е н а р и е в w ork er,
ч е го о н н е с м о ж е т делать, е сли все будет в ы ч и с л я т ь с я в глав­
н о м н о т о к е . Т а к и м о б р а зо м , и н т е р ф е й с п о л ь з о в а те л я с та н е т
более о т з ы в ч и в ы м , — и п о л ь з о в а те л и будут ощущать , ч т о ваш е
н р и л о ж е н и е р а б о та е т б ы с тр е е (д а ж е е сли в н у т р и о н о н е бу­
д ет ф у н к ц и о н и р о в а т ь х о т ь ч у т ь -ч у ть б ы с т р е е ). Н е в е р ите ?
П о н р о б у й т е э то сделать и д а й те р е а л ь н ы м п о л ь з о в а те л я м но -
р а б о та ть с в а ш и м н р и л о ж е н и е м . А за те м с н р о с и т е , ч т о о н и
дум аю т.

В т о р о й н у т ь действительно более быстрый. П о ч т и все с о в р е м е н ­


н ы е н а с т о л ь н ы е к о м н ь ю т е р ы и м о б и л ь н ы е у с т р о й с т в а снаб ­
ж а ю т с я м н о г о я д е р н ы м и п р о ц е с с о р а м и (и л и д а ж е н е с к о л ь ­
к и м и п р о ц е с с о р а м и ). М н о го я д е р н о с т ь подр а зум е ва е т, ч т о
н р о ц е с с о р с м о ж е т на р а л л е л ь н о в ы н о л н я т ь м н о ж е с т в о задач.
П р и о д н о м н о т о к е у н р а в л е н и я J a v a S c rip t в б раузере н е задей­
ств уе т в а ш и д о п о л н и т е л ь н ы е я д р а и л и п р о ц е с с о р ы , о н и н р о -
с т а и в а ю т без дела. О д н а к о е сли в ы п р и м е н и т е A P I-и н т е р ф е й с
W eb W o rk e rs , т о в е б -с ц е н а р и и w o rk er с м о гу т в о с п о л ь з о в а ть с я
п реим ущ ествам и в ы п о л н е н и я на р а зн ы х ядрах, и в ы увид ите
р е а л ь н о е у с к о р е н и е с в о е го н р и л о ж е н и я , н о с к о л ь к у н а н е го
будет т р а т и т ь с я б о льш е п р о ц е с с о р н ы х р е с у р с о в . Е сли у вас
м н о г о я д е р н ы й к о м н ь ю т е р , н у ж н о л и ш ь н о д о ж д а ть , и в с к о р е
в ы у в и д и т е р а зн и ц у.

534 глава 10
применяем ja v a s c rip t на деле

А может л и у меня
быть столько веб­
сценариев w o rke r, сколько
я пожелаю ?
О

В теории — да, но не на практике.


В е б -с ц е н а р и и w o rk er не п р е д н а з н а ч е н ы для и с п о л ь ­
з о в а н и я в б о л ьш о м к о л и ч е с т в е . Н е с м о т р я н а т о ч т о
с о зд а н и е w o rk er в ы гл я д и т н р о с т ы м в ко д е , о н н о т р е -
бует д о п о л н и т е л ь н о й п а м я т и и н о т о к а в о п е р а ц и ­
о н н о й си сте м е , ч т о м о ж е т д о р о го о б о й т и с ь в нл а не
в р е м е н и за п уска и р е сур со в . Т а к и м о б р а зо м , о б ы ч н о
у вас будет в о з н и к а т ь ж е л а н и е созд ать о гр а н и ч е н н о е
к о л и ч е с т в о ве б -сц е н а р и е в w o rk er , к о т о р ы е в ы ста н е ­
те п о в т о р н о и с п о л ь зо в а ть н о н р о ш е с т в и и в р е м е н и .

В о зь м и те на ш п р и м е р с м н о ж е с т в о м М а н д е л ь б р о та :
в т е о р и и в ы м о гл и б ы н а з н а ч и т ь w ork er , к о т о р ы й
стал бы за н и м а ть с я в ы ч и с л е н и е м к а ж д о го о д и н о ч н о ­
го п и кс е л а , ч т о , в е р о я т н о , б ы л о б ы н а м н о го н р о щ е с
т о ч к и з р е н и я р а з р а б о т к и ко д а . О д н а к о , у ч и т ы в а я то ,
ч т о в е б -с ц е н а р и и w o rk er я в л я ю т с я « тя ж е л о в е с н ы м и »
с р е д с тв а м и , м ы н и к о гд а б ы не в ы б р а л и т а к о й н о д х о д
п р и р а зр а б о тке н а ш е го н р и л о ж е н и я . В м е с то э т о го
м ы и с п о л ь зу е м г о р с т к у ве б -сц е н а р и е в w o rk er и с т р у к ­
т у р и р у е м в ы ч и с л е н и я т а к и м о б р а зо м , ч т о б ы о н и за­
д е й с тв о в а л и и х п р е и м у щ е с тв а .

Д а в а й те н е м н о го у гл у б и м ся в р а з р а б о т к у F ra c ta l
E x p lo re r, а за те м в е р н е м с я и н о э к с н е р и м е н т и р у е м
с к о л и ч е с т в о м ве б -сц е н а р и е в w ork er , ч т о б ы р а зо ­
б р а тьс я , к а к э т о т н о ка з а те л ь в л и я е т н а у р о в е н ь п р о ­
изводительности.

дальш е ► 535
разработ ка кода как упражнение для ума

Ш ТУРМ
У вас, несомненно, уже имеется масса знаний о том, как создавать приложения с применени­
ем API-интерфейса Web Workers, как генерировать и использовать веб-сценарии w o r k e r . Вы
также немного знаете о том, как решать проблемы с объемными вычислениями путем разбив­
ки их на небольшие задачи, которые могут быть выполнены веб-сценариями w o r k e r , и даже
чуть-чуть в курсе того, как вычисляются множества Мандельброта. Попробуйте соединить
все это воедино и задумайтесь над тем, как бы вы переписали приведенный ниже псевдо­
код, чтобы он задействовал веб-сценарии w o r k e r . Сначала можете предположить, что у вас
будет так много веб-сценариев w o r k e r , как вам потребуется (например, по одному w o r k e r на
каждую одиночную строку), а затем введите ограничение на количество w o r k e r (число веб­
сценариев w o r k e r меньше, чем количество строк):

for (i = 0; i < numberOfRows; i++) {

var taskForRow = createTaskForRow(i);

var row = computeRow(taskForRow);

drawRow(r

}
сделать для того, чтобы добавить
сюда веб-сценарии worker?

Свои заметки напишите здесь:

536 глава 10
применяем ja v a s c rip t на деле

Займемся созданием приложения Fractal Explorer □ Создать HTML-страницу


к уцршр^ленито
□ Создать веб-сценарии worker
Вот что нам потребуется сделать: | ^ | Запустить веб-сценарии worker
□ Реализовать код worker
j | Обработать результаты
□ Создать HTML-страницу. □ Код, касающийся взаимо­
действия с пользователями
I I Ввести весь готовый к употреблению код (или загрузить
его на свой компьютер).
□ Создать веб-сценарии w o rk er и раздать им задачи для выполнения.

□ Запустить веб-сценарии w o rk er , чтобы они выполняли свои задачи.

□ РеаЛИЗОВаТЬ КО Д w ork er.

□ Обработать результаты веб-сценариев w o r k e r , когда


они закончат выполнять свои задачи.
□ Обработать события c lic k и re s ize в интерфейсе пользователя.

Создание HTML-разметки для приложения Fractal Explorer


С начал а н у ж н о с ф о р м и р о в а т ь H T M L -с т р а н и ц у для р а зм е щ е н и я н а ш е го н р и л о ж е н и я .
Н а м н о т р е б у е т с я созд ать ф айл f r a c t a l . h tm l и д о б а в и т ь туда н р и в е д е н н у ю н и ж е разм етку.

^ ^ К а к обычноj В о т весь гот овы й к у п о т р е б л е н и ю


< ! d o c t y p e h tm l> кодj куда ц е ли к о м входит числовой код ,
стандартный
Chtml la n g = " en " > H T M L S -ф ай л. а также код для обработки г р а ф и к и .
<head> \

< title > F r a c ta l E x p lo r er < /title >


А. в о т т у т б удет J a v a S c r ip t код,
<meta c h a r s e t = " u t f - 8 ">
I ко т ор ы й мы собираемся н а п и с а т ь ...
< l i n k r e l = " s t y l e s h e e t " h r e f = " f r a c t a l . c s s "> / X" '
< s c r ip t sr c= " m a n d ellib . j s " x / s c r i p t > U /
^ л и вам интересно, где будет р а з -
м ещ ат ься код worker, то п о м н и т е , что
< s c r i p t s r c = " m a n d e l. j s " > < / s c r i p t > мы не ст анем указывать п р я м ую ссылку
< /h e a d > на J a vaS crip t-ф айл w o rker, а будем ссылаться
<body> Иа данный ф а й л , когда создадим worker в коде.
C canvas i d = " f r a c t a l " w id th = " 8 0 0 " h e i g h t = " 6 0 0 " X / c a n v a s > ' досм от рит е-ка!
ЧЧ Наш друг <canvas>
< /b o d y >
j вернулся!
< /h tm l>
<body> в к л ю ч а е т э л е м е н т <canvas>. Мы задали для него исходный р а з м е р
/\а н н ы й код б удет SOO х (ooo п и к с е ло вj однако позже м ы за й м е-------м с я ----------------
и зм е н е н и е м его р а з м е р а
р а з м е щ а т ь с я в ф ай ле с п о м о щ ь ю J ava Script. 8 конце концов , н а м необходимо т а к о е большое
fractal.htm l. множ ест во М а н д е л ь б р о т а , какое м ы т о л ь к о смож ем п о л у ч и т ь !

дальше ► 537
гот овы й к упот реблению код для ф ракт альны х изображений

Напоминание: вы м ож ет е ска ч ат ь весь код


У"*ojpoBo X ^oTDj=»0g^0HUI<> по адресу W t t p : //w ic k e d ly s m a r t.c o m / h F h tm lS

Должны признаться, что планировали отвести целую главу чудесам вычислений


множества Мандельброта... Мы собирались детально вам их объяснить, в том числе
рассказать историю Бенуа Мандельброта, поведать о том, как он открыл множество,
о его удивительных свойствах, пиксельных оптимизациях, цветовых картах и т. д., но
после звонка от нашего редактора... Ну вы сами понимаете, какой это был ЗВОНОК.
Мы немного запаздывали с работой над данной книгой, поэтому приносим свои из­
винения, однако все же дадим вам готовый к употреблению код для осуществления
низкоуровневых вычислений графики, касающейся множества Мандельброта. Однако
есть и положительный момент: мы сможем сосредоточиться на использовании API-
интерфейса Web Workers, не тратя время на математику и графику.
Сначала взглянем на код, используемый для управления задачами и рисования строк
фрактальных изображений. Введите данный код и сохраните его в файле m a n d e i i i b . j s.
var canvas;
О б р а т и т е в н и м а н и е , чт о здесь п р и ­
var ctx;
с у т с т в у ю т наши canvas и c o n te x t .

v a r i_max = 1 . 5 ;
v a r i_ m in = - 1 . 5 ;
Глобальные п е р е м е н н ы е , и с п о ль зуе м ы е
v a r r_min = - 2 . 5 ; для вычисления множ ест ва М а н д е л ь ­
v a r r max = 1 . 5 ; бр от а и его отображения.

v a r m a x _ i t e r = 102 4;
v a r e s c a p e = 1025;
var p a l e t t e = [];
Д анн ая функция упаковывает все
f u n c t i o n c r e a t e T a s k (row) { данные, необходимые веб-сценарию
var ta sk = {
w o rk e r для вычисления с т р о -
ки пикселов, в объект. Позже вы
row: row,
цвидите, как мы будем переда
w id th : r o w D a t a .w id t h , ва т ь э т о т объект веб-сценарию
g en era tio n : g en er a tio n , w o r k e r для использования.
r_m in: r_m in ,
r_m ax: r_m ax,
i : i_max + (i_ m in - i_ m a x ) row / c a n v a s . h e i g h t ,
m a x _ ite r: m a x _ ite r ,
escape: escape
}; Д а н н ы й код б удет
return task ; р а з м е щ а т ь с я в ф а й ле
mandelhb.js.

538 глава 10
применяем javascript на деле

w ( Создать HTML-страницу
"J"*ojpoBo X I j l l o 0 H U I °
| | J^otuoBoкупртре^ленито
□ Создать веб-сценарии worker
(п р о д о л ж е н и е ) □ Запустить веб-сценарии worker
□ Реализовать код worker
I | Обработать результаты
□ Код, касающийся взаимо­
действия с пользователями
function m a k ePalette() {
function wrap(x) {
x = ( (x + 256) & Oxlff) - 256; cm>o чисел в массив цвет ов R.QB. Мы 6ц -
дем использоват ь данный массив v a l e t t l
if (x < 0) x = -x;
return x;

for (i = 0; i < this .max_iter


p alette.p u s h ([wrap(7*1 wrap(5*i), w r a p (11*i)]);

функция d r a w R o w при н и м ает р е зу л ь


т а т ь i о т w o rk e r и р и с у е т с о о т в е т ­
ст вую щ ие пикселы в canvas.
function drawRow(workerResults) {
var values = workerResults.values;
Д ля эт о го она использует
var pixelData = rowData.data;
перем ен н ую rowData;
for (var i = 0; i < rowData.width; i++) { row D a ta — эт о одност роч­
var red = i * 4; ный объект Im ageD ata,
var green = i * 4 + 1; содержащий фактические
пикселы для с о о т в е т с т в у ­
var blue = i * 4 + 2;
ющей строки canvas.
var alpha = i * 4 + 3;
pixelData[alpha] = 255; // set alpha to opague
if (values[i] < 0) {
pixelData[red] = pixelData[green] = pixelData[blue] 0;
} else {
var color = this.palette[values[i]] Вот где мы используем
pixelData[red] = color[0]; p a le tte для преобразования
pixelData[green] = c o l o r [1]; р е з у л ь т а т а о т w o rk e r
(который п редст авляет
pixelData[blue] = color[2];
собой число) в и,вет.
)

}
c t x . put ImageData ( t h is . rowData f 0, w o rk e rR e su lts . row) ; Д д НН(?/ц код уже должен
} К а быть вам знаком; он п о -
Данный код будет 0т 2 5 запис 1 добен коду, который мы
р азм ещ ат ь ся в файле пикселы о ь е к т m age а применяли в главе 8 для
mandellib.js. 6 c w t e x t ^ м е н т я canvas! элем ен т ов video и canvas.

дальше ► 539
готовый к употреблению код для фрактальных изображений

У"*o jp o B o X

(п р о д о л ж е н и е )

setU p G rap hies задает глобальные п е р е ­


менныеj используемы е кодом для рисования
всей гра ф и к и , а также применяемые при
вычислении множества Мандельброта.
function setupGraphics() {

canvas = document.getElementByld("fractal
ctx = canvas.getContext("2d");
Вот где мы извлекаем canvas
и c o n te x t, а также задаем исход-
canvas.width = window.innerWidth; 1*Г~
ную ширину и вы сот у canvas.
canvas.height = window.innerHeight;

var width = ((i_max - i_min) * canvas.width / canvas.height);


var r_mid = (r_max + r_min) / 2;
^___ Переменные, используемые для в ы ­
r_min = r_mid - width/2; числения множества Мандельброта.
r_max = r_mid + width/2;

< ir \
rowData = c t x .createlmageData(canvas.width, 1); Здесь мы инициализиру­
ем п ерем ен н ую ro w D a ta
(и с п ол ь зуе м у ю для записи
makePalette();
пикселов в canvas).

А здесь мы инициализируем п а л и т р у
цв ет о вj к о т о р у ю используем для
рисования множества как ф р а к т а л ь ­
ного изображения.

Данный код будет


ра зм ещ а т ься в файле
mandelhb.js.

540 глава 10
применяем javascript на деле

J o r tio B o к ynomj=>eg jieH u i°

(п р о д о л ж е н и е )

Данный готовый к употреблению код будет использоваться worker для


математических вычислений множества Мандельброта. Именно здесь
происходит вся магия чисел. Напечатайте и сохраните данный код
В ф а й л е workerlib.j s!
c o m p u te R o w вычисляет одну с т р оку
данных множества М андельброта. Этой
функции передается объект , в который
упакованы все значения, необходимые ей
function computeRow(task) { для вычисления данной строки.
var iter = 0;
var c_i = task.i; О б р а т и т е внимание, что Это масса
var max_iter = task.max_iter; в случае с каждой ст рокой вычислений,
var escape = task.escape * task.escape; отображения мы с оверш а - Хорошо!
ем два цикла — один для
task.values = [];
каждого пиксела в строке...
for (var i = 0; i < task.width; i++) {
var c_r = task.r_min + (task.r_max task.г min) i / task.width;
var z_r = 0, z_i = 0;

for (iter = 0; z_r*z_r + z_i*z_i < escape && iter < max_iter; iter++) {
// z -> zA2 + с
var tmp = z_r*z_r - z_i*z_i + c_r; ...и еще один цикл, чтобы от ы скат ь
z_i = 2 * z_r * z_i + c_i; с о о т ве т с т в ую щ е е значение для дан -
ного пиксела. 3 э т о м внут реннем
z_r = t m p ;
цикле и заключается вы числит ель­
} ная сложность, и именно п о э т о м у
if (iter max_iter) { код будет выполняться намного бы -
iter - 1; с т рее, если ваш к о м п ь ю т е р им еет
многоядерный процессор!
}
task.values.push(iter) Р е зу л ь т а т о м всех этих вычислений является
} значение, добавляемое в массив именованных
return task; значений, который помещ ает ся назад в объект
ta sk , чтобы w o rk e r смог от о сл а т ь р е з у л ь т а т
обратно основному коду.

V Ч ут ь позже мы пристальнее
Данный код будет взглянем на э т у часть.
р а зм ещ а т ь с я в файле
workerlib.js.

дальше ► 541
как управлять веб-сценариями worker и задачами

Создание веб-сценариев worker и раздача им задач...


Разобравш ись с готовым к употреблению кодом, переклю чим впимапие
па паписапие кода, которы й будет геперировать и раздавать задачи веб-
сцепариям wo г ке г .

Мы создадим массив веб-сценариев worker, которые первона­


чально ничем не будут заняты. А также изображение, для кото­
рого ничего не будет ВЫЧИСЛЯТЬСЯ (nextRow = о). n extR ow = о

Мы будем совершать итерацию по массиву и генерировать объект


каждого Свободного worker.
task ДЛ Я

Worker

Продолжим совершать итерацию в поисках следующего незаня­


того worker, чтобы поручить ему задачу. Следующим по очереди nextRow = 1
у нас будет идти n e x t R o w = 1 . И так далее...

542 глава 10
применяем javascript на деле

O ' Создать HTML-страницу

Написание кода |

|
s/( |~отоо'3о к ynorjpebjienuK *

| Создать веб-сценарии worker


□ Запустить веб-сценарии worker
Теперь, когда мы зпаем, как будем создавать паши веб-сцепарии worker
j | Реализовать код worker
и управлять ими, папиш ем соответствую щ ий код. Для этого пам потребу­ Q Обработать результаты
ется пачальпая фупкция, поэтом у давайте создадим в mandel. js фупкцию □ Код, касающийся взаимо­
действия с пользователями
init, — мы также предусмотрим там м погое другое для обесп еч еп и я фупк-
циопировапия пашего прилож епия (паприм ер, позаботим ся об ипициали-
Почему 2? Так с л у ­
зации графики). Сначала определим п ерем ен н ую , которая
чилось, что у нас
будет содержать нужное нам количество
имеет ся к о м п ью т е р
s веб-сценариев worker. Мы используем с 2 я драм и} п о э т о ­
/ число S, и вы можете свободно поэкспери
м у т акое количество
1 о п т и р о в а т ь с э т и м пока за т ел ем , когОа
хорошо с о ч е т а е т ­
ваше приложение заработ ает . ся с возможностями
var numberOfWorkers = Пустой массив для размещения нашего ко м пью т ера.
var workers = []; наших w o rk e r Но даже если вы не
будет е ра сп о л а га т ь
Зададим обработчик onload, который т аким количеством
window.onload = init; будет вызывать функцию init, когда ядер, число 2 с т а н е т
страница полност ью загрузит ся. подходящим п о к а ­
Данная функция определена в го т о вом коде з а т е л е м , кот орый
function init() { и обрабаты вает извлечение co n te x t э л е ­ следует испробовать
setupGraphics() м е н т а canvas, изменение р а зм ер о в canvas в п ер вую очередь.
в со от вет ст вии с р а зм ер а м и окна браузера
и прочие графические детали.
Теперь мы соверш аем ит ерацию
по определенному количеству worker...
for (var i = 0; i < numberOfWorkers; i++) {
...И создаем новый w o rk e r из "worker.js",
var worker = new Worker ("worker.js <г
который мы еще не написали.

w o r k e r .onmessage = function(event) {
З а т е м задаем для обработчика сообщений
каждого w o rk e r ф ун кцию , кот орая вы зы ­
processWork(event.target, event.data)
вает ф ункцию processW ork, и передаем ей
e v e n t.ta rg e t ( w o rk e r , кот орый только что
закончил выполнение задачи) и eve n t.d a ta
wo r k e r .idle true; (р е зу л ь т а т ы от данного worker).
Помните, что нам будет нужно цзнать
сценарии w o rk e r заням ,,, * у зн а т ь, какие ве б -
workers.push(worker)
Ад» L o z o нам

startWorkers() присваиваем
еще не поручили
сценариям w o rk e r никакой работы.
Д обавляем только что создан­
ный w o rk e r в массив workers.

И наконец, в к а ко й -т о м о м е н т нам пот ре б у е т ся за п у с т и т ь Данный код будет


эт и веб-сценарии worker. Мы п о м е с т и м со о т ве т с т в ую щ и й код разм ещ ат ься в файле
в ф ункцию s ta r tW o r k e r s , к о т о р у ю нам еще нужно написать. mandel.js.

дальше ► 543
запуск ваших worker для вычисления фрактальных изображений
Создать HTML-страницу
|у< |^| ^ощоВо кl j U o СНиК>
Запуск веб-сценариев worker [71Создать веб-сценарии worker
□ Запустить веб-сценарии worker

Итак, пам п еобходим о разобраться с еще песколькими делами: запустить □ Реализовать код worker
□ Обработать результаты
веб-сцепарии worker, паписать фупкцию, которая см ож ет обработать р е­
□ Код, касающийся взаимо-
зультаты, поступающ ие обратпо от веб-сцепариев worker, а также паписать деиствия с пользователями
код для worker. Н ачпем с паписапия кода для запуска веб-сцепариев worker:
Сначала идет n ex tR ow , которая отслеж ива­
Д обавляем еще две глобаль-
е т , на какой ст роке мы находимся, по м е р е т ого
как мы продвигаемся по вычисляемому изображению.
и“ Каждый раз, когда пользоват ель увеличивает изображение м н о -
var nextRow = 0; жества М андельброта, мы запускаем вычисление нового и зоора-
~ укения. Переменная gen eratio n отслеж ивает, сколько раз мы эт о
var generation =
сделали. Ъолее подробно об э т о м поговорим позже.

function startWorkers() функция sta r tW o r k e r s будет за п ус к а т ь веб-сценарии


w orker, а также п е р езап уска т ь их, если пользоват ель
generation++; увеличит изображение. Таким образом, при каждом з а ­
nextRow = 0; пуске веб-сценариев w o rk e r мы будем сбрасывать значение
nextR ow до нуля и увеличиват ь значение generation.

for (var i = 0; i < w o r k e r s .length; i++) { обе эти п е р е м е н ­


К ак используют ся
var worker = workers [i], н о вам с т а н ет яснее ч ут ь позже...

Теперь мы соверш аем цикл по всем веб ­


if (worker.idle) { сценариям w o r k e r в массиве workers...
* „и проверяем, не сидит ли без
var task = createTask(nextRow); дела определенный worker.

Если выясняется, что w o rk e r ничем не занят,


worker.idle = false; мы ген ер и р уем объект task, чтобы поручит ь
worker.postMessage(task), е м у задачу. Данная задача будет з а к л ю ч а т ь ­
ся в вычислении строки множества М андель­
брота. функция createTask определена в
mandellib.js и возвращ ает объект task со в с е ­
nextRow++; ми данными, кот оры е необходимы w o rk e r для
вычисления с о о т ве т с т в ую щ е й строки.

Теперь мы подошли к т о м у , чтобы дат ь w o rk e r к о е - к а ­


кую р а б о т у , п о э т о м у задаем для свойства idle значение
false (эт о п о др азум евает , что он будет занят делом).
А здесь мы даем указание w o r k e r начат ь р а б о ­
И наконец, мы у в е ­ т у , для чего от пра вля ем сообщение, содержа­
личиваем значение щее объект task, w o rk e r ведет прослушивание
nextR ow , чтобы с л е ­ на п р е д м е т поступления сообщений, п о э т о м у л - я х .а,™
дующий w o r k e r п р и ­ когда он получит данное сообщение, он начнет У'аТ - ,
с т уп и л к вычислению выполнение со о т ве т с т в ую щ е й задачи. разм ещ ат ься в файле
следующей строки. mandel.js.

544 глава 10
применяем javascript на деле

f y j f ' Создать HTML-страницу

Реализация кода worker |y f gfomoSo к


Создать веб-сценарии worker
Запустить веб-сценарии worker
Теперь, когда у пас есть код для запуска worker путем передачи каждому из | | Реализовать код worker
пих объекта task, займемся паписапием кода worker. Затем пам остапется | | Обработать результаты
лишь верпуться и обработать результаты от оп ределепп ого worker, как толь­ j | Код, касающийся взаимо­
действия с пользователями
ко оп закопчит вы числепие своей части фрактальпого изображ епия. Одпако
преж де, чем мы пачпем писать код для worker, давайте взгляпем па то, как оп
долж еп работать. ф worker берет этот объект task и передает
Веб-сценарию worker его функции, входящей в готовый код,
передается объект task дл Я вычисления соответствующей строки.

отправить ее обратно коду


А Результат отправляется обратно от основной страницы,
worker также с помощью postMessage.

Итак, приступим к реализации. Введите и сохрапите в файле w o r k e r .js код,


которы й приведеп далее.

определенную в данном библиотечном файле.


/ Всеj что делает w o rk e r, — эт о задает
обработчик onmessage. Ему нет нужды
. . / делат ь чт о-либо еще, поскольку ем у лишь
l m p o r tScn p t s ("workerlib.j s") ; У ’ j /•
т реб у е т ся ждать сообщений от mandel.js
,ч , — для начала работы!
onmessage = function (task) { г

:.data);
var workerResult = computeRow(task.data)
|Г Он извлекает содержимое в виде данных
postMessage(workerResult); ^ из task и передает его функции с о т р и te R o w ,
которая выполняет
— тяжелую р а б о т у по вы-
f числению множества Мандельброта

Р е зу л ь т а т вычислений, сохраненный в перем ен - Данный код будет


ной w orkerR esult, о т п р ав л я е м с я обратно о с - р а зм ещ а т ь с я в файле
новному J a v a S c r ip t-коду с помощ ью postMessage. worker.js.

дальше ► 545
подробности об объекте task для вычисления фракталов

Короткий п и т-сто п ...


Мы с вами рассм отрели массу кода иа предыдущих стра-
пицах. Давайте сделаем короткий пит-стоп, чтобы «до­
заправить» паши баки и желудки.

Вам паверпяка захочется загляпуть украдкой «за кули­


сы» и узпать, па что п охож и task и worker Re suit веб-
сцепария worker (опи очепь п охож и друг па друга, в чем
вы убедитесь далее). Итак, бер и те бутылку лю бим ой
мипералки и давайте взгляпем па пих, пока вы будете
отдыхать...

ta sk п о д у в е л и ч и т е л ь н ы м с ш е к л ^ м

Итак, ранее ВЫ видели ВЫЗОВ createTask И postMessage, ДЛЯ КОТОрЫХ ИСПОЛЬЗуеТСЯ task:

var task = createTask(nextRow);


worker.postMessage(task);

При этом вам, возможно, интересно, на что похож task. Что ж, это объект, состоящий
из свойств и значений:
О пределяет с т р о к у , для кот орой
мы ген ер и р уем значения пикселов.
task = {
row: 1,
О предел яет ширину строки.
task содержит все width: 102 4,
значения, необходимые — О п редел яет , сколько раз мы
generation: 1,
веб-сценарию w o r k e r прибегали к увеличению...
r_ min: 2.074,
для выполнения его
вычислении. r_max: -3.074, О п редел яю т вычисляемую нами об ­
i: -0.252336,
ласт ь множества Мандельброта.

max_iter: 102 4,/ Г- К о н т р о л и р у ю т точность вычислений.


escape: 1025 J
};

546 глава 10
применяем javascript на деле

w o r k e ^ e ^ u lt л ° д у в е л и ч и т е л ь н ы м с ш е к л ° м
/> А как насчет результатов (workerResult), которые мы получаем, когда worker заканчивает
вычисление строки?
var workerResult = computeRow(task.data);

postMessage(workerResult);

На ЧТО ПОХОЖ о б ъ е к т workerResult? Он ОЧвНЬ СХОЖ С task:

workerResult = {
Здесь все т о же са м о е , что и в task.
row: 1,
И эт о здорово, поскольку когда мы
width: 102 4, получим workerResult от w o r k e r ,
w o rk e r прин им ает п е р е ­
данный ем у объект ta s k , generation: 1, мы будем зн а т ь все о task.
а з а т е м добавляет в него r_min: 2.074,
свойство values, содержащее r_max: -3.074,
А э т о ч т о - т о новень­
данные, необходимые для р и ­ кое. Здесь п р е д с т а в л е ­
i: -0.252336,
сования строки в canvas. ны значения каждого из
max_iter: 102 4, пикселов, которые нам
escape: 1025, все еще нужно п р е о б -
values: [3, 9, 56, - 1 , 22 ] ра зов ат ь в цвета (что
делается в drawRow).

Пора снова в путь...


Благодарим, что вы уделили п ек отор ое время и взгля-
пули вместе с пами па task и workerResult. Сделайте
п оследпий больш ой глоток своей мипералки — мы
спова отправляемся в путь!

дальше ► 547
обработка результатов работы worker

fy ] Создать HTML-страницу

Возвращаемся к коду: как осущ ествляется B

Q
' I f l овдоВо к ynpiyppfijIfHulo

Создать веб-сценарии worker

обработка результатов работы worker [ y f ' Запустить веб-сценарии worker


Реализовать код worker

Вы уже видели, как веб-сцепарии worker геперирую т результаты. Теперь I~~| Обработать результаты
Код, касающийся взаимо-
взгляпем, что произойдет, когда мы получим их от worker. Как вы помпите, деиствия с пользователями
когда мы создавали паши веб-сцепарии worker, мы задали обработчик со­
общ еп ий с им епем processWork:
Наш обработчик сообщений вызыва­
var worker = new W o r k e r ("worker.js"); е т функцию processW ork, передавая
ей event.data от w o r k e r , а также
wo r k e r .опте ssage = function(event) { e v e n t.ta r g e t, представляющий собой
processWork(event.target, event.data); ссылку на w o rk e r, который прислал
} с о о т ве т с т в ую щ и е данные.
Когда worker отправит пам обратпо сообщ епи е со своими результатами, их обработкой займется фупк­
ция processWork. Как вы м ож ете видеть, ей передаю тся два параметра: target сообщ епия, представ­
ляющ ий со б о й ссылку па worker, которы й его отправил, и data сообщ епия (это объект task со зпаче-
пиями для строки изображ епи я). Таким образом , теперь паша работа будет заключаться в том, чтобы
паписать processWork (введите приведеппы й далее код в m a n d e l .j s):
Передаем р е з у л ь т а т ы d r a w R o w
для рисования пикселов в canvas.
function processWork(worker, workerResults)
drawRow (workerResults);
Наш w o rk e r оказывается полностью
свободным, п о э т о м у мы можем п о р у ­
reassignWorker(worker); чить ем у уже новую задачу. Для эт ого
напишем функцию reassignWorker.
Мы п о ч т и д о с т и г л и цели, так что давайте бы стро папиш ем фупкцию reassignWorker, раз уж мы о п ей
заговорили. Вот как опа работает: мы проверяем строку, которую вычисляем, используя глобальпую
перемеппую next Row, и если остаю тся ещ е строки для вычислепия (что мож по выяспить, взгляпув па
количество строк в пашем canvas), мы поручаем worker повое задапие. В противпом случае, если боль­
ше п е остапется работы , которую требуется сделать, мы п росто присвоим свойству worker с имепем
idle зпачепие true. Введите приведеппы й далее код тож е в m a n d e l .j s:
л *лм ш пгкег сл е д у ю щ у ю с т р о к у ,
М ы создаем ся пор учим» э т о м у w o r k e r с У ^
function reassignWorker(worker) которую необходимо ^ ^ ^ Г е м значение nextRow (чтобы
var row nextRow++;

Если строка превысит высоту canvas либо сравняется


if (row >= canvas.height) { с ней по положению, дело сделано! Мы заполнили весь
canvas результатами от веб-сценариев, использован­
worker.idle = true; ных для вычисления множества Мандельброта,
} else { canvas — это глобальная переменная, которая была задана,
когда мы вызвали setup Graphics в нашей функции init.
var task = createTask (row) ;
worker.idle = false; \ Z t Ha^ еСЛ1 Z HaC же 0С^ У ^ я строки для вычисления
worker.postMessage(task)
}

Данный код будет р азм ещ а т ь ся в файле mandel.js.

548 глава 10
применяем javascript на деле

ъпо
Психоделический тест-драйв SEJ
Ну хватит уже кода! Давайте проведем тест-драйв пашего
прилож епия. Загрузите файл fractal.html в браузере и
п осм отрите, как веб-сцепарии worker займутся работой.
В зависимости от «пачипки» вашего компьютера ско­
рость прилож епия Fractal Explorer долж па стать пем по­
го выше, чем была рапее.

Мы, собствеппо говоря, еще пе паписали пикакого кода


для обработки изм епепия разм еров окпа браузера или
щелчков с целью увеличепия фрактальпого изображ е-
пия. П оэтом у все, что вы см ож ете увидеть па даппы й
момепт, — это и зобр аж еп и е, к отор ое п риведепо справа.

Тем пе м епее пока все хорош о, да? *


Такие дела! Очень жаль, что мы не можем уве­
личивать изображение и что оно пока еще не
Обработка собы тия click заполняет все окно, но мы дойдем до этого...

Наши веб-сцепарии worker трудятся пад вы числепием мпож ества Мапдель- Создать HTML-страницу
брота и возвращ ают результаты, чтобы мы могли парисовать их в canvas. J"оП)оГС
оКIplonlpC&JICHUK»
Н о что произойдет, если вы щелкпете кпопкой мыши, чтобы увеличить Q Создать веб-сценарии worker

изображ епие? К счастью, поскольку мы используем веб-сцепарии worker Запустить веб-сценарии worker
\ у \ Реализовать код worker
для осущ ествления иптепсивпы х вы числепий в ф оповом реж им е, иптер-
Р Г Обработать результаты
ф ей с пользователя долж еп живо среагировать соответствую щ им образом
□ Код, касающийся взаимо­
па ваш щелчок. Тем пе м епее пам потребуется паписать пем пого кода для действия с пользователями

ф актической обработки собы тия click.

Первое действие, которое нам потребуется предпринять, — это добавить обработчик, чтобы позабо­
<D титься о событиях, инициируемых щелчками мыши (помните, что щелчки осуществляются в нашем
элементе canvas). Для этого мы просто добавим обработчик для свойства canvas с именем onclick:
Если пользоват ель щелкнет
canvas.onclick = function(event) {
на canvas, мы вызовем ф у н к ­
handleClick(event.clientX, e v ent.clientY) цию handleClick с использова­
}; нием координат х и у м е с т а ,
где был сделан щелчок.
Добавьте данный код ниже вызова setUpGraphics в функции init в m a n d e l .j s.

Остается лишь написать функцию handleClick. Прежде чем мы это сделаем, на секунду задумаемся
© вот над чем: когда пользователь щелкает на canvas, это означает, что он хочет увеличить соответ­
ствующую область (вы можете вернуться к однопоточной версии по адресу http://wickedlysmart.com/
hfhtml5/chapter10/singlethread/fractal.html, чтобы увидеть данное поведение). Таким образом, когда
пользователь щелкнет на canvas, нам нужно будет получить координаты области, которую он хочет
увеличить, а затем привлечь все веб-сценарии worker кработе по генерированию нового изображения.
Также не забывайте, что у нас уже имеется функция startWorkers для поручения новой работы любому
незанятому worker. Давайте испытаем ее...

дальше ► 549
тестирование и улучшения

Вызов kandleClick происходит Мы передаем координаты x, у м е с т а ,


когда пользоват ель щелкает где был сделан щелчок, то ест ь мы
на canvas, чтобы увеличить будем зн ат ь, в какой именно части
экрана щелкнул пользователь.
фр— 6ражу Данный код изменяет ра зм ер ы о б -
function handleClick (х, ^ ^ "\ ласти ф ракт альн ого изображения,
I к о т о р у ю мы вычисляем, используя
var width = r_max - r_min;
У координаты X, у в центре новой
var height = i_min ■ i max;
+ w id th * v / , , Ч области. Он также следит за т е м ,
var click_r = r_min c a n v a s .w id th ; \ чт о6ы у но$ой 0§ласт и было т акое
var click_i = i_max + height У / соот н ошение ш ирины и вы сот ы ,
c a n v a s .h e ig h t; ) ж е
как у сущ ест вую щ ей области.

var zoom = 8;
Задаем значения для глобальных п е р е м е н ­
ных, используемых для создания объектов task
r_min = click_r - width/zoom; для веб-сценариев worker, уровень увеличения
г_шах = click_r + width/zoom; определяет , насколько сильно мы увеличили
i_max = click_i - height/zoom; ф ракт альн ое изображение, что, в свою оче­
редь, определяет , какие значения множества
i_min = click_i + height/zoom;
Мандельброта будут вычисляться.

startWorkers(); Теперь мы готовы к п ерезапуску


веб-сценариев worker. Данный код будет
разм ещ ат ься в файле
m andel js.

Прекрасно! У нас появилась возмож­


ность увеличиват ь изображение, однако
нам все еще нужно изм енит ь ра зм ер ы
canvas, чтобы полност ью подогнать
его под разм ер ы окна браузера. *
Еще один тест-драйв
чу

П роверим , какой эф ф ект произведут впесеппы е пами в код


изм епепия. П ерезагрузите fractal .html в браузере и па
этот раз щелкпите где-пибудь в canvas. Сделав это, вы увиди­
те, как веб-сцепарии worker пачпут работать пад увеличеп-
пым представлением.

Теперь у вас долж па появиться возмож пость приступить к


исследованию ! П осле того как вы пемпого поиграете, впе-
сем ряд фипальпых и зм епепий, чтобы довести даппую реа­
лизацию до копца.

550 глава 10
применяем javascript на деле

Подгоняем canvas под размеры окна браузера [ y j f ' Создать HTML-страницу


|v f ^ |ог,)о!}о к i p i p e Hut°
[ у ] Создать веб-сценарии worker
Как уже отмечалось рапее, пам п еобходи м о, чтобы фрактальпое и зобра­ Запустить веб-сценарии worker

ж еп и е заполпяло окпо браузера, а это озпачает, что пам потребуется изм е­ O ' Реализовать код worker

Q T Обработать результаты
пить размеры canvas, если измепятся размеры окпа. К роме того, если мы
□ Код, касающийся взаимо­
изм епим размеры canvas, то пам также придется поручить веб-сцепариям действия с пользователями
worker повый пабор задач по перерисовке фрактальпого изображ епия,
чтобы опо заполпяло canvas с повыми размерами. Давайте папиш ем код
для подгопки размеров canvas под размеры окпа браузера, а также п ереза­
пустим веб-сцепарии worker, раз уж мы об этом заговорили.

Функция resizeToWindow следит за т е м ,


function resizeToWindow() {
чтобы ширина и высота canvas задавалась
canvas .width = window.innerWidth; в со от вет ст вии с новыми р а зм ер а м и окна.
canvas.height = window.innerHeight;
var width = ((i_max - i_min) * canvas.width / canvas.height);
var r_mid = (r_max + r_min) / 2; Она также обновляет значения, ко
r_min = r_mid - width/2; орые w o r k e r будет использоват ь ^
для осуществления своих вычислении,
r_max = r_mid + width/2;
взяв за основу новую ширину и высоту
rowData = c t x .createlmageData(canvas.width, 1) (мы заботимся о т о м , чтобы ф р а к ­
тальное изображение всегда совпадало
startWorkers () ; по р а зм е р а м с canvas и сохраняло с о ­
отношение ширины и высоты окна).
S
И снова п ерезапускаем
Есть одна адм инист рат ивная дет ал ь, использующая г л о ­
веб-сценарии worker.
бальную перем ен н ую , о кот орой мы вам еще не говорили:
rowData. row D ata - эт о объект \m ageD ata, который мы
используем для рисования пикселов в ст роке canvas. Таким
образом, при изменении р а зм е р о в canvas нам по т ре б у е т с я
вновь создат ь объ ект ro w D a ta , чтобы он имел значение ш и ­
рины, совпадающее с новым значением ширины canvas. В згл я ­
ните на функцию d r a w R o w в mandellib.js, чтобы у ви д ет ь,
как ro w D ata использует ся для рисования пикселов в canvas.

Теперь пам пужпо устаповить resizeToWindow в качестве обработчика


для собы тия, инициируем ого при изм епеп и и разм еров окпа браузера:

w in d o w .o n r e s iz e = f u n c t i o n () {

r e s iz e T o W in d o w ( ) ;

}; Данный код будет


разм ещ ат ься в файле
Даппы й код пужпо поместить в фупкцию init в mandel. js, прямо под
вызовом setUpGraphics. mandel.js.

дальше ► 551
управление фрактальными поколениями

Дотошный ппгф mrftajL программист


Осталась еще одпа вещь, без к оторой код попросту пе будет корректпым. Давайте вместе поразмыш ­
ляем пад следующ ей ситуацией: у вас им еется группа веб-сцепариев worker, которы е успеш по трудятся
пад вы числепием своих строк, и вдруг у пользователя возпикает н еобходим ость щелкпуть па изображ е-
пии, чтобы увеличить его. Н ичего хорош его в этом пет, поскольку веб-сцепарии worker уже работаю т
пад вы числепием своих строк, а теперь пользователю понадобилось измепить и зображ епи е целиком,
что делает всю их работу беспол езпой . Еще хуже то, что веб-сцепарии worker пе будут иметь попятия о
том, что пользователь произвел щелчок, и в лю бом случае стапут отправлять свои результаты обратпо.
А еще хуже то, что код в осп овп ой страпице будет охотп о припимать и отображать даппы е строки! Это
пе копец света, по мы столкпемся с точпо такой ж е п роблем ой, если пользователь изм епит размеры
° КПа" Зам етка для редактора: извиняемся за небольшую напыщенность здесь но после ^
столь большого количества пройденных ст раниц эта новость может додить вас...

На даппы й м омепт вы, вероятпо, пи разу бы пе обратили па это впимапия, поскольку у вас им еется пе
так мпого веб-сцепариев worker, при этом опи очепь бы стро вычисляют одпи и те ж е строки для пового
и зображ епия, перезаписы вая предыдущ ие, пекорректпы е строки. Тем пе м епее возпикает ощущ епие,
что здесь что-то пе так. К роме того, впести исправлепия пастолько легко, что мы п росто обязапы это
сделать.

Следует призпаться: мы зпали, что так будет, и вы, возм ож по, помпите малепькую перемеппую
generation, с к оторой мы сталкивались рапее. П ри каждом перезапуске паших веб-сцепариев worker
мы увеличиваем зпачепие generation. Также п е забывайте об объекте worker Results, которы й посту­
пает обратпо от worker: у каждого результата имеется собствеп п ое поколепие в качестве свойства. Та­
ким образом , мы мож ем использовать перемеппую generation для того, чтобы узпать, получили мы
результат, имею щ ий отпош епие к текущей или ж е к предыдущ ей визуализации.

В песем п еобходим ы е исправлепия в код, а затем смож ем поговорить о том, как опи работают. Отредак­
тируйте фупкцию processWork в m a n d e l .j s и добавьте туда эти две строки:

function processWork (worker, workerResults) { ^ Mb/ проверяем р е з у л ь т а т


if (workerResults . generation == generation) { 0m Wo,r^ lrJ чтобы выяс­
н и т ь , с о о т в е т с т в у е т ли
drawRow (workerResults) ;
его поколение т екущ ем у.
}
тт , , , х Если с о о т в е т с т в у е т , то мы р и -
reassignWorker (worker) ; и п
су е м с т р о к у , в прот ивном случае

’ В л„А м * м« вручаем }°А Ж Н °


w o r k e r уже новую ра б о т у ' ст ар ой , и шя проигн орируем ее.

Таким образом , мы удостоверяемся в том, что текущее поколепие, пад которы м мы работаем , соответ­
ствует поколепию результата, возвращ еппого веб-сцепарием worker. Если так опо и есть —отличпо, тог­
да пам потребуется парисовать строку. Если ж е соответствия пет, строка, скорее всего, является старой,
поэтом у мы п росто будем ее игнорировать (очепь жаль, что паш worker впустую потратил па п ее свое
время, одпако мы пе хотим рисовать старую строку из предыдущ его и зображ епи я па экрапе).

Итак, вот и все, па этот раз по-пастоящему. П ора убедиться в том, что вы впесли все приведеппы е выше
изм епепия, и подготовиться к...

552 глава 10
применяем javascript на деле

Создать HTML-страницу

Время финального mecm-gpauBa! I


Q
^ JoJUpBo кIpPiDpCoJIfHUIo
Создать веб-сценарии worker
Запустить веб-сценарии worker
Вот и всё! Ваш код долж ен быть полностью готов к работе. Загрузите файл Реализовать код worker
fractal .html в браузере и посм отрите, как веб-сценарии worker займутся де­ Я Г Обработать результаты
лом. Данная версия долж на работать бы стрее и быть более отзывчивой, чем Код, касающийся взаимо­
действия с пользователями
оригинальная однопоточная версия (если в вашем компью тере установ­
лен п роц ессор с более чем одним ядром, то она
будет работать намного бы стрее).
Поразвлекайтесь... попробуйте увеличить и зо­
браж ения... исследуйте их. Д айте нам знать, если
найдете во м нож естве М андельброта какую-ни-
будь ранее неизвестную «территорию » (отправь­
те свои скриншоты на #hfhtml5 ч ер ез Твиттер, если
пож елаете).

Щ е лка й т е,
увеличивайт е,

дальше ► 553
г
В ЛАБОРАТОРИИ
Е сл и вы п и ш е т е в ы с о к о п р о и з в о д и т е л ь н ы й
ко д , то з а х о т и т е п р о в е р и т ь , к а к к о л и ч е с т в о
в е б -с ц е н а р и е в worker п о в л и я е т на в р е м я
в ы п о л н е н и я р а б о ты в а ш и м п р и л о ж е н и е м .

Д л я э то го вы м о ж е т е в о с п о л ь з о в а т ь с я м о ­
н и т о р о м за д а ч ка к в о п е р а ц и о н н о й с и с т е ­
ме O S X , т а к и в W in d o w s . Е с л и в е р н у т ь с я
к наш ей о р и ги н а л ь н о й о д н о по то чн о й версии О О О
(п о а д р е с у h ttp ://w ic k e d ly s m a rt.c o m /h fh tm l5 /
c h a p te r l O /s in g le th r e a d /fra c ta l.h tm l), то к а р т и ­
ну и с п о л ь з о в а н и я я д е р пр и в ы п о л н е н и и п р и ­
л о ж е н и я на н а ш е м к о м п ь ю т е р е вы м о ж е те
у в и д е т ь на д и а гр а м м е , п р и в е д е н н о й с п р а в а .

Н а ш к о м п ь ю т е р и м е е т в о с е м ь я д е р , ко т о р ы е v
б у д у т д о с т у п н ы п р и л о ж е н и ю F ra c ta l E x p lo re r 3 нашем к о м п ь ю т е р е — восемь
с в е б -с ц е н а р и я м и worker, и мы з а д а е м к о ­ ядер. Одно из них использует ся по
ли чество worker, со о тв е тств ую щ е е этом у м а к с и м у м у и не может вычислять
ч и с л у я д е р , у к а з а в numberOfWorkers = 8. бы ст рее, чем позволяет его рабочая
К а к вы м о ж е т е в и д е ть на м о н и т о р е а к т и в н о ­ част от а. Остальные семь ядер н и ­
с ти , все 8 я д е р и с п о л ь з у ю т с я по м а к с и м у м у . чего не д е л а ю т , чтобы помочь ему.

К а к вы д у м а е т е , ч т о будет, е с л и м ы з а д а д и м Теперь все наши в о ­


к о л и ч е с т в о в е б -с ц е н а р и е в worker, р а в н о е семь ядер загружены
2, 4, 16 ил и 3 2 ? И ли р а в н о е к а к о м у -т о п р о ­ работ ой, и вычисление
м еж уточном у значению ? ф ракт альн ого и зо ­
П о п р о б у й т е т а к с д е л а т ь на с в о е м к о м п ь ю ­
бражения о с у щ е с т ­
те р е и вы я сните , ка ки е зн а че н и я явл яю тся вляется НАМНОГО
н а и б о л е е п о д х о д я щ и м и д л я ва с. быстрее.

О О О

554 глава 10
применяем javascript на деле

ЗАСТО ЛБИ ТЕ С ЕБ Е УЧАСТО К!


Вы сделали это! Вы создали полностью функциональное приложение Fractal
Explorer, которое готово к исследованию областей множества Мандельбро­
та. Так чего же вы ждете — приступайте и найдите свой кусочек виртуаль­
ной Вселенной. А когда отыщете, запечатлейте и вставьте его сюда, а затем
присвойте своему новому участку название.

О О О Fractal Explorer
[' < [V | [ + 1Q http': //focal host j - Beth/HTML 5/fracta I/f racta l~.tr <5 | (O* GoogTe *)

ВСТАВЬТЕ СЮДА СВОЙ УЧАСТОК


ИЗ МНОЖЕСТВА МАНДЕЛЬБРОТА

А
дополнительная функциональность api-интерфейсэ web workers

Вам не кажется, что с л ед у ет знать


кое-что ещ е об A PI-и н т е р ф е й с е W eb
W orkers? Изучите с л е д у ю щ и е пару
страниц, чтобы узнать о б о всем , что мы
не рассказали в этой главе.

П р е р ы в а н и е В ы п о л н е н и я w o rk er

Вы создали веб-сценарии worker для вы полнения задачи, и после


того как она была выполнена, захотели избавиться от всех этих
worker (они отнимаю т ценную память браузера). Вы м ож ете п ре­
рвать вы полнение worker из кода своей осн овн ой страницы следу­
ющим образом:
w o r k e r .terminate() ;

Данная строка приведет к отм ене выполняющ егося сценария


worker, поэтом у используйте ее осторож н о. Прервав вы полнение
worker, вы не см ож ете повторно использовать его; вам придется
создать новый worker.

worker также м ож ет сам остановить свое вы полнение, вызвав


close () ; (изнутри worker).

• о ц ж а о ш и б о к w o rk er
v J

Ч то будет, если с worker случится какая-то ужасная ошибка? Как ее устранить?


И спользуйте обработчик one г г or для перехвата любых ош ибок, а также для
получения отладочной информации:

worker.onerror function(error) {
document.getElementByld("output") .innerHTML =

"There was an error in + er r o r .filename +

" at line number " + error.lineno +


": " + error.message;

556 глава 10
применяем javascript на деле

Цс31°Ль5«>Вание ддгг г}^0КГ^2а11Г°СоБ


Вы не см ож ете вставлять новые элементы <script> для вы полнения JSO N P-запросов из worker,
однако у вас будет возм ож ность использовать importScripts для соверш ения JSO NP-запросов сле­
дующим образом:
function makeServerRequest() {
importScripts("h t t p ://SomeServer.com?callback=handleRequest") ;

function handleRequest (response) { Помните JSONP ? Включите свою финкшю


postMessage (response); обратного вызова в URL-запрос, и она бидет
} вызываться с передачей JSON -результатов
makeServerRequest () ; параметре response.

IfciiojibSoBaHue ixo^ort^trij^tg Б worker

Вы могли упустить это из виду (мы бы стро прош ли мимо данного аспекта взглянув ня т

д Г “ И1а™ <,UO“ ' J=)> ТаК" М ° браЗОМ' ЧТОбЫ ° Н °™ Р “ п р ои зв ол ь н ую ™ ^ ™


var quotes - [ i hope life isn't a joke, because I don't get it.",

"There is a light at the end of every t unnel... just pray it's not a train!”,
"Do you believe in love at first sight or should I walk by again?"];
function postAQuote() {

var index = Math, floor (Math, r a n d o m () * quotes.length) ; 7 Помещаем эт и две строки


postMessage (quotes [index] ) ; j в функции? postAQuote...
}
„вызываем postA Q u ote для немедленной от правки
postAQuote () ;
^ ц и т а т ы , ал з а т е м заииьт
задаем интервал
и п т ^ у и /» для -----
отправки
setlnterval (postAQuote, 3000) ; ^ __ У дополнительных, ц и т а т , равный 3 секундам.

Ц одм астее^ье ^ W o rk er
Если вашему worker потребуется помощь в вы полнении его задачи, он сможет создать свои соб­
ственные веб-сценарии worker. Допустим, вы поручаете своему worker области изображ ения, ко­
торы е он долж ен вычислить, a worker при этом м ож ет решить, что если область превышает некий
разм ер, то работу по ее вы числению следует распределить между его собственны ми субсценария­
ми subworker.
worker генерирует subworker тем ж е путем, посредством которого код в вашей странице создает
worker: , . ....
var worker = new W o r k e r ("subworker.js );
П ом ните, что все subworker, как и обычные worker, являются довольно «тяжеловесными», они за­
нимают память и выполняются как отдельные потоки. П оэтом у будьте осторож ны с количеством
создаваемых subworker.

дальше ► 557
обзор аpi-интерфейса web workers

КЛЮЧЕВЫЕ
— МОМЕНТЫ

■ Без веб-сценариев worker JavaScript является од­ Вы можете выяснить, какой именно worker от­
нопоточным, то есть может выполнять только какое- правил сообщение, воспользовавшись свойством
то одно действие за раз. event.target.

■ Если вы взвалите на JavaScript-nporpaMMy слишком Сообщения копируются, а не совместно используют­


много работы, то на экране может появиться диало­ ся КОДОМ Вашей ОСНОВНОЙ СТраНИЦЫ И worker.
говое окно Slow Script (Медленный сценарий).
Вы можете использовать сразу несколько веб­
■ Веб-сценарии worker обрабатывают задачи в от­ сценариев worker для осуществления объемных
дельном потоке, благодаря чему ваш основной вычислений, которые могут быть разбиты на ряд
JavaScript-код сможет продолжать выполняться, небольших задач (например, при проведении вычис­
а интерфейс пользователя будет оставаться отзыв­ ления фрактальной визуализации или создании изо­
чивым. бражения методом трассировки лучей).

■ Код для веб-сценария worker располагается в от­ Каждый worker выполняется в своем собственном
дельном файле и обособлен от вашего основного потоке, поэтому ваш компьютер обладает много-
кода. ядерным процессором, веб-сценарии worker смогут
выполняться параллельно, что повышает скорость
■ У веб-сценариев worker нет доступа к любым функ­
вычислений.
циям в коде вашей страницы, а также к объектной
модели документа (DOM). Вы можете прервать выполнение worker, вызвав
worker .terminate () ИЗ КОДЭ СВОвЙ СТраНИЦЫ.
■ Код в вашей странице и веб-сценарий worker обща­
В результате выполнение сценария worker будет
ются посредством сообщений.
прекращено, worker также может сам остановить
■ Для отправки сообщения веб-сценарию worker ис­ свое выполнение, вызвав close о .
пользуйте postMessage.
Все worker располагают СВОЙСТВОМ onerror.
■ Вы можете отправлять строки и объекты веб­ Вы можете задать для него значение в виде функции
сценарию worker С ПОМОЩЬЮ postMessage. От- обработчика ошибок, которая будет вызываться в
правлять функции веб-сценарию worker нельзя. случае возникновении ошибки при выполнении сце­
нария worker.
■ Для приема сообщений обратно от worker не­
обходимо задать для свойства worker с именем Для включения и использования JavaScript-
onmessage фуНКЦИЮ обработчика. библиотек в файле вашего worker используйте
importScripts.
■ Для получения сообщений веб-сценарием worker
от кода вашей страницы необходимо задать для его Вы также можете использовать importScripts
свойства onmessage фуНКЦИЮ обработчика. в сочетании с JSONP. Реализуйте функцию обратно­
го вызова, которая передается в URL-запросе, в фай­
■ Когда worker готов к отправке результата обратно,
ле worker.
он вызывает функцию postMessage и передает ей
данный результат в качестве аргумента. Несмотря на то что у веб-сценариев worker нет
доступа к объектной модели документа (DOM) и к
■ Результаты работы worker инкапсулируются в объ­
функциям в вашем основном коде, они могут исполь­
екте event и располагаются в свойстве data.
зовать XMLHttpReguest И localStorage.

558 глава 10
применяем javascript на деле

1 Л Щ ,5 - К Г °ссК °Г Д
Здорово! Вы добрались до конца главы 10. Откиньтесь на снин-
ку стула, расслабьтесь, а затем закрените изученны й материал,
немного но раб отав другим нолуш арием своего мозга и разгадав
кроссворд.

По горизонтали По вертикали
3. Аппаратная особенность процессора, дающая ему воз­ 1. ________________выполнения.
можность выполнять более одной задачи за раз. 2. Веб-сценарии worker могут использовать
6. Свойство, используемое для регистрации обработчика XMLHttpReguest И у НИХ ИМевТСЯ ДОСТуП К__________.
с целью приема сообщений. 4. Посредством НИХ о б щ а ю тс я manager, js И Ввб-
7. В нашем первом примере мы использовали эту игру. сценарии worker.
9. Вы можете передавать______________ веб-сценариям 5. Инструмент для импорта дополнительного кода
worker С ПОМОЩЬЮ postMessage. В worker.
11. У веб-сценариев worke г нет доступа к _____________ . 8. Что нужно ввести для того, чтобы прекратить выполне­
12. Наиболее широко известный фрактал. ние worker?
13. _______________ /веб-сценарий worker. 10. В случае с множеством Мандельброта используются
15. Человек, который написал оригинальную версию числа.
Fractal Explorer. 14. ЧТО НУЖНО ВВеСТИ ДЛЯ ТОГО, ЧТОбы СОЗДаТЬ Worker.
16. Красивая область виртуальной сельской местности
в множестве Мандельброта называется «____________
острова». owie он cv)VY)dog
-02 ЭИ 020Wie wvg V(?20>iY)H IQW (OHQVV

дальше ► 559
решение упражнения

(ТАНЬ 6рду>ер«м. Решение


UjniUijio время прлгрВорлгрься браузером,

оП,0ниВа1°ЩиМ JaVa^cTi]3!— К°Д.

window.onload = f u n c t i o n () {
var worker = new W o r k e r ("wor k e r .j s " ); Данный код о т п р а в и т пя т ь сообщений
worker.onmessage = f u n c t i o n (e v e n t ) { со строкой "ping" § сб-сценарию w o rk e r, к о ­
a l e r t ("Worker says " + event.data); торый в о т в е т от ош л е т пят ь сообщений
} со строкой "pong", п о э т о м у на экране п о ­
for (var i = 0; i < 5; i++) { явится пя т ь диалоговых, окон a le r t с т е к ­
wo r k e r . p o s t M e s s a g e ("pin g " ); с т о м "W ork er says pong".
}
}
window.onload = f u n c t i o n () { Данный код о т п р а в и т пя т ь сообщений
var worker = new W o r k e r ("wor k e r .j s " );
со строкой "pong" веб-сценарию wor,ken
worker.ommessage = function(event) {
который пр о и гн о р и р ует их, поскольку они
a l e r t ("Worker says " + event.data);
не вклю ч а ю т ст р о к у "pj^g"- Никакого вы ­
} вода генерироват ься не будет.
for(var i = 5; i > 0; i— ) {
wo r k e r . p o s t M e s s a g e (" p ong");

window.onload = function() { Данный код о т п р а в и т сообщение со с т р о ­


var worker = new W o r k e r (" w o rker.j s " ); кой "ping"]'а каждый р а з назад
worker.onmessage = fu n c t i o n (e v e n t ) { б удет п о с т у п а т ь сообщение со строкой
a l e r t ("Worker says " + event.data) "pong"t он с т а н е т о т п р а в л я т ь новое такое
wo r k e r . p o s t M e s s a g e (" p ing"); же сообщение, п о э т о м у в р е з у л ь т а т е мы
} будем Iн аблюдать бесконечный цикл из появ­
wor k e r . p o s t M e s s a g e ("ping"); ляющихся диалоговых окон a fert с т е к с т о м
"Worker says p o n g u\.......................................................
window.onload = function() {
var worker = new W o r k e r ("wor k e r .j s " );
worker.onmessage = function(event) {
a l e r t ("Worker says " + event.data); Данный код б удет о т п р а в л я т ь сообщение
} со ст рокой "pi^g" каждую секунду, п о э т о ­
м у мы ст а н ем получ ат ь в о т в е т сообще­
setlnterval(pinger, 1000); ние со ст рокой "pong" всякий ра з, когда он
будет о т п р а в л я т ь "ping".
function p i n g e r () {
w o r k e r . p o s t M e s s a g e ("pin g " );

560 глава 10
применяем javascript на деле

|озьми в руку карандаш_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


Решение
Несмотря на то что обычно веб-сценарии worker получают рабочие задания
посредством сообщений, такой подход вовсе не обязателен. Взгляните на дан­
ный отличный и компактный способ сделать необходимую работу с помощью
веб-сценариев worker и HTML. Когда вы разберетесь в том, что делает данный
код, опишите это внизут

<! doctype html> quote.htm l


<html lang="en">
<head>
<title>Quote</title>
<meta charset="utf-8">
</head>
<body>
<p id="quote"></p>
<script>
var worker = new W o r k e r ("quote.js");
w o r k e r .оптеssage = function(event) {
document.getElementByld("quote").innerHTML = event.data;
}
</script>
</body>
< /h tm l> qwote.js

var quotes = ["I hope life isn't a joke, because I don't get it.",
"There is a light at the end of every tunnel....just pray it's not a train!",
"Do you believe in love at first sight or should I walk by again?"];
var index = Math.floor(Math.random() * quotes.length);

postMessage(quotes[index]);

Свое описание приведите здесь:

В НТМL у нас имеется скрипт , создающий w orker, выполнение кот орого зап ускает ­
ся незамедлит елт о. worker произвольно выбирает цит ат у из массива quotes и о т ­
правляет ее основному коду с помощью postMessage- O сновной код извлекает цит а­
т у из event.data и добавляет ее на страницу в элемент <р> с id в виде "quote".

дальше ► 561
решение упражнения

562 глава 10
применяем javascript на деле

Как было бы здорово, если бы


это уже был конец книги. Если бы
не было больше никаких ключевых
моментов, головоломок, JavaScript-
листингов или чего-то еще. Об этом
aa^w HO лишь мечтать...

Доздравляем!
1)ьх Д о Ш Л и Д о ХонДа.

Конечно же, еще есть приложение.


И выходные сведения.
А также адрес нашего сайта...
Так просто сбежать у вас не получится — мы серьезно!

дальше ► 563
П р и л ож ен и е. О ста в ш и еся т е м ы

+ Десять важных тем


(которые мы не рассмотрели)

Мы изучили множество различных тем, и вы почти закончили


читать эту книгу. Нам грустно с вами расставаться, но прежде, чем мы это
сделаем, поведаем еще кое о чем, чтобы подготовить вас к выходу в реальный
мир. Вообще-то изначально мы включили в книгу все, что читателям следует
знать о HTML5 (не рассмотренное в предыдущих главах), уменьшив размер
шрифта до 0,00004. Но такой мелкий текст невозможно было прочитать. По­
этому нам пришлось выбросить большую часть и оставить в приложении
только десять самых важных тем.
modernizr и audio

№ 1. Modernizr
Читая книгу, вы, вероятно, обратили внимание на то, что нри н е­
обходи м ости выяснить, ноддерж ивает ли браузер тот или и н ой
API-интерф ейс, оказывается, что едины й сн особ сделать это отсут­
ствует; фактически, ноддерж ка ночти лю бого API-интерф ейса детек­
тируется но-разному. Н анример, в случае API-интерф ейса G eolocation
мы ищ ем объект geolocation как свойство объекта navigator, в то
время как в API-и нтерф ей се Web Storage мы нроверяем , он ределен ли
localStorage в объекте window. Что касается API-интерф ейса V ideo,
то в дан ной ситуации мы нроверяем , есть ли у нас возмож ность соз­
дать элем ент video в объектной модели документа (DOM ) и т. д. На­
верняка существует сн особ но лучше?

M odernizr — это JavaScript-библиотека с открытым исходны м кодом, кото­


рая обеснечивает едины й ин тер ф ей с для детектирования того, что им енно ноддерж ивает конкретны й
браузер. M odernizr охватывает всевозмож ны е детали различны х снособов детектирования, включая
даж е ф акторинг в сложных ситуациях с устаревшими браузерами. Домаш няя страница M odernizr рас­
полагается но адресу h t t p : //w w w .m o d e r n iz r .c o m /. Библиотека M odernizr ш ироко ноддерж ивается раз­
работчиками, и вы будете часто сталкиваться с ее н рим енением в И нтернете. Мы рекомендуем вам ее.

Включение Modernizr В сбою страницу


Д ля нснользовання M odernizr вам нужно загрузить эту JavaScript-библиотеку в свою страницу. Для этого
сначала нотребуется зайти на сайт M odernizr (h t t p : //w w w .m o d e r n iz r .c o m /d o w n lo a d /), где вы см ож ете
нрои звести пользовательское конф игурирование библиотеки, которая в итоге будет содержать только
н еобходим ы й вам код для детектирования (либо м ож ете включить в н ее сразу все, находясь на стра­
н ице но данному адресу). Сделав это, сохраните библиотеку в файле и загрузите его в свою страницу
(н осети те веб-сайт Modernizr, чтобы найти дополнительны е учебны е материалы и документацию но
оптимальным методикам работы ).

Как определяется, ч то именно поддерживает браузер


П осле инсталляции M odernizr нроц есс детектирования НТМ Ьб-элементов и API-интерф ейсов JavaScript
станет намного легче и нроще:

Пример определения поддержки API-


if (Modernizr.geolocation) {
интерф ейсов d eolocatio n , VJeb Storage ^
и Video последовательным образом. console.l o g ("You have geo!");

Примечание: возможности библиот е­ if (Modernizr.localstorage) {


ки M odernizr п р о ст и р а ю т ся значительно console.l o g ("You have web storage!");
дальше прост ого детектирования поддержи­
ваемых A P I-инт ерф ейсов; она также п о ­
if (Modernizr.video) {
зволяет определят ь поддерживаемые CSS-
п а р а м е т р ы л видеокодеки и многое другое. console.l o g ("You have video!");
П оэтому обязательно ознаком ьт есь с ней!

566 приложение
оставшиеся темы

№ 2. Элемент audio и A PI-интерфейс Audio


HTM L5 предусматривает стандартны й сн особ восн рои зведен ия аудио на ваших страницах с использо­
ванием не плагинов, а элемента <audio>:
Выглядит знакомо? Д а , audio
< a u d i o s r c = " s o n g . i n p 3 n i d = Mb o o m b o x n c o n t r o l s > поддерживает аналогичную ф у н к -
S o r r y b u t a u d io i s n o t s u p p o r t e d i n y o u r b r o w s e r . Циональность> как и video ( е с т е -
< /a u d io > ственно, за исключением возмож ­
ности воспроизводить видео).

П омимо элемента <audio>, существует соответствую щ ий API-интерф ейс A udio, ноддерж иваю щ ий ме­
тоды , которы е вы и ожидали бы увидеть, нанример play, pause и load. Если вам все это нокажется
знакомым — это хор ош о, носкольку API-интерф ейс A udio является отраж ением (в соответствую щ их
случаях) API-интерф ейса V ideo. API-интерф ейс A udio также ноддерж ивает м ногие свойства, с кото­
рыми вы сталкивались в API-и нтерф ей се V ideo, нанример src, currentTime и volume. Н иж е нриведен
небольш ой связанный с аудио код, чтобы вы ночувствовали, как данны й API-интерф ейс иснользуется
в сочетании с элем ентом в странице:

va r a u d io E le m e n t = Извлекаем ссылку на элем ен т audio,


d o c u m e n t. g e tE le m e n t B y ld ( "b o o m b o x ") ;
после чего у м ен ьш аем гр о м к о с т ь звука
a u d io E le m e n t . v o lu m e = .5 ; на 1 / 2 и запускаем воспроизведение.
a u d io E le m e n t.p la y ( ) ;

Как и в случае с видео, каждый браузер но-своему реализует внеш ний вид элементов унравления нро-
игрывателем (в число которы х обы чно входит нолоса воснроизведения, кнонки ностановки на наузу
и регулирования громкости).

Н есм отря на нростую функциональность, элем ент audio и API-интерф ейс A udio нредоставляю т вам
ш ирокий контроль. П одобн о тому как мы ностунали с элем ентом video, вы см ож ете создавать и н терес­
ные веб-нриложения, предусматривая скрытие элементов унравления из виду и унравление воснроиз-
ведением аудио в своем коде. А с номощ ью HTM L5 тенерь у вас есть возмож ность делать это без н ео б ­
ходим ости иснользовать (и изучать) нлагины.

С тан д ар т В сфере аудцоформатов


П рискор бно, но, как и для видео, стандартного ф ормата
для аудио нет. Понулярны три формата: MP3, WAV и O gg
Vorbis. Вы увидите, что ноддерж ка данны х форматов ва­
рьируется среди браузеров (на м омент нанисания книги
Chrom e был единственны м браузером, ноддерживавш им
все три формата).

дальше ► 567
j Query

He забывайте, что Ajax — эт о всего лишь н а -


№ 3 . j Q uery звание шаблона использования XM L H ttpRequest
для извлечения данных, как отмечалось в главе 6 .
jQ uery нредставляет со б о й JavaScript-библиотеку, иризваиную уменьшить количество,
а также унростить большую часть JavaScript-кода и синтаксиса, которы е н еобходим ы для
работы с объектной моделью документа (DO M ), использования Ajax и добавления визу­
альных эф ф ектов к вашим страницам. jQ uery является весьма нонулярной, ш ироко ис-
нользуемой библиотекой и ноддерж ивает возмож ность расш ирения носредством своей
нлагиновой модели.

jQ uery не нозволяет сделать ничего такого, чтобы было бы невозм ож но с номощ ью


JavaScript (как мы уже говорили, jQ uery является всего лишь JavaScript-библиотекой), од­
нако она дает возмож ность сократить количество кода, к оторое вам нридется нанисать.

Понулярность jQ uery говорит сама за себя, хотя м ож ет потребоваться н ек отор ое время,


чтобы вы нривыкли к ней. П осм отрим, что м ож но сделать с номощ ью библиотеки jQuery.
И сследуйте ее бол ее нристально, если реш ите, что она будет вам нолезна.

Для начала вонрос: ном ните ли вы все те функции w indow .onload, которы е мы нисали \
но ходу книги? Нанример: т а к т и ч е ск о е
3 наши они ^
window, on load = f u n c t io n () { ^ а н и е jQ uery являете
a l e r t ("the page i s lo a d e d !" ); деЗНЫМ навыКОМ>
, п о м о га ет , п о н я т ь код,
д .п писанный другими.
А вот то ж е самое, но с иснользованием jQuery:

$ (document) . read y ( fu n c tio n () { <— К ак и в нашей версии: когда за гр узка докум ент а
a l e r t ("the page i s lo a d e d !" ); б удет закончена, вызвать м о ю функцию.
}) ;
М ожно сократить данный код ещ е больше, до:
$ ( fu n c tio n () { Это классно, но чтобы привы кнут ь, п от реб ует ся
немного времени. Не беспокойтесь — все эт о быстро
a l e r t ("the page i s lo a d ed ! ") ; ^ ^ npiAgm i M делоМ.
}) ;
А что с извлечением элементов и з объектной модели документа (DOM)? И м енно здесь jQ uery блистает.
Донустим, в вашей странице им еется якорь с id в виде "buynow" и вы хоти те назначить обработчик со­
бы тий, инициируемы х нри щелчке кнонкой мыши, для собы тия c l i c k данного элемента (как мы уже
делали ранее несколько раз). Вот как это м ож но сделать:
Так что же здесь происходит ? Сначала мы задаем ф ун кцию ,
кот орая будет вызываться по завершении загрузки страницы.

$ (fu n c tio n () { _____ Д алее мы извлекаем якорь с id в виде "buynow"


(следует о т м е т и т ь , что jQ u e ry использует
$ ( "# b u y n o w M) . c lic jM fu n c tio n () { CS S -синтаксис для выборки элем ен т ов).
a le r t (пI w ant to buy n o w ! 11) ;

D ' З а т е м мы вызываем jQ u e ry - м е т о д click в отношении


>) ; р е з у л ь т а т а для задания обработчика onclick.

568 приложение
оставшиеся темы

Н а самом деле это лишь начало; мы м ож ем так ж е легко задать обработчик собы тий c l i c k для каждого
якоря на странице:
Для эт ого нам п о т р еб ует ся использовать
$ ( f u n c t i o n () {
лишь с о о т ве т с т в ую щ е е имя тега.
$ ( " а ” ) . c l i c k ( f u n c t i o n () {

a le r t ( " I w ant to buy n o w !") ; Сравните показанное здесь с кодом,


который вам пришлось бы н ап и сат ь,
});
используя J a v a S c rip t без jQ uery.
});

Н апр им ер, мы можем найти все элемент ы


Мы также мож ем делать бол ее сложны е вещи:
<Н>, кот оры е являются дочерними по о т ­

$ ( f u n c t io n () { Г ношению к э л е м е н т у с id в виде "playlist".

$ ( " # p la y lis t > li" ) .a d d C la s s ( " f a v o r it e " ) ; Д з а т е м добавить


\\ . ^ ^ их в класс "favorite".

X
Ч_ Вообще т о здесь jQ u e ry лишь « ра зо гр е ва е т с я »; данная библиотека
позволяет делат ь вещ и, намного сложнее этик.

У jQ uery есть соверш енно другая сторона, которая нозволяет осуществлять лю боны тны е и н тер ф ей с­
ные трансф ормации элементов, как ноказано далее:

$ ( f u n c t i o n () {

$ ( " # s p e c i a l o f f e r " ) . t o g g l e ( f u n c t i o n () {

$ ( t h i s ) . a n im a t e ( { b a c k g r o u n d C o lo r : " y e llo w " }, 800);

},fu n c t i o n () {

$ ( t h i s ) . a n im a t e ( { b a c k g r o u n d C o lo r : " w h ite " }, 300);

; Э т о т код п ереклю чает элем ен т с id в виде


}) ; 1 "speda!offer" из состояния, в к о т о ро м он желтый
и и м еет ширину 2 0 0 пикселов, в состояние, в к о т о ­
р о м он белый с шириной ЗОО пикселов, при э т о м п е р е ­
ход между двумя данными состояниями анимируется.

Как вы м ож ете видеть, с номощ ью jQ uery возм ож но м ногое, нри этом мы даже еще не начинали раз­
говор об иснользовании дан ной библиотеки для общ ения с веб-службами и обо всех нлагинах, которы е
работаю т с jQuery. Если вы заинтересовались дан ной тем ой, введите в браузере адрес h ttp ://jq u e r y .
с о т / и изучите имею щ иеся там учебны е материалы и документацию.

А также загляните в книгу « И зу ч а е м р а б о т у с j Q u e r y » (Head First jQuery)!

дальше ► 569
XHTML и SVG

№ 4 . XHTML м ертв, 9a здравствует XHTML


Мы довольно ж естко новели себя с XHTM L в этой книге, сначала во время дискуссии «XHTML мертв»,
а затем н оздн ее, когда вели речь о «JSON нротив XML». Вся нрав да заключается в том, что когда дело
доходи т до XHTM L, то здесь им еется в виду версия XHTM L 2 и выше, которая умерла, нри этом вы,
фактически, м ож ете нисать свою НТМЬб-разметку, иснользуя XHTM L-стиль, если захотите. П очему вы
м ож ете этого захотеть? Ч то ж, вам м ож ет потребоваться осуществлять валидацию или трансф ормацию
своих документов как XML либо обеснечить ноддержку XML-технологий вроде SVG (см. тему № 5), ко­
торы е работаю т с HTML.
Давайте взглянем на н р остой XHTM L-документ, а затем нройдем ся но основны м аснектам (для нас не
нредставлялось возмож ны м новедать обо всем, что вам нотребуется знать но дан ной теме, как и обо
всех вещах, связанных с XML, носкольку вы бы стро запутались бы).

То же самое определение
< ! D O C TY P E h t m l > . _____ d o c ty p e , что и раньше!
~ Это XML, нам нужно
Chtml xmlns="http://www.w3.org/1999/xhtml"> ^ _ у пр о с т р а н ст ^о имен!
<head>
< title > Y o u R ock!< /title > Все элементы должны быть правильными;
/ о б р а т и т е здесь внимание на идущие о конце
C m e ta c h a r s e t = " U T F - 8 '- /> сиМ ош исП0ЛЬЗуеАЛЬ1е для зак ры -
</head> тия данного п уст ого элемент а.
<body>
<p>I'm kinda liking this XHTML!</p>
Мы используем SVCi
<svg xmlns="h t t p ://www.w3.org/2000/svg"> для рисования прямо -
<rect stroke="black" fill="blue" x="45px" y="45px" угольника на нашей
width="200px" height="lOOpx" stroke-width="2 " /> странице. Изучите
</svg> ^ т е м у N~S (на следую -
</bod > 4. можем вложить XML щей ст ранице)> чтобы
° У прямо в страницу! И эт о у ЗИа т ь больше о SVQ.
</html> очень здорово.
А тенерь давайте взглянем на ряд вещ ей, которы е вам нотребуется нринимать во внимание в случае
с вашими XHTM L-страницами: Закры т ие всех ваших э л е м е н ­
т о в , кавычки вокруг значений
■ Ваша страница долж на нредставлять со б ой нравильный XML. а т р и б у т о в , допуст им ое вл о­
жение элемент ов и т. п.
■ Ваша страница долж на загружаться с иснользованием тина MIME application/xhtml+xml, для чего
вам нотребуется удостовериться в том, что ваш сервер обеснечивает данны й тин (нроверив это са­
м остоятельно либо связавшись с адм инистратором вашего сервера).

■ О беснечьте и включите пространство имен XHTM L в свой элем ент <html> (что мы уже сделали
в коде чуть выше).

Как мы уже отмечали ранее, относительно XML существует масса дополнительны х вещ ей, о которы х
м ож но узнать, а также м нож ество вещ ей, с которы ми следует быть осторож ны м и. И, как и всегда в слу­
чае с XML, да нребудет с вами Сила...

570 приложение
оставшиеся темы

№ 5. SVG
Scalable Vector Graphics («Масштабируемая векторная графика» ), или SVG, иредставляет со бой еще один
сн особ — номимо canvas — включения графики нативно в ваши веб-страницы. SVG существует уже дол­
гое время (с 1999 года или около того) и в настоящ ий м омент ноддерж ивается во всех текущих версиях
основны х браузеров, включая Internet Explorer 9 и выше.
В отличие от canvas, которы й, как вы знаете, иредставляет со бой элемент, нозволяю щ ий рисовать
никселы на н оверхн ости для растрового рисования с номощью JavaScript, SVG-графика определяется
использованием XML. XML, вы говорите? Да, XML! Вы будете создавать элементы , которы е нредстав-
ляют графику, а затем объединять эти элементы друг с другом комплексными путями для создания гра­
ф ических сцен. Давайте взглянем на очень н р остой SVG-нример:

Мы используем HTMLS в XHTM L-


стиле п о т о м у , что применяем SVQ,
<!DOCTYPE html> что основывается на XML.
<html xmlns="h t t p :/ / w w w . w 3 .org/1999/xhtml">
<head>
<title>SVG</title>
<meta charset="utf-8" />
Мы используем элем ен т
</head>
<svg> прямо в нашей

S
<body> HTML -разм е т к е ! ^
Наш SVG - п р и м е р прост: он сооер
<div id="svg"> v- ^ m w кот 0рый pacno
<svg xmlns=”http: //www.w3.org/2000/svg"> у ______
> У ложен по - ~ K00pduHamaM X=50, y=SO
<circle id="circle" и обладает радиусом 2-0 пикселов
c x = " 5 0 " c y = "50 " r= "2 0"
s tro k e = " # 3 7 3 7 3 7 " s tro k e -w id th = " 2 " ^ ...снабжен линией обводки шириной 2 пик
fill= " # 7 d 7 d 7 d " /> села, имеющей т ем н о -с е р ы й цвет...
</svg>
</div> ...и заливкой с исп оль­
Вы можете извлечь
</body> зованием серого цвета
данный элем ен т
</html> со средним значением.
circle, как и любой
SVG онределяет ряд базовых фигур, таких как круги, нрямоугольники, многоу­ другой элем ен т из
гольники, линии и т. д. Если вам нотребуется нарисовать более сложные фигуры, объектной модели
то вы также см ож ете онределить контуры с номощ ью SVG — естественно, в этот докум ент а Р О М ,
м омент вещи начнут становиться более сложными (как вы уже могли убедиться и сделат ь с ним
в случае с контурами в canvas). Однако существуют графические редакторы , ко­ т о, что вам необ­
торы е нозволят вам нарисовать сцену или экспортировать ее как SVG, избавляя ходимо... н а п р и м е р ,
вас от головной боли, которую вам доставила бы н еобходим ость самостоятель­ добавить о б р а б о т ­
но разбираться со всеми этими контурами! Вы см ож ете масштабировать свою чик событий click
графику, увеличивая или уменьшая ее но своему усм отрению , и она нри этом не и изменять зн аче­
подвергнется никселизации, которая и м еет м есто нри масштабировании и зо ­ ние а т р и б у т а fill
браж ений в ф ормате jp e g или png. Это облегчает новторн ое использование гра­ элем ен т а circle на
фики в различны х ситуациях. А носкольку SVG определяется с использованием 11r e d 11, когда п о л ь ­
текста, в случае с SVG-файлами м ож но осуществлять ноиск, индексировать их, зоват ель щелкнет
нрименять к ним сценарии, а также сжимать их. И сследуйте данпую технологию на данном э л е м е н ­
но др о б н ее, если она вас заинтересовала. те мышью.

дальше ► 571
автономные веб-приложения и api-интерфейс web sockets

№ 6. Автономные 6еб-прилоЖенця
Е с л и у вас им еется см артф он или нланш етный комнью тер, то вы, вероятно, выхо­
дите в И нтернет, находясь в пути, и благодаря Wi-FI и сетям сотовой связи ночти
все время подключены к В сем ирной наутине. А как насчет того врем ени, когда вы
не подключены к ней? Разве не будет здор ов о, если вы см ож ете нродолжать ис-
нользовать все эти веб-нрилож ения HTM L5, которы е создаете для себя?
Ч то ж, тенерь у вас есть такая возмож ность. Автономны е веб-нрилож ения ноддер- ^
ж иваются всеми настольными и мобильными браузерами (с одним исключением: ^ благодаря т а -
Internet Explorer). кой вещ и, как
Как ж е сделать свои веб-нрилож ения достунными в автоном ном режиме? Нужно авт о но мные
создать файл манифеста кэша, которы й будет содержать снисок всех файлов, необ- веб-приложения,
ходимы х вашему нрилож ению для работы, и браузер загрузит все эти файлы и не- у вас ест ь
реключится на локальные файлы, когда ваше устройство н ерей дет в автономны й возможность
реж им. Ч тобы сообщ ить своей веб-странице о том, что у н ее имеется файл мани- пользоваться
ф еста, пужно н росто добавить его ф айловое имя в тег <html>, как ноказано далее: своими льо-
Chtml manif est="notetos elf .manifest " > биМЫМи веб -
Вот что содерж и т файл notetoself .manifest: прилож ениям и,
~ когда вы не п о д -
САСНЕ M A N IF E S T 4 ------- С э т о го должен начинаться каждый КЛМЧены к И н -
САСНЕ: ^ ф а й л м а н и ф е с т а кэша. т ернету'.

notetoself.html К — 3 секции CACHE нужно ук а за т ь все ф айлы , которые


notetoself.css ) вы х о т и т е кэшировать: файлы с HTML- р а зм е т к о й ,
notetoself .js с CSS и J a v a S c r ip t-кодом , файлы изображений и т. п.
Данны й файл «говорит»: нри заходе на веб-страницу, указывающую на данны й файл, следует загрузить
все файлы, указанные в секции CACHE этого файла. Вы также м ож ете добавить две дополнительны е
секции в данны й файл — f a l l b a c k и n e t w o r k . f a l l b a c k онределяет то, какой файл будет иснользовать-
ся, если вы ноны таетесь нолучить достун к файлу, которы й не был кэш ирован, a NETWORK онределяет
файлы, которы е никогда не должны кэшироваться (нанример, в случае с ресурсами, отслеживающ ими
уровень посещ аем ости).
А тенерь, нреж де чем реш ите ноиграть со всем этим, вам н еобходи м о узнать о двух вещах: во-нервых,
вам будет пужно убедиться в том, что ваш веб-сервер обеснечивает корректны й тин MIME в случае с
файлами м аниф еста кэша (точно так ж е, как нам это было нужно сделать, когда речь шла о видеоф ай­
лах в главе 8 ). Н анример, если вы иснользуете сервер A pache, то добавьте нриведенпую далее строку в
файл . htaccess на верхнем уровне вашего веб-каталога:
AddType text/cache-manifest .manifest

В тор ое, что вам будет пужно знать, заключается в том, что тестирование автономны х веб-нрилож ений
осущ ествляется мудреным снособом ! Мы рекомендуем вам изучить соответствую щ ие снравочны е мате­
риалы на эту тему, а также спецификацию автономны х веб-нрилож ений HTML5.
Как только у вас заработает базовое кэш ирование, вы см ож ете иснользовать JavaScript для нолучения
уведомлений о связанных с кэшем собы тиях, которы е инициирую тся, нанрим ер, когда файл м аниф е­
ста кэша подвергается обновлению , а также о состоянии кэша. Для нолучения уведом лений о собы тиях
н еобходим о добавить обработчики собы тий в объект window. applicationCache, как ноказано далее:
window. applicationCache.addEventListener("error", errorHandler, false);
Реализуйт е errorH andler для получений уведолл-
572 приложение лений, если в случае с кэш ем произойдет ошибка.
оставшиеся темы

№ 7. A PI-интерфейс Web Sockets


В э т о й книге мы рассм отрели два сн особа коммуникации: XMLHttpRe quest и JSONP. В обои х случаях мы
иснользовали модель « за н р о с/о тв ет» на основе HTTP. То есть мы нрименяли браузер для соверш ения
занроса и сходн ой веб-страницы, CSS и JavaScript, и каждый раз, когда нам требовалось что-то другое,
мы соверш али новый занрос с иснользованием XMLHttpRe quest или JSONP. Мы даже соверш али занро-
сы, когда для нас не было никаких новых данных, что иногда случалось в нрим ере с Mighty Gumball.

Web Sockets — это новый API-интерф ейс, которы й нозволяет ноддерживать откры тое нодклю чение
к веб-службе, чтобы каждый раз, когда становятся достунными новы е данны е, эта служба могла нри-
сылать их вам (и ваш код мог нолучать соответствую щ ие уведомления). Считайте все это откры той
тел еф он н ой линий между вами и службой.

Вот вы сокоуровневы й об зо р того, как следует иснользовать данны й API-интерфейс: сначала для созда­
ния веб-сокета вам нотребуется нрименить конструктор WebSocket: о б р а т и т е внимание: в с л у -
чае с данным URL-адресом
используется прот окол WS,
va r socket = new W e b S o cke t ( "ws :/ / y o u r d o m a in /y o u r s e r v ic e " ); a не п р о т о к о л HTTP.

" И п о м н ит е, что вам либо к о м у - т о д р у ­


го м у придет ся написат ь серверный код,
чтобы у вас было с чем «общ ат ься».

Вы см ож ете нолучить уведом ление, как только сокет будет открыт носредством собы тия open, для кото­
рого м ож но назначить обработчик: Здесь мы п р едусм о т рел и обработчик, который
ст а н е т вы зываться, когда сокет будет полност ью
s o c k e t . o n o p e n = f u n c t i o n () { п
о т к р ы т и гот ов к коммуникации.
a le r t( " Y o u r socket is now open w ith th e w eb s e r v ic e " ) ;

}
Вы см ож ете отнравить веб-службе сообщ ени е с номощ ью м етода postMessage:
Здесь мы от правляем серверу с т р о к у j
s o c k e t.p o s tM e s s a g e ( - - p la y e r m o v e d r ig h t- - ) ; двоичные данные н а с т у п а ю т , но пока еще
не поддерживаются широко.
А для нолучения сообщ ени й необходим о зарегистрировать другой обработчик, как показано далее:
З ар еги с т р и р ова в обработчик,
s o c k e t, onmessage = function ( event ) { мы сможем получат ь все
alert ("From socket: " + event.data); сообщения, содержа­
щиеся в свойстве
*' event.data.
К онечно, но мимо всего этого есть немного ещ е кое-чего, и вам п о­
требуется изучить учебны е материалы, имею щ иеся в И н терн ете, однако
относительно API-интерф ейса больше о со б о сказать нечего. Данны й API-
и н тер ф ей с отстает в развитии от некоторы х других API-интерф ейсов HTML5,
ноэтому читайте самые свеж ие руководства, где содерж ится инф орм ация о совме­
стим ости с браузерами, нреж де чем браться за какой-либо крунный проект.

573
дополнительно о api-интерфейсе canvas

№ 8. Дополнительно об A PI-интерфейсе Canvas


Мы уже нровели весело время с canvas в главе 7, создавая наш стартан TweetShirt. Однако есть еще
много интересны х вещ ей, связанных с canvas, которы е м ож но сделать, и мы хотим рассказать здесь
о некоторы х и з них.
Мы очень кратко уноминали, что вы см ож ете сохранять и восстанавливать context элемента canvas с
номощ ью, соответственно, методов save и restore. Зачем вам м ож ет потребоваться сделать это? Д о ­
пустим, вы задали значения для ряда свойств context, нанрим ер fillStyle, strokeStyle, lineWidth
и т. д. А затем у вас возникла н еобходим ость врем енно изменить их значения для того, чтобы кое-что
сделать, нанример нарисовать фигуру, однако вы нри этом не хоти те заниматься восстановлением всех
эти х значений, чтобы верпуться к тем значениям свойств, что были у вас нреж де. Для этого вы м ож ете
воспользоваться м етодами save и restore:

. м м задаем значения для группы свойств


context.fillStyle = "lightblue"; в c o n tex t и осущ ест вляем рисование.
Теперь мы сохраняем context. Значения всех эплих свойств
context.s a v e () б у ду т надежно сохранены. Mbi сможем изм ени т ь их...
context.fillStyle = "rgba(50, 50, 50, .5)";
context.filiRect(0, 0 , 100 , 100 );
context.resto r e () ;
...а з а т е м в ер н ут ь всех их об ра т н о, сделав их т а к и м и , какими они
были прежде, когда мы сохраняли эт и значения, для чего прост о
вызовем м е т о д restore! 3 э т о т м о м е н т все наши свойства п р и ­
о б р е т у т значения, кот орые они имели перед сохранением.
Д анны е методы особен н о нридутся кстати, когда вам нотребуется транслировать или новерпуть canvas
для того, чтобы что-то нарисовать, а затем верпуть его в нолож ен и е но умолчанию. Что делаю т методы
translate и rotate? Давайте носмотрим...

Loo*Wh«ItVe* /^ЧУ нас в странице имеется canvas размером 400x400


I4 пикселов. Если мы нарисуем прямоугольник с коорди­
натами х=0, у=0, то он появится в верхнем левом углу, как
мы и ожидали бы.
context.filiRect(0, 0, 100, 100);

/JVТеперь мы берем canvas и перемещаем его


на 200 пикселов вправо и на 200 пикселов
вниз. Если мы нарисуем еще один прямоуголь­
ник с координатами х=0, у=0, то он появится на
200 пикселов правее и на 200 пикселов ниже
первого нашего прямоугольника. Мы только что
транслировали canvas.
context.translate(200, 200);
context.filiRect(0, 0, 100, 100);

574 приложение
оставшиеся темы

LwtLWucI l>f- /0\ А что, если ми повернем canvas до того,


как нарисуем прямоугольник? canvas вра­
щается вокруг своего верхнего левого угла
(по умолчанию), и поскольку мы только что
переместили верхний левый угол в позицию
2 00,2 00, там и будет вращаться canvas.

ш context.translate(200, 200);
context.rotate(degreesToRadians(36));
context.fillRect(0, 0, 100, 100);

Когда вы т р а н с л и р уе т е иди п о ­
ворачиваете canvas., он п е р е м е ­
щается по координатной сет ке,
которая позиционируется о т ­
носительно верхнего левого угла
окна браузера. Если вы прим ен ит е

т 36
CSS для позиционирования canvas,
то данные значения б у дут п р ин и­
м а т ь ся в расчет. Попробуйте!

А тенерь давайте соединим все это! Вы м ож ете иснользовать методы t r a n s l a t e и r o t a t e


сообщ а для создания интересны х эф ф ектов.

var canvas = document.getElementByld("canvas"

var context = canvas.getContext("2d");

var degrees = 36;

натной сетке после т ого , как мы


context.s a v e (); А вот итогооыи р е -
Mw т р а н сли р уем наш canvas, з д - ^ з у л ь т а т . Интересно
context.translate (200, 200) ; dag npu э т о М з н а ч е н и я 2-00, ZOO. выглядит!
context.fillStyle " rgba(50, 50, 50, .5
Мы р и су е м
Ю п р я м о уго л ь -
for (var i = 0; i <360/degrees; i++) { ^ НиК° в пУмеМ
поворот а canvas
context.fillRect(0, 0, 100, 100); на 36° перед т ем ,
context.rotate(degreesToRadians(degrees)); ри соват ь пря
м оугольник о n o -
} Теперь наш canvas возвра- зищли О, О, при
context.restore (); щ ает ся в свое исходное каж дом вы полне-
полож ение/ Иии цикла.
К омбинируйте эти нросты е трансф орм ации с другими даж е ещ е более
мощными (и сложными!) методиками вроде комнозиции и п реобразова­
ний, и возм ож ности но созданию графических и зображ ен и й с использо­
ванием canvas стапут безграничными.

дальше ► 575
api-интерфейс selectors и кое-что еще

№ 9. A P I-интерфейс Selectors
Вы уже знаете как нронзводнть выборку элементов и з объектной модели документа DOM с номощью
document.getElementByld; мы иснользовали данны й м етод как сн особ сделать так, чтобы HTML и
JavaScript работал и сообщ а. Вы также увидели, как сл едует иснользовать document.getElementsByTagName
(данный м етод возвращ ает массив всех элементов, соответствую щ их заданному тегу) и даж е метод
getElementsByClassName (возвращающий, как вы уже догадались, все элементы в он ределенн ом клас­
се). Благодаря HTM L5 сейчас у нас им еется новы й сн особ выборки элементов из объектной модели до­
кумента DOM , основанны й на j Query. Тенерь вы м ож ете задействовать те ж е селекторы , которы е при­
м еняете в CSS с целью выборки элементов для стилизации в своем JavaScript, для выборки элементов из
объектной модели документа DOM с использованием м етода document.querySelector. Допустим, у нас
им еется приведенная далее нростая HTML-разметка:
<!doctype html>
<html lang="en">
<head> Пристально взгляните на с т р у к т у р у
< t it l e > Q u e r y s e l e c t o r s < / t i t l e > данной HTML-разм ет ки. Мы собираемся
<meta c h a r s e t = " u t f - 8 "> __ использовать A P I -инт ерф ейс Selectors
< /h e a d > gbl$0p KU элементов из страницы.
<body> С—
<div class="content">
<р id="avatar" class="level5">Gorilla</p> У нас &сть элем ен т <div> С классом
<р id="color">Purple</p> ^ " c o n te n t” и два элем ен т а <р>, каждый
</ div> из которых обладает собственным
</body> и ден т иф ик а т ор ом , при э т о м у одно -
</html> го из ниу имеет ся класс "le v e lsп.

Тенерь давайте воспользуемся API-интерф ейсом Selectors для выборки элемента <р> с id в виде "avatar":
document.queryS elect or ("# avatar" ) ; 4*—

П о сути, это то ж е самое, что и document . getElementld ("avatar"). Тенерь давайте иснользуем класс
элемента для его выборки: ^ ^
U , Сейчас мы используем имя т ега
document.querySelector("p.Ievel5"); u класс для его выборки.
Мы также мож ем нрои звести выборку элемента <р>, которы й является дочерни м но отнош ению к эле-
менту < d iv > , следующим образом: мы ислользуем селектор дочерних
d o c u m e n t.q u e ry S e le c to r (" d iv > p " ) ; эл е м ен т о 0 child для выборки элем ен т а <р>,
или даж е так: который является дочерним по отношению
л /" к э л е м е н т у <div>. По умолчанию он выби-
document.querySelector (". content>p") ; — л - ,,лл
^ J v * ' р а е т первый элемент.
А если нам но надобятся все элементы <р> в <div>, то мы см ожем воспользоваться другим м етодом в API-
и н тер ф ей се Selectors с им енем queryS elect orAll: , п _
Теперь мы извлекаем все дочерние
document.queryS elect о г All ("div>p" ) ; элемент ы <р> элем ен т а <dtv>!

queryS el ectorAll возвращ ает массив элементов точно так ж е, как и м етод getElementsByTagName.
Вот и всё! В API-интерф ейсе Selectors им еется только два метода. Данны й API-интерф ейс является н е­
большим, однако он нривносит новую мощпую функциональность для выборки элементов.

576 приложение
оставшиеся темы

№ 10. Однако есть даЖе еще кое-что!


Мы действительно хотели ограничиться десятью темами, которы е не рассм о­
трели в дан н ой книге, но, п охож е, что нам есть ещ е куда двигаться, и вместо
того чтобы стоять между вами и чтением алфавитного указателя, мы поведаем
вам о нескольких дополнительны х темах на одн ой странице. Вот они (им ейте в
виду, что некоторы е из эти х обл астей все ещ е развиваются, одпако мы поним а­
ли, что вам потребуется зпать о них па будущее):

A P I-интерфейс Indexed Database и Web SQ L


Е с л и в ы ищ ете нечто бол ее индустриальное, чем API-интерф ейс Web Storage,
для сохрапени я свои х данны х локальпо, следите за сф ер о й баз данны х, функци­
онирую щ их в И п тер н ете. В настоящ ее время там присутствуют два конкуриру­
ю щ их реш ения: Web SQL и In d exed D B . По ирони и судьбы, технология Web SQL
обр ел а бол ее широкую поддерж ку по сравнению с In d exed D B , одпако недавпо
комитет стандартов выступил против нее (то есть он не реком ендует перепи-
мать ее как стандарт, и вам, вероятно, не следует основывать на п ей свой следу­
ющ ий стартап). С другой стороны , технология In d exed D B пока не реализовала ш ироко, однако поддерж ивается
со стороны G oogle и Firefox. In d exed D B обеспечи вает бы стры й доступ к обш и р н ой коллекции индексированны х
данпы х, в том время как Web SQL является компактным SQL-движком, работающ им в браузере. Следите за тем,
куда движутся эти технологии; они бы стро меняются!

A P I-интерфейс Drag and Drop


Веб-разработчики уже долгое время обеспечи ваю т возм ож пость перетаскивать и помещ ать элем енты с помощью
мыши, используя для этого jQ uery, а теперь данная функциональность пативно поддерж ивается в HTM L5. И споль­
зуя API-ин терф ейс Drag and Drop, вы м ож ете определить что-либо для перетаскивания, а также м есто, куда п ер е­
таскиваемый элем ент м ож но будет пом естить, и JavaScript-обработчики, которы е будут уведомляться о различны х
собы тиях, инициируем ы х при перетаскивании и пом ещ ении элем ентов. Ч тобы сделать элем ент поддерж иваю ­
щим возм ож ность перетаскивания с помощ ью мыши, нужно лишь задать для атрибута draggable значение true.
Перетаскивать мож но почти любы е элементы: и зобр аж епия, списки, параграфы и т. д. Вы м ож ете конф игуриро­
вать пов едеп и е, связанное с перетаскиванием , путем прослуш ивания собы тий, наприм ер, dragstart и dragend,
и даже измепять стиль элем ента, чтобы во время перетаскивапия он п риобретал такой впеш ний вид, которы й вы
пож елаете. Вы м ож ете отправлять небольш ое количество данпы х наряду с перетаскиваемы м элем ептом , исполь­
зуя свойство dataTransf ег; обращ аться к нему м ож но посредством объекта event, чтобы узнать, наприм ер, п ер е­
мещается ли определ ен н ы й элем ент или ж е копируется. Как вы м ож ете видеть, благодаря такому API-интерф ейсу
HTM L5, как Drag and D rop, п ер ед вами откры вается масса прекрасны х возм ож н остей по обесп еч ен и ю повы х взаи­
м одействий с и н тер ф ей сом пользователя.

A P I-интерфейс Cross-document Messaging


В главе б мы использовали ш аблон передачи данпы х, известны й как JSONP, чтобы избеж ать м еж дом енны х ком-
муникационпых проблем , возникаю щ их в случае с XMLHttpReguest. Существует ещ е одип сп о со б коммуника­
ции между документами — даже документами, находящ имися в разны х дом енах. API-ин терф ейс C ross-docum ent
M essaging определяет, что вы см ож ете отправить сообщ еп и е документу, которы й загрузили, используя элем ент
ifram e. Данны й документ даже м ож ет располагаться в другом дом ене! Теперь вам не потребуется загружать про­
сто любойдокумепт в свой iframe; вам будет нужно удостовериться в том, что он исходит из дом ена, котором у вы
довер я ете, и настроить его па прием ваших сообщ ен и й . В результате вы получаете сп о со б отправлять сообщ ения
туда-сюда между двумя HTM L-до куме птам и.

U мы могли бы продолЖать и дальше...


Захватывающая вещь относительно HTM L5 заключается в том, что больш ое количество новы х фупкциональпы х
возм ож н остей разрабаты вается довольно быстрыми темпами; на эт о й страпице мы могли бы привести ещ е боль­
ше материала, однако для этого просто не осталось места. П оэтом у заходите к нам на сайт в И п тер н ете по адресу
h t t p : //w ick ed ly sm a rt.co m , чтобы узнавать о б о всех новейш их разработках в области HTML5!

дальше ► 577
htm 15-руководство по новым конструкциям

Не верится, что книга почти закончилась.


Прежде чем мы с вами расстанемся, у нас есть
для вас прощальный подарок от города Веб­
вилль; это руководство по НТМЬ5-элементам
(атакже по новинкам в CSS3), которое мы вам
обещали. Замечательный город этот Вебвиль,
не правда ли?!

578 приложение
оставшиеся темы

HTMLS-pykoBogcmBo по новым конструкциям


Здесь, в Вебвилле, мы недавно внесли ряд дон олнен и й в наши «строительные»
коды и нодготовили удобное руководство но всем новым конструкциям, которы е
могут нредставлять для вас интерес. Так, в частности, мы добавили грунпу новых
семантических элементов, которы е обеснечат для вас даж е ещ е более ш ирокие
возм ож ности но созданию страниц. Однако наше руководство не является и счер­
пывающим; верн ее, наша цель здесь заключалась в том, чтобы дать вам, онытному
разработчику, достаточно материала для того, чтобы вы были хорош о знакомы с
новыми НТМ Ьб-элементами и CSSS-свойствами и смогли иснользовать их в веб-
нрилож ениях, создание которы х изучаете в данной книге, когда будете к этому
готовы. П оэтом у если вам требуется краткое уч ебн ое н особи е но семантическим
нововведениям в HTM L5, то м ож ете взять один экземнляр — они БЕСПЛАТНЫ
(но лишь в теч ен и е ограниченного врем ени).

дальше ► 579
семантические элементы html5

Вебвилльское руководство по сем антическим элементам HTML5

Здесь, в Вебвилле, мы внесли ряд свежих изменений в наш «строительный» код и подготовили
<div> вместо
удобное руководство по всем новым конструкциям. Если вы используете элементы
обычных конструкций вроде <header>, <nav>, <f ooter> и <article> для блоговых статей,
то у нас есть для вас новые строительные блоки. Итак, давайте взглянем на них.

<section>

<section> — это «общий документ». Вы могли бы использовать <section>


для разметки, например, «Руководства по HTML». Или чтобы заключить в
него HTML. <section> не является общим контейнером — это работа <div>.
И помните, что нужно использовать <div>, если вы просто группируете эле­
менты в целях стилизации.

<article>

<articie> — это отдельный блок содержимого, которым вы можете захотеть


поделиться с другой страницей или веб-сайтом (или даже со своим псом).
Идеально подходит для блог-постов и новых статей.

<header>

<header> предназначен для верхуш ек элементов вроде <section> И <article>.


<header> также может использоваться в верхней части <body> для создания
основного заголовка страницы .

<footer>

<footer> предназначен для нижней части элементов. Таких элементов, как


<section>, <article> И <div>. Вы МОГЛИ ПОДуМЭТЬ, ЧТО ДОПуСКЭвТСЯ ТОЛЬКО
ОДИН <footer> в странице; на самом деле вы можете использовать его всякий
раз, когда вам будет необходимо разместить содержим ое нижнего колонтитула
в <section> вашей страницы (например, б иограф ические данны е или ссы лки
на некую статью ).

<hgroup>

Это мудреный элемент. В отличие от <header>, который может содержать


любые элементы, связанные с заголовком, <h group> специально предна­
значен ДЛЯ группирования заголовков (<hl>...<h6>) внутри <header>. Хорошо
подходит для структур.

580 приложение
оставшиеся темы

Вебвилльское руководство по сем антическим элементам HTML5

<nav>
<nav> — это навигация, и данный элемент, конечно же, предназначен для ссы-
лок. Но не для любых ссылок: используйте <nav>, когда у вас имеется группа
ссылок, например навигация для вашего сайта или блога. Не используйте его
для одиночных ссылок в параграфах.

< a s id e >

<aside> удобен для размещения всевозможных вещей, которые представляют


собой блоки содержимого, которые находятся вне основного потока вашей стра­
ницы, например сайдбары, выносные цитаты или мысли, пришедшие в голову
позднее.

< tim e >

Ну наконец-то! Здесь речь идет о дате/времени. Вы можете использовать <time>


для определения даты/времени. Не нужно спешить; найдите время и сделайте
все правильно — изучите допустимые форматы для <time>.

< p ro g re s s >

Почти закончили? Да, мы с успехом продвигаемся вперед по этим HTML5-


элементам... <progress> представляет то, насколько далеко вы продвинулись
в завершении выполнения задачи. Используйте немного CSS и JavaScript для
создания красивых эффектов.

< a b b r>

Эй, мистер, обязательно используйте аббревиатуру вместо этого длинного


слова! Это значительно облегчит поиск, поскольку поисковые движки не всегда
настолько сообразительны относительно аббревиатур, как мы.

< m a rk >

Используйте <mark> для пометки слов, например, с целью выделения или редак­
тирования. Данный элемент хорошо подходит для использования в сочетании
с результатами, выдаваемыми поисковыми движками.

дальше ► 581
css3-ceo0cmea

Добавление стиля в ваши новые конструкции с помощью CSS 3

Вебвилльское руководство по CSSS-свойствам


Теперь, когда ваши новые строительные блоки заняли свое место, пора задуматься о дизайне
интерьера. Вам ведь захочется, чтобы все ваши новые конструкции выглядели красиво, не так ли?
Новые свойства
В CSS3 имеется порядочное количество новых свойств, многие из которых делают то, что соз­
датели веб-страниц претворяли в жизнь довольно долго посредством различных витиеватых
манипуляций с HTML, изображениями и JavaScript. Примеры:
_________Д е л а е т э л е м е н т непрозрачным на SO%.
opacity: 0. 5; Создает эф фект закругления
с изгибом величиной в 6 пикселов
border-radius: брх;
в случае с каждым углом.
box-shadow: 5рх 5рх Ю р х #373737;
Тень длиной s пикселов, высотой s пиксе­
лов, размытием с радиусом г о пикселов,
Новые макеты имеющая темно -серый цвет.
Появилась пара новых мощных способов создания макетов страниц с помощью CSS, которые
выходят за рамки обычного позиционирования и намного более просты в применении. Примеры:

display: table; I Эт о даст вам табличный


display: table-cell; м а к ет без HTML-таблиц.

display: flexbox;
Благодаря flexbox вы получает е больший конт роль
flex-order: 1; <- над т е м , как б р аузер будет подходить к р а з м е щ е ­
Новые анимации нию блоков, наприм ер элем ен т ов d iv на странице
Благодаря анимациям у вас есть возможность анимировать переход между значениями свойств.
Например, вы можете сделать так, чтобы что-нибудь исчезало из виду путем перехода из не­
прозрачного состоянии в полупрозрачное: Свойство transition определяет
transition: opacity 0.5s ease-in-out; свойство для перехода в кон­
Задавая для opacity значение О, кретное состояние и выхода из
opacity: 0; п него (в данном случае речь идет
например, о случае наступления
события, инициируемого при на­ о непрозрачности), время, ко­
ведении курсора мыши на элемент, торое будет занимать переход,
мы можем создать анимацию его и функцию замедления, чтобы
исчезновения/появления снова.
он был постепенным.
Новые селекторы
Появилась целая масса новых селекторов, включая nth-child, который позволяет на­
целиваться на специфические дочерние элементы, заключенные в том или ином элементе.
Наконец-то у вас появилась возможность задавать цвет фона чередующихся строк в списке,
не прилагая при этом сумасшедших усилий. ^ п < ~
v v 3 м J Это означает: выдрать? каждый
ul l i : nth-child (2n) { color: gray; } вт орой элем ен т списка и з а ­
дат ь серый цвет фона.

582 приложение
информация о книге «Изучаем программирование на HTML5»

+Выходные сведения

Дизайн всех внутренних макетов был выполнен Эриком 1рименом


и Элизабет Робсон. Кэти Сиерра и Берт Бэйтс придумали стиль оформления
книг из серии «Изучаем...». При производстве данной книги были использованы
программы Adobe InDesign CS и Adobe Photoshop CS.
К числу мест, где осуществлялось написание данной книги, относятся следующие:
Бэйнбридж Айленд, штат Вашингтон; Портленд, штат Орегон; Лас-Вегас, штат Не­
вада; Порт-оф-Несс, Шотландия; Сисайд, штат Флорида; Лексингтон, штат Кентукки;
Туксон, штат Аризона и Анахейм, штат Калифорния. На протяжении долгих дней,
пока мы писали эту книгу, нам придавал силы кофеин в чае «Honest Tea», «GT’s
Kombucha», а также музыка таких исполнителей, как Sia, Sigur Ros, Том Вейте,
OMD, Филип Глас, Muse, Епо, Кришна Дас, Майк Олдфилд, Одра Мэй, Devo, Стив
Роач, Beyman Brothers, Pogo и всех людей на turntable.fm, а также музыка огром­
ной массы исполнителей 1980-х годов, которые вас, возможно, не заинтересуют.

дальше ► 583
/ А вы знаете о нашем веб-сайте? \
^ Там приводятся ответы на не-
которые вопросы из этой книги,
b i н е проЩ а^ с Вами!
а также руководства, из которых можно Заходите на
научиться дополнительным вещам,
и ежедневные обновления вблоге
от авторов! ]
Э. Фримен, Э. Робсон
Изучаем программирование на HTML5
Серия «Head First O’Reilly»

Перевел с английского В. Черник

Заведующий редакцией К. Галицкая


Руководитель проекта Д. Виницкий
Ведущий редактор М. Моисеева
Литературный редактор М. Моисеева
Художник Л. Адуевская
Верстка Е. Леля

ООО «Мир книг», 198206, Санкт-Петербург, Петергофское шоссе, 73, лит. А29.
Налоговая льгота — общероссийский классификатор продукции ОК 005-93, том 2; 95 3005 — литература учебная.
Подписано в печать 10.09.12. Формат 84x108/16. Уел. п. л. 67,200. Тираж 2000. Заказ 0000.
Отпечатано с готовых диапозитивов в типографии «Вятка». 610033, Киров, ул. Московская, 122.

Вам также может понравиться