/
Автор: Янцев В.В.
Теги: информационные технологии вычислительная техника обработка данных программирование информатика учебное пособие язык программирования javascript
ISBN: 978-5-507-44357-4
Год: 2022
Текст
В. В. ЯНЦЕВ
JAVASCRIPT.
КАРТИНКИ, ГАЛЕРЕИ,
СЛАЙДЕРЫ
Учебное пособие
•САНКТПЕТЕРБУРГ•МОСКВА•КРАСНОДАР•
2022
В. В. ЯНЦЕВ
JAVASCRIPT.
КАРТИНКИ, ГАЛЕРЕИ,
СЛАЙДЕРЫ
Учебное пособие
•САНКТПЕТЕРБУРГ•МОСКВА•КРАСНОДАР•
2022
УДК 004
ББК 32.973.4я73
Я 65
Янцев В. В. JavaScript. Картинки, галереи, слайдеры : учебное
пособие для вузов / В. В. Янцев. — СанктПетербург : Лань, 2022. —
252 с. : ил. — Текст : непосредственный.
ISBN 9785507443574
Современные webресурсы невозможно представить без серьезного
иллюстративного материала. В социальных сетях почти любое сообщение
сопровождается фотографиями. Естественно, что важное место в разработке
сайтов занимает вопрос наилучшего представления иллюстраций. Между
тем в литературе по JavaScript этой теме посвящено крайне незначительное
количество материала.
Данная книга призвана ликвидировать этот пробел. В ней приведено
36 примеров сценариев, предназначенных для манипулирования изображе
ниями. Среди них программы для: просмотра и выбора фотографий; вставки
рисунков на страницы; наполнения галерей и автоматических слайдеров;
загрузки картинок на сайт; перемещения фото; создания эффектов для
различных изображений.
Рекомендовано в качестве дополнительной литературы для студентов
вузов, обучающихся по направлению «Информатика и вычислительная
техника».
УДК 004
ББК 32.973.4я73
Обложка
П. И. ПОЛЯКОВА
© Издательство «Лань», 2022
© В. В. Янцев, 2022
© Издательство «Лань»,
художественное оформление, 2022
Оглавление
1. Введение .................................................................................................................. 5
1.1. О чем эта книга ................................................................................................. 5
1.2. Особенности изложения материала ................................................................ 6
1.3. Оформление сценариев .................................................................................... 7
2. Среда разработки .................................................................................................. 9
2.1. Выясняем разрядность ОС ............................................................................... 9
2.2. Установка пакета Visual C++ ......................................................................... 11
2.3. Установка сервера Apache 2.4 ....................................................................... 13
2.4. Установка PHP 8 ............................................................................................. 19
2.5. Установка редактора Notepad++ 8 ................................................................ 22
2.6. Установка файлов zip-архива на локальный хостинг ................................. 27
3. Тестирование программ ..................................................................................... 29
3.1. Тестирование сценариев в браузерах............................................................ 29
3.2. Тестирование сценариев в валидаторах ....................................................... 30
3.3. Кодировка файлов ........................................................................................... 33
4. Элемент img .......................................................................................................... 34
4.1. Атрибут src ...................................................................................................... 35
4.2. Атрибут alt ....................................................................................................... 36
4.3. Атрибут title ..................................................................................................... 37
4.4. Атрибут id ........................................................................................................ 37
4.5. Атрибут class ................................................................................................... 38
4.6. Атрибут style ................................................................................................... 41
4.7. Атрибут draggable ........................................................................................... 42
4.8. Атрибуты ismap и usemap .............................................................................. 43
5. Свойства изображений ....................................................................................... 44
5.1. Размер в документе ......................................................................................... 45
5.2. Рамки ................................................................................................................ 45
5.3. Тени .................................................................................................................. 46
5.4. Непрозрачность ............................................................................................... 48
5.5. Положение на странице.................................................................................. 49
5.6. Положение в линии элементов ...................................................................... 50
5.7. Внешний зазор................................................................................................. 52
5.8. Центрирование по вертикали ........................................................................ 52
5.9. Выравнивание по вертикали .......................................................................... 54
5.10. Видимость ...................................................................................................... 54
5.11. Вид курсора ................................................................................................... 55
5.12. Иерархия ........................................................................................................ 55
5.13. Оттенки серого .............................................................................................. 56
5.14. Вращение ....................................................................................................... 56
5.15. Перспектива ................................................................................................... 57
5.16. Фоновый рисунок.......................................................................................... 59
6. Просмотр фото ..................................................................................................... 60
6.1. Простой просмотр ........................................................................................... 60
3
6.2. Просмотр на фоне ........................................................................................... 62
7. Выбор фото ........................................................................................................... 68
7.1. Выбор для просмотра ..................................................................................... 68
7.2. Увеличиваем непрозрачность ........................................................................ 73
7.3. «Гасим» лишнее .............................................................................................. 77
7.4. Выбор из списка .............................................................................................. 81
7.5. Увеличение и растворение ............................................................................. 84
7.6. Вращаем изображения .................................................................................... 91
7.7. Колонка фотографий ...................................................................................... 95
7.8. Список альбомов ........................................................................................... 100
7.9. Слои вместо фото .......................................................................................... 105
8. Вставка фото ...................................................................................................... 111
8.1. Фото со страниц ............................................................................................ 111
8.2. PHP на помощь .............................................................................................. 118
9. Галереи ................................................................................................................ 123
9.1. Смещаем фото вверх .................................................................................... 123
9.2. Фото по номерам ........................................................................................... 129
9.3. Три галереи .................................................................................................... 134
9.4. Перемотка от центра ..................................................................................... 139
9.5. Перемотка с растворением ........................................................................... 147
9.6. Галерея-аккордеон ........................................................................................ 152
9.7. Галерея с ограничителями ........................................................................... 156
9.8. Замкнутая галерея ......................................................................................... 162
9.9. Оптимальная галерея .................................................................................... 166
10. Автоматические слайдеры ............................................................................ 176
10.1. «Левый» слайдер ......................................................................................... 176
10.2. Слайдер c растворением ............................................................................. 182
11. Загрузка по частям .......................................................................................... 187
11.1. Добавляем снимки ...................................................................................... 187
11.2. Последовательное проявление .................................................................. 191
11.3. Бесконечная лента ....................................................................................... 196
12. Перемещение изображений ........................................................................... 204
12.1. Направляем ракету ...................................................................................... 204
12.2. Перемещаем солнце .................................................................................... 210
12.3. Освещаем пейзаж ........................................................................................ 215
12.4. Тормозим шарики ....................................................................................... 220
13. Эффекты ............................................................................................................ 226
13.1. Пасьянс из картинок ................................................................................... 226
13.2. Раскрашиваем рисунки ............................................................................... 232
13.3. Настраиваем фото ....................................................................................... 234
13.4. Проявляем картинку ................................................................................... 237
13.5. Фото за шторкой ......................................................................................... 244
14. Заключение ....................................................................................................... 250
4
1. Введение
Как и многие программисты старшего поколения, я еще помню то время,
когда в Интернет выходили через модемы, подключенные к телефонным сетям.
Скорость взаимодействия с серверами была такая низкая, что загрузки некоторых документов приходилось ждать по несколько минут. В то время основная
информация содержалась в текстах. Поэтому браузеры, чтобы ускорить получение данных клиентом, имели функцию, позволяющую отключать загрузку
изображений — самых «тяжелых» элементов web-страниц.
На смену телефонным сетям пришли специальные компьютерные сети, которые отличались более высокими скоростями передачи информации. Однако в
первые годы с ними тоже были определенные сложности ⸻ например, ограниченный трафик или его высокая стоимость (в 2005 г. за 1 Гб трафика с довольно
посредственной скоростью я платил своему провайдеру столько же, сколько сегодня плачу за безлимитный высокоскоростной интернет). И вновь сэкономить
можно было, отключая в браузерах загрузку рисунков.
Предполагаю, что именно по этим причинам много лет назад в стандарте
языка разметки HTML появилось правило, согласно которому все теги img
должны иметь обязательный атрибут alt с альтернативным текстом. Он поясняет содержание рисунка, если его демонстрация отключена.
На мой взгляд, отключение изображений в браузерах на сегодняшний день
больше похоже на анахронизм. Времена кардинально поменялись. В современном потоке информации картинки и фотографии являются едва ли не важнейшими элементами. Теперь невозможно представить какой-либо сайт без серьезного иллюстративного материала. В социальных сетях почти любое сообщение
сопровождается фотографиями. Причем чаще всего сообщения короткие, а вот
фотографий к ним прикрепляют от одной штуки до нескольких десятков.
Естественно, что, размещая обилие снимков на web-страницах, разработчики стремятся преподнести иллюстрации в самом лучшем виде. А для этого
создают различные сценарии на JavaScript. Благодаря таким программам рисунки можно увеличивать, преобразовывать, собирать в галереи и даже в автоматические слайдеры.
Автор, занимаясь созданием сайтов, немало времени посвятил разработке
скриптов для управления изображениями. И, накопив богатый опыт, решил поделиться им с начинающими программистами.
1.1. О чем эта книга
За годы работы программистом я прочел очень много книг по JavaScript.
Еще больше бегло просмотрел. И вот какое вынес наблюдение: в тех изданиях,
где приведены не только основы языка, но и даны примеры сценариев, такой
важной теме, как работа с изображениями, либо уделено очень мало внимания,
либо данная тема вообще не рассматривается. И это во времена, когда рисунки
и фотографии занимают господствующее положение в информационном поле!
5
Частично я попытался осветить тему работы с картинками в своих предыдущих учебниках. В «JavaScript. Готовые программы» ей посвящена одна из
глав. В «JavaScript. Обработка событий на примерах» приведен ряд сценариев
для манипулирования изображениями. В «JavaScript. Как писать программы»
тоже есть отдельная глава с 9-ю программами для работы с фото. Однако эти
книги не охватывают весь спектр возможных приемов, доступных программисту при использовании рисунков на сайтах.
Поэтому я решил написать отдельную книгу, целиком посвященную работе с изображениями. Мной ставилась задача показать максимально простые варианты, но в то же время дающие самые разнообразные эффекты. В итоге было
отобрано 36 программ, сгруппированных в 8 тематических глав. Все сценарии
имеют подробные описания, поэтому у читателя не должно возникнуть проблем с пониманием принципов их действия. Скрипты легко повторить и при
необходимости модернизировать. Кроме того, программистам не составит труда внедрить их в свои web-разработки.
На страницах издания вы найдете как объяснения к отдельным фрагментам
сценариев, так и полный код всех программ. Вы также можете упростить изучение материала, скачав по ссылке https://testjs.ru/IMG.zip zip-архив со всеми
примерами. Это позволит вам читать книгу и одновременно наблюдать программы в действии. Кроме того, у вас сразу будут готовые скрипты ⸻ не надо
вручную набирать их код.
В качестве вспомогательного материала в книге даны две небольшие главы
с описанием наиболее важных для разработчика атрибутов тега img и свойств
изображений.
И последнее. Как ясно из названия книги, главное действующее лицо в
ней ⸻ язык программирования JavaScript. Поэтому было бы неплохо, если бы
читатели оказались знакомы с основами и синтаксисом этого языка.
1.2. Особенности изложения материала
В книге четырнадцать глав.
Первая ⸻ «Введение». Вы читаете ее сейчас.
Вторая глава посвящена созданию среды разработки на персональном
компьютере. Если вы хотите скачать zip-архив и экспериментировать на своем
ПК, необходимо создать на нем локальный хостинг, установив несколько программ. Хотя для запуска большинства сценариев достаточно любого браузера,
несколько скриптов будут работать только на реальном или локальном хостинге. Об этом ⸻ в соответствующих разделах.
Из главы 3 вы узнаете, как проверялись и тестировались файлы, представленные в книге. Здесь дана весьма полезная информация, ибо для надежной работы сценариев их надо проверять самым разносторонним образом.
Глава 4 познакомит вас с перечнем атрибутов тега img, которые необходимо указывать, помещая изображения в тело документа. Кроме того, манипулируя данными атрибутами, вы можете создавать скрипты, управляющие графическим материалом страниц.
6
Пятая глава посвящена свойствам стилей изображений. Устанавливая эти
свойства, вы можете представлять картинки самым разным образом: уменьшать
или увеличивать, перемещать, менять прозрачность и цветность, а также выполнять другие манипуляции.
В шестой мы рассмотрим приемы увеличения изображений.
В седьмой собраны несколько программ, предназначенных для выбора фотографий из большого количества размещенных на странице.
Сценарии из главы 8 демонстрируют, как можно добавлять картинки на
сайт.
Девятая глава содержит примеры различных фотогалерей, позволяющих
просматривать изображения в определенном или произвольном порядке.
Глава 10 предлагает вашему вниманию скрипты автоматических слайдеров,
где рисунки меняются без участия посетителя.
Глава 11 рассказывает о поэтапной загрузке изображений в тело документа.
В 12-й главе показано, какими способами можно перемещать фотографии
по странице.
Набор любопытных эффектов для управления изображениями представлен
в главе 13.
И в самой короткой главе 14 мы подведем итоги нашей работы.
На что еще хотел бы обратить внимание читателя: во избежание терминологических споров автор ориентировался на определения, данные на страницах
сайта https://developer.mozilla.org/ru/.
1.3. Оформление сценариев
Сценарии имеют различное типографское оформление в соответствии с их
размещением в тексте.
Если код в книге выделен в отдельный блок, то он оформлен моноширинным шрифтом, например так:
if(e.tagName=="IMG")
{
let b=e.id;
let t=document.getElementById(b).style;
t.transition="opacity 1s";
t.opacity=1;
}
Если фрагменты сценария внедрены непосредственно в текст, то в этом
случае части кода выделены полужирным шрифтом, например так:
условие if(a<7) становится ложным
Обратите внимание: в некоторых блоках программ сделан перенос части кода на вторую и даже на третью строку (из-за недостатка ширины
страницы в книге). В реальном сценарии код записывается одной строкой.
7
Запомните правило: все переносы строк кода существуют только в их типографском воспроизведении. Если вы в дальнейшем столкнетесь с подобной ситуацией, учитывайте данный аспект.
Еще один момент. Обычно таблицы стилей какой-либо страницы принято
записывать следующим образом:
#basis {
position : relative;
margin : auto;
border : #000000 solid 1px;
width : 600px;
height : 400px;
}
Однако подобный код занимает в книге слишком много места. Поэтому
автор применил сокращенную форму записи стилей:
#basis {position: relative; margin: auto;
border: 1px solid #000000;
width: 600px; height: 400px;}
Как видите, экономия налицо: в этом случае вместо семи строк на запись потрачено только три.
И последнее. В описании программ нередко имеет смысл не приводить
весь код, который относится к разбираемому фрагменту, а показывать только ту
его часть, что важна в контексте данных объяснений. Поэтому в таких случаях
автор вводит сокращение в виде трех точек:
...
Например, сокращенный вариант для предыдущего примера с настройками
стилей может выглядеть так:
#basis {... width: 600px; height: 400px;}
Тем самым мы показываем, что на данном этапе описания нам важно обратить
внимание исключительно на размеры элемента.
8
2. Среда разработки
Для написания и тестирования примеров из книги нам в обязательном порядке необходимо создать на своем компьютере локальный хостинг.
Вообще, хостинг ⸻ это, упрощенно говоря, компьютер, предназначенный
для размещения сайтов и обеспечивающий к ним доступ из Интернета. Локальный хостинг ⸻ набор программ на вашем персональном компьютере, которые
позволяют имитировать реальный хостинг и проводить тестирование ваших
сайтов (включая HTML-страницы и серверные скрипты) перед их размещением
в сети. Кстати, обратите внимание: локальный хостинг работает без подключения к Интернету!
Для чего нужен хостинг в нашем случае? Дело в том, что для запуска
большинства рассмотренных в книге примеров достаточно любого браузера.
Для большинства, но не для всех. Некоторые из них заработают только на локальном хостинге. А некоторые, кроме того, взаимодействуют с серверными
скриптами ⸻ для последних хостинг нужен в обязательном порядке.
Чтобы получить результаты, описанные в данной книге, вам понадобится
установить на компьютер распространяемый пакет компонентов Visual C++ от
Microsoft, сервер Apache и интерпретатор PHP. Описание технологии их установки ⸻ в следующих разделах.
Полноценную среду разработки невозможно представить без настоящего
текстового редактора, специально предназначенного для создания программ.
Конечно, весь код можно писать в обычном «Блокноте». Но гораздо лучше и
рациональнее пользоваться специализированными редакторами. Такие приложения намного удобнее: они подсвечивают код, предлагают синтаксические
подсказки, позволяют менять кодировку документов, сохраняют файлы в разных форматах.
В нашем случае необходим редактор, который позволит:
– выполнять качественную разметку;
– создавать файлы с таблицами стилей;
– писать сценарии на JavaScript;
– писать серверные приложения на PHP.
Этим принципам удовлетворяют многие редакторы. Но лучше всего, на
мой взгляд, Notepad++. Где его взять и как установить, рассказано в пятом разделе этой главы.
Итак, вводная часть завершена ⸻ приступим к созданию локального хостинга. А начнем мы с выяснения разрядности вашей ОС.
Обратите внимание: все процедуры описаны для компьютера с операционной системой Windows 10.
2.1. Выясняем разрядность ОС
Перед тем как мы создадим на компьютере среду разработки, необходимо
выяснить разрядность вашей операционной системы, чтобы знать, какие файлы
скачивать для локального хостинга.
9
Включите компьютер, дождитесь полной загрузки операционной системы.
Щелкните на кнопке «Пуск», а затем на кнопке «Параметры» (см. рис. 2.1.1).
В открывшемся окне выберите пункт меню «Система». Откроется следующая
вкладка, в которой необходимо кликнуть на строке «О системе» (или «О программе»). После этого на вкладке «Характеристики устройства» посмотрите
строку «Тип системы» (см. рис. 2.1.2).
Рис. 2.1.1. Кнопка «Параметры» в меню
Рис. 2.1.2. Разрядность или тип операционной системы
10
Типов ОС Windows существует два ⸻ 32-разрядная и 64-разрядная. Запомните разрядность вашей. Это число понадобится трижды: при скачивании
пакета Visual C++, а также zip-архивов сервера Apache и интерпретатора PHP.
2.2. Установка пакета Visual C++
Откройте браузер и зайдите на страницу https://www.apachelounge.
com/download/. Это сайт, с которого мы будем скачивать архив с сервером
Apache. Но сначала надо установить на ваш компьютер компоненты Visual C++,
без которых сервер не заработает.
Для этого найдите на указанной странице текст «Be sure you installed latest
14.29.30037.0 Visual C++ Redistributable for Visual Studio 2015‒2019:
vc_redist_x64 or vc_redist_x86 see Redistributable» (на момент подготовки книги данные строки были последними в описательной части страницы; со временем текст может несколько измениться). Для нас важны две ссылки, расположенные в тексте: vc_redist_x64 и vc_redist_x86. Если у вас 64-разрядная ОС,
нажмите ссылку vc_redist_x64. Если 32-разрядная, необходимо щелкнуть на
ссылке vc_redist_x86 (см. рис. 2.2.1).
Рис. 2.2.1. Ссылки для скачивания пакетов Visual C++
Запустите скачанный файл (см. рис. 2.2.2). Примите условия лицензионного соглашения и нажмите кнопку «Установить». Дождитесь завершения процесса установки (см. рис. 2.2.3). Нажмите кнопку «Закрыть» (см. рис. 2.2.4).
11
Рис. 2.2.2. Начало установки компилятора
Рис. 2.2.3. Процесс установки
Рис. 2.2.4. Завершение установки
12
2.3. Установка сервера Apache 2.4
Теперь скачайте на рабочий стол компьютера с сайта https://www.apache
lounge.com/download/ zip-архив сервера, соответствующий разрядности вашей
ОС (см. рис. 2.3.1). Для 64-разрядной системы ⸻ архив с пометкой Win64
(файл httpd-2.4.48-win64-VS16.zip), для 32-разрядной ⸻ с пометкой Win32
(файл httpd-2.4.48-win32-VS16.zip). Распакуйте архив. Скопируйте папку
Apache24 (только ее) непосредственно на диск C, чтобы ее адрес был
C:\Apache24 (см. рис. 2.3.2).
Рис. 2.3.1. Сайт с zip-архивом сервера
Рис. 2.3.2. Копируем папку Apache24 на диск C
Откройте приложение «Командная строка» от имени администратора. Для
этого нажмите кнопку «Пуск», в меню выберите «Служебные ⸻ Windows»,
найдите пункт «Командная строка» и щелкните на нем правой (правой!) кнопкой мыши. В выпадающем списке выберите «Дополнительно», а затем «Запуск
от имени администратора» (см. рис. 2.3.3). Откроется окно программы.
13
Рис. 2.3.3. Запуск командной строки
Теперь надо инсталлировать, а затем запустить сервер. Для этого в окне
командной строки сразу после
C:\WINDOWS\System32>
наберите
C:\Apache24\bin\httpd.exe -k install
Должно получиться
C:\WINDOWS\System32>C:\Apache24\bin\httpd.exe -k install
Нажмите «Enter». Когда процесс инсталляции закончится (см. рис. 2.3.4), в окне
программы вновь появится строка
C:\WINDOWS\System32>
14
Закройте окно командной строки и перезагрузите компьютер.
ВНИМАНИЕ! Может открыться окно брандмауэра с запросом на разрешение работы «Apache». Разрешите доступ во всех сетях.
Нам надо убедиться, что сервер заработал. Для этого откройте ваш браузер
и введите в строке адреса http://localhost/. Если появилось сообщение «It
works!», значит все в порядке ⸻ сервер функционирует как положено (см. рис.
2.3.5).
Рис. 2.3.4. Инсталляция сервера из приложения «Командная строка»
Рис. 2.3.5. Сервер подтверждает, что он работает
Теперь обратите внимание на один важный момент. Метод, которым мы
установили сервер, позволяет запускать его автоматически при включении
компьютера и завершать его работу при выключении компьютера. То есть
Apache продолжает функционировать, даже если в данное время он вам не нужен. Эта информация вызывает у вас беспокойство по поводу теоретической
уязвимости ПК? Тогда переведите сервер в режим ручного запуска. Для этого
выполните следующие действия:
– введите в строке поиска слово «службы» (см. рис. 2.3.6) и нажмите на
соответствующей иконке, которая появится в списке результатов поиска;
– в открывшемся окне найдите строку «Apache2.4» и щелкните на ней правой (правой!) кнопкой мыши ⸻ появится меню управления службой (см.
рис. 2.3.7);
– кликните на строке «Свойства» и в окне на вкладке «Общие» найдите
список «Тип запуска»;
– выберите пункт «Вручную», затем последовательно нажмите кнопки
«Применить» и «ОК» (см. рис. 2.3.8);
– теперь остановите службу, нажав соответствующую ссылку в левой стороне окна (см. рис. 2.3.9);
15
– дождитесь окончания процесса (см. рис. 2.3.10);
– закройте вкладку «Службы».
Рис. 2.3.6. Находим приложение «Службы»
Рис. 2.3.7. Открываем меню управления службой
16
Рис. 2.3.8. Переводим службу в режим ручного запуска
Рис. 2.3.9. Нажимаем ссылку «Остановить службу»
17
Рис. 2.3.10. Идет процесс остановки Apache
Рис. 2.3.11. Для запуска Apache нажмите ссылку «Запустить службу»
18
Рис. 2.3.12. Идет процесс запуска сервера
Теперь Apache остановлен и переведен в режим ручного запуска. При
необходимости воспользоваться сервером снова зайдите в раздел «Службы»,
выделите строку «Apache2.4» и кликните на ссылке «Запустить службу» (см.
рис. 2.3.11). Подождите окончания процесса (см. рис. 2.3.12).
Продолжаете беспокоиться о безопасности? Можете на время работы с
сервером отключать свой ПК от Интернета. Напомню ⸻ локальный хостинг
работает без сети.
2.4. Установка PHP 8
Скачайте на рабочий стол компьютера с сайта https://windows.php.net/
download/ zip-архив PHP 8, соответствующий разрядности вашей ОС. Для 64разрядной системы ⸻ архив с пометкой x64, для 32-разрядной ⸻ с пометкой
x86. Обратите внимание: так как мы будем устанавливать PHP в качестве модуля сервера Apache, скачивать надо дистрибутив Thread Safe (см. рис. 2.4.1).
Распакуйте архив. Переименуйте распакованную папку на php и переместите ее непосредственно на диск C, чтобы ее адрес был C:\php (см. рис. 2.4.2).
В папке C:\Apache24\conf с помощью текстового редактора «Блокнот» откройте файл httpd.conf (см. рис. 2.4.3), найдите в нем строку
DirectoryIndex index.html
и добавьте к ней
index.php
19
Рис. 2.4.1. Сайт с zip-архивом PHP
Рис. 2.4.2. Перемещаем папку php на диск C
20
Рис. 2.4.3. Файл httpd.conf
Должно получиться
DirectoryIndex index.html index.php
Теперь в самый конец файла httpd.conf добавьте 2 строки:
AddHandler application/x-httpd-php .php
LoadModule php_module "C:/php/php8apache2_4.dll"
Сохраните изменения, закройте файл и перезагрузите компьютер.
Убедимся, что PHP заработал. Для этого в папке C:\Apache24\htdocs создайте текстовый файл и запишите в него следующий код:
<?php
echo "Good !";
Сохраните этот файл под именем, например, test.php. Откройте ваш браузер и введите в строке адреса http://localhost/test.php. Если появилось сообщение «Good !», значит все в порядке ⸻ PHP работает (см. рис. 2.4.4).
Рис. 2.4.4. Проверяем работу PHP
21
2.5. Установка редактора Notepad++ 8
Скачать Notepad++ можно по адресу https://notepad-plus-plus.org/down
loads/ (см. рис. 2.5.1).
Устанавливается редактор следующим образом. Запустите скачанный файл.
В первую очередь появится окно выбора языка программы. Оставляем русский
(см. рис. 2.5.2) и нажимаем кнопку «ОК».
Рис. 2.5.1. Сайт с файлами редактора Notepad++
Рис. 2.5.2. Выбираем язык ПО
В следующем окне нажимаем кнопку «Далее» (см. рис. 2.5.3). Затем нажатием кнопки «Принимаю» соглашаемся с условиями лицензии (см. рис. 2.5.4).
Теперь нам необходимо выбрать папку для установки программы. По
умолчанию предлагается C:\Program Files\Notepad++. Думаю, такой вариант
установки подходит всем, поэтому данную папку оставляем без изменений (см.
рис. 2.5.5).
22
Рис. 2.5.3. Нажимаем кнопку «Далее»
Рис. 2.5.4. Соглашаемся с условиями лицензии
23
Рис. 2.5.5. Выбираем папку для установки программы
Рис. 2.5.6. Здесь ничего не меняем, жмем кнопку «Далее»
24
Дальше будет окно с выбором компонентов, которые можно установить
вместе с программой. Этот раздел предназначен в первую очередь для опытных
программистов, каковыми мы пока не являемся. Поэтому здесь ничего не меняем, жмем кнопку «Далее» (см. рис. 2.5.6).
На последнем этапе перед началом непосредственной установки на вкладке появится пункт «Create Shortcut on Desktop» (см. рис. 2.5.7). То есть нам
предлагают создать ярлык программы на рабочем столе. Делать это или нет ⸻
зависит от вашего желания. Замечу, что после установки редактора ссылка на
него добавится в контекстное меню. Достаточно будет навести указатель мыши
на файл, щелкнуть правой клавишей и в списке возможных действий вы увидите строку «Edit with Notepad++». Кликните по ней, и файл будет открыт в редакторе.
Разобравшись с вопросом, необходим ли ярлык на рабочем столе или нет,
нажмите кнопку «Установить». Дождитесь окончания процесса (см. рис. 2.5.8).
После завершения установки вам нужно будет принять еще одно решение:
сразу запустить программу или отложить это дело «на потом». Для этого
оставьте или снимите «галочку» в пункте «Запустить Notepad++» (см.
рис. 2.5.9). Теперь нажмите кнопку «Готово». Поздравляю ⸻ отныне на вашем
компьютере установлен профессиональный текстовый редактор!
Познакомимся с ним поближе. Как выглядит редактор, вы можете видеть
на рисунке 2.5.10.
Рис. 2.5.7. Нажимаем кнопку «Установить»
25
Рис. 2.5.8. Ждем окончания процесса
Рис. 2.5.9. Завершение установки
26
Notepad++ позволяет:
– выполнять поиск по файлу в разных направлениях;
– производить замену по шаблону;
– устанавливать кодировки, в том числе необходимую для нашего проекта
UTF-8;
– менять страницы, форматируя их по стандартам разных операционных
систем ⸻ Windows, Unix или macOS;
– подсвечивать код, выделяя разные по назначению фрагменты, операторы,
функции, переменные, комментарии и т. д.;
– выбирать синтаксис документа (благодаря чему меняются варианты подсветки кода), например HTML, CSS, JavaScript или PHP;
– сохранять файлы с разным расширением;
– менять стили оформления окна программы ⸻ вариантов достаточно,
найдется любой по желанию;
– выполнять еще многие и многие операции.
Рис. 2.5.10. Редактор Notepad++ с открытым в нем файлом JavaScript
2.6. Установка файлов zip-архива на локальный хостинг
Чтобы не писать все программы самостоятельно, а запускать готовые webстраницы из архива, выполните следующие действия:
– удалите из папки C:\Apache24\htdocs файл index.html, поставляемый
вместе с сервером Apache, и файл test.php, который мы создавали для проверки
работоспособности интерпретатора PHP;
27
– скачайте на рабочий стол компьютера zip-архив, который можно получить по адресу https://testjs.ru/IMG.zip;
– распакуйте архив в папку IMG на рабочем столе;
– скопируйте содержимое папки IMG ⸻ все файлы и каталоги;
– поместите скопированные файлы и каталоги в папку C:\Apache24\htdocs;
– запустите браузер и в строке адреса введите http://localhost/ ⸻ загрузится главная страница нашего проекта, которая содержит ссылки на все 36 программ (см. рис. 2.6.1);
– чтобы посмотреть код любой из страниц, открывайте соответствующие
файлы в редакторе Notepad++.
Рис. 2.6.1. Главная страница проекта, запущенного на локальном хостинге
28
3. Тестирование программ
Как ни хороши современные web-обозреватели, но кое-чем они мне категорически не нравятся. А именно тем, что в них все очень тщательно продумано и предусмотрено. В результате, даже получив некачественный код, браузеры
понимают, чего хотел добиться программист, и демонстрируют правильную
web-страницу. А это провоцирует разработчиков небрежно относиться к своим
обязанностям. В результате миллионы сайтов за красивой оболочкой содержат
множество ошибок и нарушений стандартов, которые web-обозреватели
успешно исправляют.
Удивительно, но даже в ресурсах лидеров мировой web-индустрии ошибок
и нарушений немало.
Большинство из таких сайтов сделаны на популярных «движках», как иногда называют всем известные CMS. Ошибки и отклонения от стандартов заложены у них в модулях, формирующих страницы.
Автор относится к тому немногочисленному отряду программистов, которые выпускают «продукцию» в свет, только добившись абсолютно чистого кода. Поэтому я проверил разметку, стили и сценарии самым тщательным образом. Вот перечень проведенных работ:
– проверка работоспособности сценариев в различных браузерах, в том
числе достижение идентичности результатов показа страниц;
– проверка кода с помощью валидаторов и устранение ошибок.
Подробнее об этом ⸻ в следующих разделах.
3.1. Тестирование сценариев в браузерах
Один из важнейших этапов тестирования файлов со сценариями ⸻ проверка их работоспособности в разных web-обозревателях. Написав программу и
убедившись, что она корректно выполняется в одном браузере, нельзя останавливаться на достигнутом. Ведь может оказаться, что в другом браузере сайт будет работать совсем не так, как вы ожидали.
Чем в большем количестве web-обозревателей проведены испытания, тем
лучше для вашего проекта. Это гарантирует, что все посетители сайта увидят на
его страницах именно то, что вы хотели продемонстрировать.
На мой взгляд обязательный набор разработчика должен включать минимум 5 web-обозревателей. Если вы решили серьезно заниматься webпрограммированием, советую установить на свой компьютер эти браузеры.
Расскажу о них по порядку.
1. Браузер Microsoft Edge. Он входит в состав операционной системы
Windows 10, поэтому не нуждается в скачивании и установке. Многие опытные
программисты не любят данный браузер и игнорируют его при проверке сценариев. Я считаю, что это серьезная ошибка. Дело в том, что Microsoft Edge является браузером по умолчанию в операционной системе Windows 10. Многие
пользователи, не такие продвинутые, как программисты, просто используют то,
29
что у них изначально установлено на ПК. Следовательно, большой процент посетителей Интернета прибегают к услугам Microsoft Edge.
2. Google Chrome. На мой субъективный взгляд ⸻ лучший браузер. И, судя по некоторым опросам, наиболее популярный. Он моложе некоторых своих
конкурентов, но снабжен самыми передовыми решениями и очень быстро развивается. И это не удивительно ⸻ ведь за ним стоит такой гигант, как компания Google. Скачать ПО можно здесь: https://www.google.ru/chrome/.
3. Яндекс.Браузер. После его создания компания Яндекс вложила заметные средства в рекламу и популяризацию своей разработки. Поэтому данный
браузер стоит у многих владельцев компьютеров с ОС Windows. Этих людей
обязательно надо учитывать. Скачать дистрибутив можно здесь:
https://browser.yandex.ru/.
4. Opera ⸻ один из старейших браузеров, существовавших еще во времена борьбы за лидерство между Netscape Navigator и Internet Explorer. В России у него много поклонников. Недаром среди российских пользователей Интернета показатель его популярности в несколько раз выше, чем общемировой
уровень. Кстати, браузер Opera был одним из первых, кто начал поддерживать таблицы стилей. Скачать программное обеспечение можно здесь:
https://www.opera.com/ru.
5. Mozilla Firefox. В этом браузере сценарии необходимо проверять в обязательном порядке. У него достаточно высокий уровень популярности. При
этом есть ряд отличий в обработке кода по сравнению с четырьмя перечисленными выше браузерами. Что-то Mozilla Firefox обрабатывает аналогично
остальным браузерам, а что-то по-своему. Во всяком случае, я неоднократно
сталкивался с ситуациями, когда код, отлично работавший в других браузерах,
начинал «капризничать» в Mozilla Firefox. Скачать браузер можно здесь:
https://www.mozilla.org/ru/firefox/.
И уж совсем идеальной можно считать проверку, которую, кроме всего
прочего, удалось провести на устройствах Apple с операционной системой
macOS и браузером Safari.
3.2. Тестирование сценариев в валидаторах
Валидатор ⸻ это специальная программа для проверки кода, написанного
на одном из языков, предназначенном для создания web-проектов. Задача такой
программы ⸻ найти ошибки, если они есть, и выдать их перечень разработчику
или сообщить, что код безупречный, если ошибок нет.
Можно сказать и по-другому: назначение того или иного валидатора ⸻
проверять код на соответствие стандартам языка программирования.
Стандарты HTML и CSS разрабатывает Консорциум Всемирной паутины ⸻ World Wide Web Consortium (W3C). Он же предоставляет и валидаторы
для проверки разметки страниц и написания таблиц стилей. Вот их адреса в
сети:
– валидатор HTML5 – https://validator.w3.org/;
– валидатор CSS3 – http://jigsaw.w3.org/css-validator/.
30
Данные валидаторы очень удобны. Они позволяют проверять разметку и
таблицы стилей:
– страниц, уже загруженных в сеть;
– файлов, загруженных в валидатор с вашего компьютера;
– в коде, скопированном из вашего файла и помещенном в специальное
текстовое поле.
Например, после обработки кода разметки все ошибки и предупреждения с
комментариями на английском языке появятся на странице HTML-валидатора в
ее нижней части. При этом ошибки будут сопровождаться надписью Error на
розовом фоне, а предупреждения ⸻ надписью Warning на желтом фоне.
Например, строка кода <script type="text/javascript"> получит предупреждение, так как по современным стандартам указывать тип скрипта не надо, но в то
же время данная ошибка не критична, так как не мешает нормальному отображению страницы. Зато следующая строка <img src="img/im1.jpg"> будет отмечена надписью Error, так как у рисунка пропущен обязательный, согласно
стандартам HTML5, атрибут alt.
У HTML-валидатора есть еще одна полезная функция: по завершении проверки он показывает, сколько времени было потрачено на загрузку вашей страницы.
Если ошибок нет, валидаторы сообщат вам об этом. Любопытно заметить,
что о безупречности HTML-кода вы получите простое текстовое подтверждение. А вот качественную таблицу стилей Консорциум Всемирной паутины
предлагает отметить специальным знаком ⸻ что-то вроде знака качества, который вам будет предложено разместить на странице сайта (по крайней мере, так
было на момент написания книги).
Естественно, что разметка и таблицы стилей наших файлов в обязательном
порядке проверялись в этих валидаторах. Результаты такой проверки вы можете видеть на рисунках 3.2.1 и 3.2.2.
Рис. 3.2.1. Проверка кода одного из файлов в HTML валидаторе. Как видите, ошибок нет
31
Рис. 3.2.2. Проверка таблицы стилей одного из файлов в CSS валидаторе. Как видите, и
здесь ошибок нет
Что касается валидатора JavaScript, то здесь ситуация несколько иная. Таких валидаторов много. Я опробовал несколько и выбрал из них вариант, в котором реализован самый строгий подход к оценке кода. Вот его адрес:
https://beautifytools.com/javascript-validator.php.
Он позволяет вставить в специальное текстовое поле ваш код, после чего
сразу, без нажатия каких-либо кнопок, начинается проверка скрипта. Единственное неудобство этого валидатора, обнаруженное мною на момент написания книги, ⸻ сообщения об ошибках, предупреждения и рекомендации он выдает в общем списке, не выделяя пункты этого списка по степени важности.
Думаю, читатели уже догадываются, что все сценарии проекта, написанные на JavaScript, были проверены в данном валидаторе. На момент написания
книги отклонений от стандартов языка и нарушений синтаксиса в сценариях не
было (см. рис. 3.2.3).
Особенность всех упомянутых валидаторов в том, что они находят все
ошибки в разметке, в таблицах стилей, в коде программ, в том числе пропущенные символы, опечатки (но не в обычном тексте), необъявленные переменные и т. д. Понятно, что задача хорошего программиста ⸻ исправить эти
ошибки и получить идеально чистый и правильный код. Что и было сделано
автором.
Автор пытался тестировать и код PHP, но, хотя PHP-валидаторы существуют, ни одного надежного на просторах сети обнаружить не удалось.
32
Рис. 3.2.3. Проверка одного из сценариев. И опять ни одной ошибки
3.3. Кодировка файлов
Создавая примеры, автор сохранял их в кодировке utf-8. Если вы будете самостоятельно писать код, обязательно сохраняйте все файлы ⸻
JavaScript и PHP ⸻ в формате utf-8.
Как это сделать? Откройте редактор Notepad++ и наберите код программы.
Затем в меню редактора кликните закладку «Кодировки» и посмотрите, в каком
формате написан файл. Если не в utf-8, то в открывшемся меню щелкните на
строке «Преобразовать в UTF-8» (см. рис. 3.3.1). Сохраните результаты вашей
работы.
Рис. 3.3.1. Выбор кодировки для файла
33
4. Элемент img
IMG ⸻ тег, необходимый для демонстрации на web-странице фотографий
и рисунков. Название элемента образовано сокращением английского слова
image, что переводится как изображение.
HTML5 не содержит списка форматов картинок, которые должны поддерживаться браузерами в обязательном порядке. Однако все современные webобозреватели работают с наиболее популярными форматами. Это:
– JPEG;
– GIF;
– PNG;
– SVG;
– BMP;
– WEBP;
– ICO.
В сети есть интересная программа, которая позволяет узнать перечень
форматов изображений, поддерживаемых любым браузером. Она находится по
адресу https://bolknote.ru/files/detect-graphics-formats/ (см. рис. 4).
Рис. 4. Проверка поддерживаемых форматов изображений в браузере Google Chrome
В разных web-обозревателях поддерживаемые форматы могут не совпадать. Однако профессиональный разработчик должен ориентироваться только
на такие картинки, которые будут без проблем отображаться во всех наиболее
популярных браузерах.
Тег img ⸻ одинарный, то есть не имеет парного закрывающего тега. Иногда еще говорят, что это пустой элемент, так как он не может содержать внутри
себя никакого контента.
Наиболее простая запись элемента img в разметке страницы выглядит,
например, так:
<img src="pict/ocean.jpg" alt="Тихий океан">
Так как атрибуты src и alt, показанные в данном примере, являются, согласно стандартам HTML5, обязательными, с них мы и начнем рассмотрение
перечня «компонентов» тега, которые считаются наиболее важными для разработчика.
Обратите внимание: в разделах глав 4 и 5 будет демонстрироваться
ряд примеров кода. Все эти примеры даны в максимальном сокращении.
34
4.1. Атрибут src
Данный атрибут содержит адрес изображения. Оно может находиться
непосредственно на сервере с вашим сайтом или на удаленном ресурсе. В первом случае картинку называют внутренней, во втором ⸻ внешней.
Если рисунок находится на текущем сервере в одной из папок, то загрузить
ее на страницу можно способом, показанным в предыдущем разделе:
<img src="pict/ocean.jpg" alt="Тихий океан">
Здесь pict ⸻ папка, находящаяся в рабочей директории вашего сайта.
Если вы добавляете в разметку внешнее фото, то тег img будет выглядеть,
например, следующим образом:
<img src="https://testjs.ru/pict/flower.jpg"
alt="Цветок">
Хочу обратить ваше внимание на один принципиальный момент. Размещая
на своем сайте внешнее фото, будьте предельно внимательными. Дело в том,
что рисунок с чужого ресурса по прошествии времени может быть удален, перемещен, переименован. Более того, внешний ресурс вообще может быть закрыт. И получится, что в один совсем не прекрасный день на какой-то из страниц вашего сайта вместо фотографии окажется крошечная пиктограмма отсутствующего рисунка. Чтобы избежать подобных казусов, регулярно проверяйте
состояние тех страниц, где использованы внешние картинки.
Атрибут src может быть полезен при создании сценариев на JavaScript.
Типичный пример. У вас на странице есть несколько фото небольшого размера:
img {width: 300px;}
...
<img src="pict/im1.jpg" alt="Алтай">
<img src="pict/im2.jpg" alt="Памир">
<img src="pict/im3.jpg" alt="Урал">
При этом в оригинале ширина каждого изображения, допустим, 600 пикселей.
Естественно, что посетителю надо предоставить возможность рассмотреть
снимки в натуральном размере. Для этого вполне подойдет сценарий, «вычисляющий» адрес картинки, на которой кликнул посетитель, и загружающий на
отдельный слой с предустановленным изображением (например, с id="big")
исходное фото:
document.getElementById("big").src=event.target.src;
Кстати, такой прием мы используем в одном из сценариев седьмого раздела.
Добавлю, что разработчик имеет возможность программными методами
заменять рисунки не только на специальных слоях, но и непосредственно в ис35
ходной разметке. Для этого атрибуту src картинки просто присваивается новое
значение.
4.2. Атрибут alt
Об этом атрибуте мы уже говорили в первой главе. В стандарте HTML5
существует правило, согласно которому все теги img должны иметь обязательный атрибут alt с альтернативным текстом. Он поясняет содержание рисунка,
если его демонстрация отключена или невозможна по каким-то причинам.
Во-первых, все современные браузеры позволяют пользователям отключить показ изображений на загружаемых страницах. Во-вторых, загрузка картинок может оказаться невозможной по причинам различных сбоев или повреждений файлов. В обоих случаях web-обозреватели вместо отсутствующих
снимков выводят небольшие пиктограммы и вспомогательный текст. И то и
другое поясняет, какой контент должен был появиться в этом месте страницы.
Альтернативный текст внедряется в код элемента очень просто:
<img src="pict/ocean.jpg" alt="Тихий океан">
Как и в случае с атрибутом src, разработчик может изменить значение alt
программными методами. Такая необходимость возникает, когда в результате
действий пользователя на странице меняется текущее изображение или добавляются новые кадры. В первом случае изменение картинки, естественно, влечет
и замену альтернативного текста. Во втором случае вместе с новыми фото в их
тегах появляются и новые текстовые пояснения.
Специалисты рекомендуют использовать информативные атрибуты alt.
Например, alt="Фото" никак не поможет клиенту понять, какой именно кадр
он не увидел. Зато alt="Тихий океан" более информативен и точен. Сразу ясно,
что можно лицезреть на отсутствующем рисунке. Мы для сокращения кода отступим от данного разумного совета и станем все-таки использовать
alt="Фото". Читатели, адаптируя примеры из книги к своим страницам, легко
внесут необходимые изменения и добавят рисункам подписи alt, соответствующие тематике изображений.
К сожалению, мне не раз приходилось наблюдать, как многие авторы книг
по web-программированию и многие разработчики тех или иных проектов игнорируют использование данного атрибута в теге img. Хотя это и не вызывает
нарушений в работе сайтов и скриптов, однако является грубым нарушением
стандартов. Все равно, что ездить на авто без боковых зеркал. Вы можете ни
разу не попасть в ДТП, но такой автомобиль никогда не пройдет техосмотр или
перерегистрацию в ГИБДД. Думаете, что над создателями сайтов не стоят такие
строгие проверяющие, как в случае с автомобилями? Не исключено, что вы серьезно ошибаетесь. Лично я знаю массу случаев, когда заказчики проверяли
сданный им проект с помощью валидаторов, о которых мы говорили в третьей
главе. В результате разработчики «нарывались» на две неприятности: необходимость доработать проект и штрафные санкции.
36
4.3. Атрибут title
Содержит информацию, которая появляется на экране компьютера при
наведении указателя мыши на тот или иной элемент. Весьма полезный атрибут.
Например, часто используется для создания подсказок, объясняющих клиенту,
какое действие необходимо выполнить или какой результат он может получить,
кликнув по элементу.
Специалисты рекомендуют не копировать в атрибуте title текст атрибута
alt. На мой взгляд, это правильный совет. Действительно, alt предназначен для
альтернативного описания изображения, а title ⸻ для выведения дополнительной информации. То есть у них совершенно разные функции.
Содержание атрибута title очень редко меняют программными методами.
Но иногда такая необходимость все-таки возникает. Представьте, что на странице есть фотография современного вида Красной площади в Москве. При
наведении мыши на снимок появляется подсказка «Кликните на фото, чтобы
посмотреть, как выглядела Красная площадь в начале XX века». Вы щелкаете
мышью и видите новую картинку. Одновременно программными методами меняется и значение атрибута title. Если теперь вновь навести указатель мыши на
изображение, то появится подсказка «Кликните еще раз, чтобы вернуть прежнее изображение».
Добавлю, что в этой книге нет реальных примеров с заменой содержимого
атрибута title. Но написать сценарий, выполняющий подобные действия, не составит труда.
4.4. Атрибут id
Уникальный идентификатор элемента. Один из полезнейших атрибутов
для разработчика. Большинство сценариев, чтобы произвести какое-то действие
с элементом, обращаются к его id.
В разделе 4.1 мы уже демонстрировали пример изменения изображения с
определенным идентификатором:
document.getElementById("big").src=event.target.src;
Таким же образом можно менять свойства изображений: их размеры, непрозрачность, толщину и цвет рамки, положение на странице, ориентацию в
пространстве и другие. Например:
document.getElementById("big").style.opacity=0.5;
Создавая HTML-документ, будьте внимательны при назначении имен
идентификаторов различным элементам. Совпадение идентификаторов у двух
или более тегов неизбежно приведет к незапланированным результатам выполнения сценариев.
Кроме того, используя id, можно в таблице стилей устанавливать элементу
определенные свойства. Допустим, так:
37
#basis {position: relative; margin: auto;
border: 1px solid #000000;
width: 600px; height: 400px;}
...
<div id="basis">
...
</div>
В среде программистов наиболее корректными считаются id, составленные
по таким принципам:
– имя идентификатора должно начинаться с латинской буквы;
– в имени лучше всего использовать латинские буквы, цифры, дефисы и
знаки подчеркивания;
– в имени не должно быть пробелов между символами.
При этом ни одно из упомянутых правил, согласно спецификации глобальных атрибутов HTML5, не является обязательным. Вот цитата из этого документа: «Атрибут id определяет уникальный идентификатор элемента. Других
ограничений на то, какую форму может принимать идентификатор, нет; в частности, идентификаторы могут состоять только из цифр, начинаться с цифры,
начинаться с подчеркивания, состоять только из знаков препинания и т. д.». От
себя автор добавит, что и пробелы тоже можно использовать, согласно определению из спецификации. Автор проверял разные имена id, не совпадающие со
стандартами, принятыми в среде программистов, ⸻ и все они прекрасно работали (в том числе и id с пробелами в именах). Однако на деле лучше все-таки
пользоваться тремя упомянутыми правилами ⸻ они возникли не случайно, а
как результат многолетней практики тысяч программистов, в итоге определивших наиболее оптимальные варианты.
4.5. Атрибут class
Атрибут class содержит имя класса, свойства которого описаны в таблице
стилей. В атрибуте может быть обозначен один класс или список из нескольких
классов, разделенный пробелами, например:
<img ... class="swit but tog">
Селектор по классу применяется в таблицах стилей для описания свойств
группы элементов, у которых атрибуты class имеют одно и то же значение. Это
очень удобное средство сокращения кода.
В таблицах стилей перед описанием класса ставится точка. Вот так:
.swit {width: 100px; height: 30px;
border: 1px solid #0000CC; margin: 20px;}
Разработчики часто используют данный атрибут при одновременном манипулировании элементами с одинаковым значением class. Для этого отлично
38
подходят два метода ⸻ getElementsByClassName и querySelectorAll, которые
возвращают массив элементов с заданным именем класса.
Сначала покажем пример с использованием метода getElementsByClass
Name:
<style>
.fr {width: 300px;}
</style>
<img
<img
<img
<img
src="fr1.jpg"
src="fr2.jpg"
src="fr3.jpg"
src="fr4.jpg"
id="fr1"
id="fr2"
id="fr3"
id="fr4"
class="fr" alt="Фото">
class="fr" alt="Фото">
alt="Фото">
class="fr" alt="Фото">
<script>
addEventListener("click", function()
{
let d=document.getElementsByClassName("fr");
for(let i=0; i<d.length; i++)
document.getElementById(d[i].id).style.width=
"100px";
});
</script>
Здесь из четырех картинок три относятся к классу fr, который устанавливает размер изображений (см. рис. 4.5.1). После клика в любой точке страницы
создается массив элементов данного класса:
let d=document.getElementsByClassName("fr");
Рис. 4.5.1. Три рисунка из четырех относятся к классу fr
39
Затем в цикле происходит изменение размеров фотографий, относящихся к
данному классу (см. рис. 4.5.2):
for(let i=0; i<d.length; i++)
document.getElementById(d[i].id).style.width=
"100px";
Чтобы посмотреть, как работает метод querySelectorAll, надо всего лишь
изменить первую строку функции:
let d=document.querySelectorAll(".fr");
Остальная часть кода осталась без изменений, как и принцип действия программы, а также конечный результат ее выполнения.
Рис. 4.5.2. Снимки, относящиеся к классу fr, изменили размеры
На что надо обратить внимание начинающим разработчикам. Метод
getElementsByClassName принимает в качестве аргумента имя класса, поэтому
оно пишется без точки:
getElementsByClassName("fr")
Метод querySelectorAll принимает в качестве аргумента селектор, поэтому
здесь пишется имя селектора и символ его типа, в данном случае — точка:
querySelectorAll(".fr")
40
Как видите, рассмотренные варианты имеют минимальные различия.
В каждой конкретной ситуации программист сам решает, какой из методов использовать в сценарии.
4.6. Атрибут style
Используется для описания стилей непосредственно в теге элемента.
Например, так:
<img src="fr1.jpg" alt="Фото"
style="width: 200px; border: 2px solid #0000CC;">
Однако в среде программистов установка стилей в теге элемента считается
не самым лучшим тоном. В корпоративных средах принято размещать стили в
заголовочной части документа, а еще лучше — в отдельном файле, который
подключается к текущей странице.
Для начинающих программистов обращу внимание на один важный момент. Помните, в разделе 4.4 у нас был пример строки, устанавливающей определенный уровень непрозрачности изображения:
document.getElementById("big").style.opacity=0.5;
Так вот, для сценария, меняющего свойства элементов, не имеет никакого значения, каким образом были установлены стили и установлены ли они вообще.
Это утверждение хорошо иллюстрирует следующий пример (см. рис. 4.6.1):
Рис. 4.6.1. Страница примера, где трем изображениям размеры установлены разными способами, а четвертое загружается в натуральном виде
41
<style>
.fr {width: 100px;}
#fr2 {width: 150px;}
</style>
<img
<img
<img
<img
src="fr1.jpg"
src="fr2.jpg"
src="fr3.jpg"
src="fr4.jpg"
id="fr1"
id="fr2"
id="fr3"
id="fr4"
class="fr" alt="Фото">
alt="Фото">
style="width: 200px;" alt="Фото">
alt="Фото">
<script>
addEventListener("click", function()
{
for(let i=1; i<5; i++)
document.getElementById("fr"+i).style.width="300px";
});
</script>
Как видите, для первого изображения его размер установлен в стилевом
классе, для второго ⸻ через его id, для третьего ⸻ непосредственно в атрибуте
style, а у четвертого описание стилей вообще отсутствует. Тем не менее при
клике на странице у всех фотографий устанавливается ширина 300 пикселей
(см. рис. 4.6.2).
Рис. 4.6.2. Результат выполнения сценария ⸻ все изображения стали одного размера
4.7. Атрибут draggable
Атрибут устанавливается элементу, который может перетаскиваться посетителем страницы с помощью мыши. Принимает одно из двух значений ⸻ true
или false. draggable="true" разрешает перетаскивание, draggable="false" отменяет.
42
Как и в случаях с другими атрибутами, значение draggable можно менять
программными методами.
Для выполнения перетаскивания, кроме самого элемента, необходим контейнер, в который будет перемещен этот элемент.
В главе 12 у нас будет одна программа, демонстрирующая перетаскивание
изображения с установленным атрибутом draggable.
4.8. Атрибуты ismap и usemap
ismap ⸻ атрибут логического типа, указывающий, что изображение является частью серверной карты ссылок. При этом необходимо, чтобы элемент img
был потомком элемента a с установленным атрибутом href. При клике на рисунке с атрибутом ismap на сервер отправляются текущие координаты мыши.
В зависимости от значений этих координат серверная программа выполняет те
или иные действия.
usemap ⸻ имя карты-изображения, связанной с данным элементом img
(в значении атрибута перед именем карты ставится знак #). Таким образом, значение данного атрибута фактически является неполным URL. Карта создается
тегом map, внутри которого располагаются активные области area. Наглядно
представить код такой карты можно на следующем примере:
<img src="pict/rus.jpg" alt="Карта России"
usemap="#map1">
<map name="map1">
<area href="p1.html" ...>
<area href="p2.html" ...>
...
<area href="pN.html" ...>
</map>
В данной книге нет сценариев, которые используют карты-изображения.
Поэтому подробно останавливаться на атрибутах ismap и usemap мы не станем.
Интересующимся можно порекомендовать ознакомиться с информацией, содержащейся в сети, ⸻ этой теме посвящено немало статей.
43
5. Свойства изображений
Множество свойств, которые мы рассмотрим в данной главе, относятся к
стилевому оформлению изображений. Их можно устанавливать в коде документа и менять программными методами. Но одно свойство ⸻ натуральные
размеры ⸻ имеет отношение не к стилю, а исключительно к исходным параметрам картинки. Хотя в книге нет примеров с использованием такого свойства
в реальных сценариях, мы все-таки коротко коснемся этого вопроса ⸻ вполне
возможно, что информация пригодится вам в дальнейших разработках.
Собственно говоря, если быть точным, речь идет не об одном свойстве, а о
двух:
– naturalWidth ⸻ возвращает естественную ширину изображения;
– naturalHeight ⸻ возвращает естественную высоту изображения.
Ниже приведен несложный сценарий, который вычисляет натуральные
размеры фото (см. рис. 5). Достаточно щелкнуть мышью в любом месте страницы, и появится диалоговое окно с указанием ширины и высоты картинки.
Рис. 5. Программа, определяющая истинный размер изображений
<img src="fr1.jpg" id="fr" alt="Фото">
<script>
addEventListener("click", function()
{
let w=document.getElementById("fr").naturalWidth;
let h=document.getElementById("fr").naturalHeight;
alert(w+" x "+h);
});
</script>
44
Замечу, что с помощью этой программы можно также проверять размеры
изображений, полученных со сторонних ресурсов. Достаточно изменить значение атрибута src, например, так:
<img src="https://testjs.ru/pict/flower.jpg"
id="fr" alt="Фото">
5.1. Размер в документе
Изображение в документе может иметь как фиксированные ширину и высоту, так и меняющиеся в зависимости от размеров окна браузера. Например,
если программист верстает «резиновый» макет сайта, то ему необходимо
предусмотреть возможность увеличения или уменьшения рисунков. Кроме того,
во многих ситуациях требуется установить ограничения на растяжение и сжатие картинок.
Для установки размеров изображений используются следующие свойства.
width ⸻ задает ширину изображения. Если значение указано в пикселях,
то ширина будет фиксированной. Если значение указано в процентах, то ширина будет меняться в зависимости от ширины блока, содержащего изображение.
height ⸻ задает высоту изображения. Если значение указано в пикселях,
то высота будет фиксированной. Если значение указано в процентах, то высота
будет меняться в зависимости от высоты блока, содержащего изображение.
max-width ⸻ определяет максимально возможную ширину изображения.
max-height ⸻ определяет максимально возможную высоту изображения.
min-width ⸻ определяет минимально возможную ширину изображения.
min-height ⸻ определяет минимально возможную высоту изображения.
Необходимо отметить, что разработчику не обязательно указывать в таблице стилей одновременно ширину и высоту картинки. Достаточно задать
только одно свойство, и браузер самостоятельно пропорционально уменьшит
или увеличит рисунок.
Для «резиновых» макетов можно указать в настройках стилей сразу три
параметра, например, исходную, максимальную и минимальную ширину:
img {width: 50%; max-width: 400px; min-width: 300px;}
5.2. Рамки
В этом разделе, применительно к изображениям, нас заинтересуют четыре
параметра рамок: толщина, цвет, тип линии и скругление.
Первые три параметра можно задать, используя сокращенную запись
свойств рамок ⸻ border. Например:
img {border: 1px solid #000000;}
или
img {border: 2px dashed #0000CC;}
45
Для скругления рамок используют свойство border-radius:
img {border-radius: 20px;}
Если применить это свойство, не задавая изображению рамку, то углы фотографии все равно будут скруглены.
Скругление можно задавать для каждого угла отдельно (см. рис. 5.2.1):
img {border-radius: 20px 60px 100px 140px;}
Как видно по картинке, отсчет углов начинается с левого верхнего.
Рис. 5.2.1. Изображение с разными скруглениями для отдельных углов
Мы рассмотрели самые простые варианты создания рамок — именно такие
использованы в некоторых примерах из книги. Но способов оформления рамок
гораздо больше. Например, можно сделать так, что все четыре стороны рамки
будут разного цвета. Или разного типа. Или разной толщины. И не только
это — вы можете получить еще очень много нестандартных оформительских
эффектов. Если данная тема интересна вам, советую проштудировать какойнибудь справочник по CSS.
5.3. Тени
Для создания теней по краям изображений используется свойство boxshadow. Оно определяет параметры тени. Свойство имеет четыре числовых
значения, которые записываются в следующем порядке:
– смещение по горизонтали;
– смещение по вертикали;
46
– расстояние размытия;
– расстояние распространения тени.
Кроме того, есть еще один параметр ⸻ цвет тени. Цветовое значение записывается либо первым пунктом свойства, либо последним.
Экспериментируя со смещениями, расстояниями и цветом, можно получить самые разнообразные варианты теней. На рисунке 5.3.1 показаны два простейших случая. Левая картинка имеет тень по всему периметру, у правой тень
смещена вниз и вправо.
Свойству box-shadow левого снимка установлены следующие значения:
#im1 {box-shadow: 0 0 20px 10px #000000;}
Так как смещения отсутствуют, тень обтекает все фото.
У правого снимка смещения заданы:
#im2 {box-shadow: 20px 20px 20px 10px #000000;}
Рис. 5.3.1. Разные тени у изображений
Чтобы расположить тень слева от рисунка, надо задать отрицательное значение горизонтального смещения:
#im2 {box-shadow: -20px 20px 20px 10px #000000;}
Чтобы расположить тень над рисунком, надо задать отрицательное смещение по вертикали:
#im2 {box-shadow: 20px -20px 20px 10px #000000;}
47
Чтобы расположить тень слева и вверху, надо одновременно задать обоим
смещениям отрицательные значения:
#im2 {box-shadow: -20px -20px 20px 10px #000000;}
Сложной структуры теней можно добиться, указывая в свойстве boxshadow не один набор значений, а несколько, записывая их через запятую,
например, так:
#im1 {box-shadow: 0 0 5px 5px #FFFFFF,
0 0 12px 12px #000000;}
Данный код создаст вокруг изображения белый ореол, а за ним появится тень.
Как выглядит фотография в таком случае, показано на рисунке 5.3.2.
Рис. 5.3.2. Фотография со сложной тенью
5.4. Непрозрачность
По умолчанию, если иное не задано в таблице стилей, все изображения
имеют полную непрозрачность. Когда в процессе манипулирования компонентами страницы надо изменить непрозрачность какого-либо элемента, используют свойство opacity. Его значение задается вещественным числом в интервале от 0 (картинка полностью прозрачна) до 1 (картинка полностью непрозрачна).
Данное свойство оказывается весьма полезным при создании галерей и
слайдеров фотографий. Мы на страницах этой книги напишем несколько сценариев, меняющих непрозрачность изображений.
48
На рисунке 5.4.1 показаны два одинаковых фото с разным уровнем непрозрачности. Левый снимок загружен в режиме «по умолчанию», то есть он полностью непрозрачен. Для правого рисунка уровень непрозрачности 0.3 задан в
таблице стилей:
#im2 {opacity: 0.3;}
Уровень непрозрачности можно изменять как скачкообразно, так и плавно.
В последнем случае разработчики используют свойство transition, задавая через него время растворения.
Рис. 5.4.1. Одинаковые фото с разным уровнем непрозрачности
5.5. Положение на странице
Изображение на странице можно расположить одним из трех способов:
– в потоке элементов документа (когда элементы в разметке страницы просто следуют один за другим и также последовательно отображаются на странице);
– позиционировать как самостоятельный элемент относительно границ документа;
– позиционировать относительно границ вмещающего контейнера, например, слоя div.
Первый способ ⸻ довольно редкий, так как при таком размещении трудно
получить красивую страницу.
В остальных способах используют либо абсолютное позиционирование,
либо относительное. Для этого устанавливают значение свойства position:
49
– absolute ⸻ при этом значении изображение занимает строго фиксированное положение, привязанное к границам документа или вмещающего контейнера и не зависящее от положения остальных элементов;
– fixed ⸻ привязывает рисунок к границам окна браузера, при прокрутке
страницы такая картинка остается на мониторе в одном и том же положении;
– relative ⸻ сначала высчитывается нормальное положение снимка в потоке элементов документа, а затем происходит его смещение на указанные величины ⸻ на экране клиент видит конечный результат.
Для абсолютного и относительного позиционирования используются четыре свойства:
– left ⸻ определяет смещение элемента вправо относительно левого края
документа, вмещающего контейнера или исходного положения;
– right ⸻ определяет смещение элемента влево относительно правого края
документа, вмещающего контейнера или исходного положения;
– top ⸻ определяет смещение элемента вниз относительно верхнего края
документа, вмещающего контейнера или исходного положения;
– bottom ⸻ определяет смещение элемента вверх относительно нижнего
края документа, вмещающего контейнера или исходного положения.
На рисунке 5.5.1 показаны три изображения с абсолютным позиционированием.
Рис. 5.5.1. Три изображения с абсолютным позиционированием
5.6. Положение в линии элементов
Как мы уже говорили, изображение может располагаться естественным
образом в потоке элементов страницы. В таком случае место картинки по
умолчанию ⸻ у левого края документа. Если необходимо сместить фотогра50
фию к правому краю, можно, например, заключить ее в тег p и установить его
свойству text-align значение right:
p {text-align: right;}
...
<p><img src="im1.jpg" alt="Фото"></p>
Если необходимо расположить фотографию по центру, заключите ее в тег p и
установите его свойству text-align значение center:
p {text-align: center;}
Другая ситуация, когда снимок находится в тексте. Чтобы установить его
положение и задать обтекание, используют свойство float. Если его значение
left, то текст будет обтекать рисунок с правой стороны. Если right ⸻ то с левой.
Пример расположения двух картинок с разным значением свойства float
показан на рисунке 5.6.1.
Рис. 5.6.1. Пример расположения двух картинок с разным значением свойства float
Ниже приведен сокращенный код данного примера:
<style>
#fr1 {float: left;}
#fr2 {float: right;}
</style>
...
<p>
<img src="fr1.jpg" id="fr1" alt="Фото">
<img src="fr2.jpg" id="fr2" alt="Фото">
ТЕКСТ
</p>
51
5.7. Внешний зазор
К недостаткам примера из раздела 5.6 можно отнести эффект «прилипания» букв к границам изображений. Чтобы избежать этого, установите картинкам свойство margin. Рисунок, расположенный слева, обтекается текстом справа и внизу. Значит, имеет смысл задать свойства margin-right и margin-bottom:
#fr1 {float: left; margin-right: 30px;
margin-bottom: 20px;}
Правый рисунок обтекается текстом слева и внизу. Ему зададим свойства margin-left и margin-bottom:
#fr2 {float: right; margin-left: 30px;
margin-bottom: 20px;}
В результате страница примет более качественный вид (см. рис. 5.7.1).
Рис. 5.7.1. Вид страницы после установки рисункам свойств margin
5.8. Центрирование по вертикали
Одна из задач, которая очень часто возникает у программиста, ⸻ увеличить маленькое изображение и показать его поверх страницы, причем строго
посередине. Центрировать картинку по горизонтали мы уже умеем (с помощью
свойства text-align со значением center). Теперь хотелось бы научиться центрировать фотографии еще и по вертикали. Добиться такого эффекта можно
разными способами. Рассмотрим два из них. Заодно отметим, что в обоих случаях результат будет совершенно одинаковый. Он показан на рисунке 5.8.1.
Способ первый. Создадим на странице таблицу с единственной ячейкой, в
которой расположим снимок:
<table>
<tr><td>
<img src="fr1.jpg" alt="Фото">
</td></tr>
</table>
52
Рис. 5.8.1. Центрирование изображения в окне браузера
Установим для таблицы следующие свойства:
table {width: 100%; height: 100%; text-align: center;}
Тело таблицы заполнит весь экран (так как свойства width и height имеют
значения 100%). Горизонтальное положение рисунка ⸻ по центру (text-align:
center). Параметры вертикального выравнивания в таблице не указаны. А это
значит, что браузер расположит фотографию в центре также и по вертикали
(так действуют по умолчанию все браузеры).
Второй вариант ⸻ с использованием контейнера div:
<div>
<img src="fr1.jpg" alt="Фото">
</div>
Зададим контейнеру следующие свойства:
div {width: 100%; height: 100%; display: flex;
justify-content: center; align-items: center;}
У нас получился не простой div, а flex-контейнер. Он, как и таблица, заполняет весь экран (width и height ⸻ 100%). Горизонтальное выравнивание
определяется свойством justify-content ⸻ его значение center. Вертикальное ⸻
свойством align-items, его значение также center.
53
5.9. Выравнивание по вертикали
Вертикальное позиционирование в строчных, строчно-блочных элементах
и ячейках таблиц устанавливается свойством vertical-align.
Например, в ячейке таблицы можно поместить изображение в три разных
положения:
– top ⸻ у верхнего края;
– middle ⸻ посередине (устанавливается, как мы уже выяснили, браузером
по умолчанию, если значение vertical-align не указано);
– bottom ⸻ у нижнего края.
Кроме того, изображения можно позиционировать в текстовых строках
(используется, например, для выравнивания пиктограмм, иконок, графических
кнопок). При этом в качестве значений могут указываться не только top, middle
или bottom (последнее ⸻ значение по умолчанию), но и целые положительные
или отрицательные числа. Примеры разных вариантов вертикального позиционирования картинок в текстовых строках показаны на рисунке 5.9.1.
Рис. 5.9.1. Разное положение картинок в строках
5.10. Видимость
Этот раздел очень короткий и касается ситуаций, когда необходимо программными методами скрыть демонстрируемое изображение или, наоборот,
показать скрытое (иногда такие манипуляции совершаются не с самой картинкой, а с родительским контейнером). В этих случаях используют свойство
visibility с одним из двух значений:
– visible ⸻ элемент виден (значение по умолчанию);
– hidden ⸻ элемент не виден.
54
В сценариях из данной книги мы будем часто манипулировать значениями
свойства visibility.
5.11. Вид курсора
Еще один короткий раздел, касающийся всего одного вопроса. Предположим, вам надо показать клиенту, что перед ним фото, на которое можно нажать,
дабы произвести с ним какое-то действие: увеличить, изменить, скрыть и т. д.
Как это сделать? Ответ очень простой ⸻ установить изображению свойство
cursor со значением pointer:
img {cursor: pointer;}
Тогда при наведении мыши на картинку указатель примет вид руки. А это
означает, что перед вами элемент, по которому можно кликнуть.
5.12. Иерархия
Если на странице несколько изображений и они частично или полностью
перекрывают друг друга, необходимо установить порядок их следования или
иерархию. Для этого применяют свойство z-index, которое определяет расположение элементов по оси z, перпендикулярной плоскости отображения.
Например, фотографии собраны «в стопку». В этом случае они имеют
идентичное абсолютное положение, а порядок их следования определяется
свойством z-index:
img {position:
#fr1 {z-index:
#fr2 {z-index:
#fr3 {z-index:
absolute; left: 200px; top: 20px;}
3;}
2;}
1;}
...
<img src="fr1.jpg" id="fr1" alt="Фото">
<img src="fr2.jpg" id="fr2" alt="Фото">
<img src="fr3.jpg" id="fr3" alt="Фото">
Чем выше порядковый номер z-index, тем выше находится картинка.
В нашем примере самой верхней окажется первая (fr1.jpg, z-index: 3), посередине ⸻ вторая (fr2.jpg, z-index: 2), а внизу ⸻ третья (fr3.jpg, z-index: 1).
Другая ситуация, когда фотографии частично перекрывают друг друга.
Сместим их и расставим индексы в обратном порядке:
img {position: absolute; top: 20px;}
#fr1 {left: 50px; z-index: 1;}
#fr2 {left: 200px; z-index: 2;}
#fr3 {left: 350px; z-index: 3;}
Теперь на самом верху окажется третий снимок (см. рис. 5.12.1).
55
Рис. 5.12.1. Расположение картинок при их частичном перекрытии друг другом
5.13. Оттенки серого
Если вы хотите перевести цветное фото в режим «оттенки серого», используйте свойство filter. Для установки режима можно применить следующую запись:
img {filter: grayscale(100%);}
или
img {filter: grayscale(1);}
где grayscale ⸻ функция, определяющая уровень обесцвечивания снимка.
Обычно цветность фотографиям возвращают программными методами.
Для этого задайте в функции grayscale значение 0:
document.getElementById("im").style.filter=
"grayscale(0)";
Если необходимо установить картинке «частичную» цветность, используйте
значения в процентах от 0% до 100% (например, 50%) или дробные числа от 0
до 1 (например, 0.5).
В дальнейшем мы разберем простые варианты манипулирования оттенками серого. Два сценария из книги будут посвящены «раскрашиванию» изображений.
5.14. Вращение
Иногда в качестве оформительского приема дизайнеры немного (а бывает,
и много) поворачивают изображения. Для этого применяют свойство transform,
56
значение которого определяется функцией rotate. На рисунке 5.14.1 показан
пример поворота двух фотографий в разных направлениях: левая повернута по
часовой стрелке, правая ⸻ против.
Рис. 5.14.1. Два изображения повернуты на 45 градусов, но в разные стороны
В таблице стилей такие повороты записаны следующим образом:
#fr3 {transform: rotate(45deg);}
#fr4 {transform: rotate(-45deg);}
Если функция rotate оперирует положительными значениями, поворот выполняется вправо, если отрицательными ⸻ влево.
Также вращение используют как динамический эффект при перемещении
или увеличении картинок. Мы с вами тоже напишем сценарий, который будет
плавно вращать снимок, одновременно увеличивая его размер.
5.15. Перспектива
Очень интересный эффект перспективы можно придать изображению с
помощью свойств perspective и transform. Пример таких «превращений» показан на рисунке 5.15.1.
Для получения данного эффекта понадобилось написать вот такой код
(приводится в сокращении):
<style>
td {perspective: 800px;}
#fr3 {transform: rotateY(30deg);}
57
#fr4 {transform: rotateX(30deg);}
</style>
<table>
<tr>
<td>
<img src="fr3.jpg" id="fr3" alt="Фото">
</td>
<td>
<img src="fr4.jpg" id="fr4" alt="Фото">
</td>
</tr>
</table>
Рис. 5.15.1. Фотографии с эффектом перспективы
Здесь ячейкам таблицы задано свойство perspective: 800px (тем самым мы
как бы устанавливаем расстояние от воображаемого пользователя до плоскости
страницы; чем меньше данное расстояние, тем больше искажение картинки).
Для левого фото установлена перспектива по оси Y (transform:
rotateY(30deg) ⸻ поворот снимка относительно его левого края по горизонтали на заданный угол). Для правого ⸻ по оси X (transform: rotateX(30deg) ⸻
поворот снимка относительно его нижнего края по вертикали на заданный угол).
Если rotateY и rotateX имеют отрицательные значения, то перспектива будет
выглядеть противоположной той, что вы можете наблюдать на рисунке 5.15.1.
Обратите внимание: для получения эффекта перспективы необходимо
свойство perspective прописывать для родительского контейнера, а свойство
transform ⸻ для внутренних элементов.
Свойства perspective и transform позволяют создавать множество других
эффектов. Подробнее об этом лучше прочитать в какой-либо специализированной книге по CSS или на страницах сайта MDN Web Docs:
– https://developer.mozilla.org/ru/docs/Web/CSS/perspective;
– https://developer.mozilla.org/ru/docs/Web/CSS/transform.
58
5.16. Фоновый рисунок
Иногда рисунки применяют не как самостоятельный элемент страницы, а
как фоновое изображение внутри какого-либо контейнера (изображение заднего плана). Для установки фоновой картинки используют как сокращенный вариант описания фона ⸻ свойство background, так и его различные «производные». Нам интересны следующие:
– background-attachment ⸻ определяет, следует ли прокручивать фоновый рисунок или нет;
– background-clip ⸻ определяет в контейнере границу, по которой обрезается фоновый рисунок;
– background-image ⸻ служит для размещения изображений заднего плана;
– background-position ⸻ указывает положение изображений заднего плана;
– background-repeat ⸻ устанавливает, как будет повторяться фоновая
картинка;
– background-size ⸻ задает размеры фоновой картинки.
Комбинирование различных вариантов свойств background позволит вам
создать самые разнообразные варианты заднего плана. Ниже приведен CSS-код
примера, где фон компонуется на основе трех изображений:
body {background-image:
url(fr1.jpg), url(fr3.jpg), url(fr5.jpg);
background-repeat: repeat-y, repeat-y, repeat-y;
background-position: top left, top right, 30% 30%;
background-size: 250px, 500px, 350px;}
Результат показан на рисунке 5.16.1 (картинка сформирована для ширины
окна браузера 1000 пикселей).
Рис. 5.16.1. Фон окна браузера на основе трех изображений
59
6. Просмотр фото
Итак, все приготовления завершены. Мы создали на компьютере рабочую
среду, разобрались, как тестировать программы, узнали, какими атрибутами и
стилевыми свойствами будут манипулировать сценарии из книги. Пора приступать к практике.
Напоминаю, что примеры необходимо смотреть на локальном хостинге.
Для этого необходимо переместить на него файлы из архива книги (как это сделать, подробно рассказано в разделе 2.6). Запустите браузер и в строке адреса
введите http://localhost/ ⸻ загрузится главная страница нашего проекта, которая содержит ссылки на все 36 программ. Просто кликаете по нужной строке
и переходите на страницу того или иного сценария. Все ссылки расположены в
том порядке, в каком следует их описание в книге.
Чтобы читать и одновременно изучать код любой из страниц, открывайте
соответствующие файлы в редакторе Notepad++.
В этой главе мы разберем два элементарных скрипта, выполняющих увеличение маленьких изображений.
6.1. Простой просмотр
Файл full.html.
Как и положено, наш самый первый сценарий является одновременно самым простым. Используя JavaScript, мы будем увеличивать маленькое изображение на весь экран.
Запустите в браузере главную страницу проекта, которая расположена по
адресу http://localhost/. В списке разделов первым идет «Просмотр фото».
Нажмите ссылку Простой просмотр. Запустится страница, на которой представлена одна фотография (см. рис. 6.1.1). Щелкните по снимку. Фон монитора
станет черным, при этом картинка пропорционально заполнит большую часть
экрана (см. рис. 6.1.2). Нажмите клавишу «Escape» («Esc»), и монитор примет
исходный вид.
Страница содержит единственный элемент ⸻ изображение:
<img id="im" src="nat/im1.jpg" alt="Фото">
Код сценария, управляющего процессом его увеличения, очень короткий:
addEventListener("load", function()
{
document.getElementById("im").
addEventListener("click", function()
{
document.getElementById("im").requestFullscreen();
});
});
60
Рис. 6.1.1. Исходный вид страницы
Рис. 6.1.2. Фото развернуто на весь экран
После загрузки страницы
addEventListener("load", function()
{
...
});
61
регистрируем обработчик клика по изображению:
document.getElementById("im").
addEventListener("click", function()
{
...
});
Перевод фото в полноэкранный режим происходит с помощью метода
requestFullscreen:
document.getElementById("im").requestFullscreen();
Вот и все. Согласитесь, что проще не бывает.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Простой просмотр</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
#im {border: 1px solid #000000; width: 300px;
cursor: pointer;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("im").
addEventListener("click", function()
{
document.getElementById("im").requestFullscreen();
});
});
</script>
</head>
<body>
<div id="basis">
<img id="im" src="nat/im1.jpg" alt="Фото">
</div>
</body>
</html>
6.2. Просмотр на фоне
Файл look.html.
Страница из предыдущего примера имеет один существенный недостаток.
Естественный размер фотографии ⸻ 600 на 400 пикселей. Размеры экранов со62
временных компьютеров намного больше. Поэтому и рисунок увеличивается
намного больше истинного размера. А это приводит к потере качества изображения. Подобного недостатка лишен пример, который мы рассмотрим в данном
разделе. Здесь картинка увеличивается только до ее натурального размера.
Как механизм просмотра увеличенного изображения реализован на большинстве сайтов? Примерно вот так: снимок открывается в родительском окне,
посредине экрана, на темном или светлом полупрозрачном фоне. Подобный вариант мы и разберем.
Кликните ссылку Просмотр на фоне. Откроется страница, исходный вид
которой показан на рисунке 6.2.1. Она как две капли воды похожа на страницу
из предыдущего раздела. Но если щелкнуть на фотографии, поверх страницы
появится белый полупрозрачный фон, а на переднем плане по центру экрана
расположится снимок в натуральную величину (см. рис. 6.2.2) ⸻ в нашем случае размером 600 на 400 пикселей. Чтобы завершить просмотр, щелкните мышью на изображении, на любом участке фона или прокрутите ползунок браузера, и страница вернется в исходное состояние.
Как и в предыдущем случае, документ содержит фотографию:
<img id="im" src="nat/im1.jpg" alt="Фото">
Но это не все. Нам еще необходимо:
– добавить слой с белым полупрозрачным фоном;
– добавить слой с большой фотографией;
– сделать фон и большую фотографию временно невидимыми.
Вставляем в документ фоновый слой
<div id="bas"></div>
и слой с изображением натурального размера:
<div id="view">
<img id="pict" src="nat/im1.jpg" alt="Фото">
</div>
В таблице стилей указываем следующие настройки:
#bas, #view {position: absolute; left: 0; top: 0;
width: 100%; height: 100%; visibility: hidden;}
#bas {z-index: 1; background: #FFFFFF;
opacity: 0.95;}
#view {z-index: 2; display: flex;
justify-content: center; align-items: center;}
Таким образом, слои у нас растягиваются на весь экран, а фотография располагается в центре верхнего слоя. Нижний слой с id="bas" имеет белый полупрозрачный фон (background: #FFFFFF и opacity: 0.95), верхний (id="view")
полностью прозрачный, так как свойство background для него не установлено.
63
Рис. 6.2.1. Исходный вид страницы
Рис. 6.2.2. Изображение, увеличенное до натурального размера
В исходном состоянии фон и снимок не видны (visibility: hidden).
Наверное, у многих читателей уже возник вопрос: а почему понадобился
отдельный нижний фоновый слой? Не проще ли обойтись только верхним, указав в его настройках background: #FFFFFF и opacity: 0.95? К сожалению, такой способ нам не подойдет, так как в этом случае изменится прозрачность
большой фотографии (как дочернего элемента верхнего слоя). Она станет «про64
свечивать», чего мы, естественно, не хотим. Поэтому белый фон ⸻ на одном
слое, а фото ⸻ на другом.
Теперь перейдем к сценарию, который управляет просмотром большой
фотографии.
После загрузки документа
addEventListener("load", function()
{
...
});
регистрируем обработчик события прокрутки страницы:
addEventListener("scroll", del);
Функция del скрывает слои по завершении просмотра фотографии. Ее мы опишем чуть позже.
Создадим две переменные для обращения к свойствам слоев (этим мы сокращаем код сценария):
let view=document.getElementById("view");
let bas=document.getElementById("bas").style;
Зарегистрируем еще один обработчик ⸻ щелчок по слою view:
view.addEventListener("click", del);
Этот обработчик тоже запускает функцию del.
При щелчке на маленьком изображении у нас запускается анонимная
функция, управляющая просмотром увеличенного фото:
document.getElementById("im").
addEventListener("click", function()
{
let sc=window.pageYOffset;
bas.top=sc+"px";
view.style.top=sc+"px";
view.style.visibility="visible";
bas.visibility="visible";
});
Первым делом определяется величина прокрутки страницы по вертикали
let sc=window.pageYOffset;
а затем слои смещаются вниз на эту величину:
bas.top=sc+"px";
view.style.top=sc+"px";
Таким образом, слои всегда полностью занимают рабочую часть окна браузера.
65
Теперь можно сделать слои видимыми:
view.style.visibility="visible";
bas.visibility="visible";
В результате мы получаем снимок в натуральную величину посередине
экрана на белом полупрозрачном фоне.
Если прокрутить страницу или щелкнуть на любом участке верхнего слоя,
будет запущена функция del:
function del()
{
view.style.visibility="hidden";
bas.visibility="hidden";
}
Ее задача ⸻ сделать слои опять невидимыми.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Просмотр на фоне</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
#im {border: 1px solid #000000; width: 300px;
cursor: pointer;}
#bas, #view {position: absolute; left: 0; top: 0;
width: 100%; height: 100%; visibility: hidden;}
#bas {z-index: 1; background: #FFFFFF;
opacity: 0.95;}
#view {z-index: 2; display: flex;
justify-content: center; align-items: center;}
#pict {border: 1px solid #000000; cursor: pointer;}
</style>
<script>
addEventListener("load", function()
{
addEventListener("scroll", del);
let view=document.getElementById("view");
let bas=document.getElementById("bas").style;
view.addEventListener("click", del);
document.getElementById("im").
addEventListener("click", function()
{
let sc=window.pageYOffset;
bas.top=sc+"px";
view.style.top=sc+"px";
66
view.style.visibility="visible";
bas.visibility="visible";
});
function del()
{
view.style.visibility="hidden";
bas.visibility="hidden";
}
});
</script>
</head>
<body>
<div id="bas"></div>
<div id="view">
<img id="pict" src="nat/im1.jpg" alt="Фото">
</div>
<div id="basis">
<img id="im" src="nat/im1.jpg" alt="Фото">
</div>
</body>
</html>
67
7. Выбор фото
В предыдущей главе в обоих примерах мы использовали только по одной
фотографии. Теперь нам предстоит изучить несколько случаев, когда на странице много снимков и для детального ознакомления можно выбрать любой из
них.
Мы будем просматривать изображения:
– кликнув по одному из них;
– наведя указатель мыши на одно из них;
– выбрав произвольный пункт из списка (это будет единственный случай,
когда на странице изначально находится только одно фото, которое заменяется
на другое).
7.1. Выбор для просмотра
Файл choi.html.
Мы опробовали простые способы увеличения размеров фотографий при
просмотре. Но они просты и удобны, когда речь идет о единственном снимке на
странице. А если их больше? Как поступить в таком случае? Очень просто: мы
создадим код, который будет использовать одни и те же уже знакомые нам
слои ⸻ view и bas ⸻ для демонстрации разных изображений.
Перейдите по ссылке Выбор для просмотра. Вы увидите страницу с
9 картинами природы (см. рис. 7.1.1). Щелкните на любом снимке. Поверх
страницы появится белый полупрозрачный фон, а на переднем плане по центру
экрана расположится выбранный рисунок в натуральную величину (см.
рис. 7.1.2). Для завершения просмотра щелкните мышью на изображении, на
любом участке фона или прокрутите ползунок браузера, и страница вернется в
исходное состояние.
Разберемся в новом варианте программы.
Теперь у нас на странице 9 фотографий:
<img class="im" src="nat/im1.jpg" alt="Фото">
<img class="im" src="nat/im2.jpg" alt="Фото">
<img class="im" src="nat/im3.jpg" alt="Фото"><br>
<img class="im" src="nat/im4.jpg" alt="Фото">
<img class="im" src="nat/im5.jpg" alt="Фото">
<img class="im" src="nat/im6.jpg" alt="Фото"><br>
<img class="im" src="nat/im7.jpg" alt="Фото">
<img class="im" src="nat/im8.jpg" alt="Фото">
<img class="im" src="nat/im9.jpg" alt="Фото">
Также есть фоновый слой
<div id="bas"></div>
68
и слой с картинкой
<div id="view">
<img id="pict" src="pict/net.jpg" alt="Фото">
</div>
Рис. 7.1.1. Коллекция фотографий на странице
При внимательном изучении приведенного выше фрагмента становится
понятно, что структура верхнего слоя осталась прежней. Но изменилось содержимое тега img. Атрибуту src теперь присвоен адрес pict/net.jpg. Это микроскопическая белая точка размером 1×1 пиксель. По стандартам HTML5 атрибуту src всегда должен быть задан какой-то конкретный адрес. Так как теперь в
исходном состоянии ни один из снимков не загружен в слой view, мы, следуя
правилам, загружаем вместо них нейтральное миниатюрное изображение, которое не видно на белом фоне и быстро заменяется одним из девяти рисунков.
Сценарий новой страницы очень похож на аналогичный из раздела 6.2.
После загрузки документа
addEventListener("load", function()
{
...
});
регистрируем обработчик события прокрутки страницы:
addEventListener("scroll", del);
69
Рис. 7.1.2. Выбранный снимок в натуральную величину
Функция del, как и раньше, скрывает слои по завершении просмотра фотографии.
Создадим две переменные для обращения к свойствам слоев
let view=document.getElementById("view");
let bas=document.getElementById("bas").style;
и одну переменную для обращения к атрибуту src рисунка:
let pict=document.getElementById("pict");
Регистрируем обработчик, завершающий просмотр большого фото после
щелчка по слою view:
view.addEventListener("click", del);
При клике на любом маленьком изображении запускается анонимная
функция:
document.getElementById("basis").
addEventListener("click", function(ev)
{
if(ev.target.tagName=="IMG")
{
let sc=window.pageYOffset;
70
bas.top=sc+"px";
view.style.top=sc+"px";
pict.src=ev.target.src;
view.style.visibility="visible";
bas.visibility="visible";
}
});
В качестве аргумента ev функция получает параметры из интерфейса event
(объекта события).
Сначала определяется величина прокрутки страницы по вертикали
let sc=window.pageYOffset;
а затем слои смещаются вниз на эту величину:
bas.top=sc+"px";
view.style.top=sc+"px";
Присваиваем картинке с верхнего слоя адрес «кликнутого» изображения:
pict.src=ev.target.src;
Теперь можно сделать слои видимыми:
view.style.visibility="visible";
bas.visibility="visible";
В результате мы получаем выбранный снимок в натуральную величину по
центру экрана на белом полупрозрачном фоне.
Если прокрутить страницу или щелкнуть на любом участке верхнего слоя,
будет запущена функция del:
function del()
{
view.style.visibility="hidden";
bas.visibility="hidden";
pict.src="pict/net.jpg";
}
Ее задача ⸻ сделать слои вновь невидимыми, а изображению верхнего слоя
вернуть первоначальный адрес pict/net.jpg. В принципе, последнюю операцию
можно было не выполнять. Но в таком случае при низкой скорости соединения
с сервером вы столкнетесь с неприятным эффектом: допустим, вы посмотрели
один снимок, закрыли фотографию и щелкнули на другом снимке. Вновь запустится режим просмотра, но из-за медленной загрузки второго снимка вы некоторое время будете видеть первый. А это, согласитесь, не очень хорошо. Присваивая src значение pict/net.jpg, мы избавляемся от подобных неприятностей,
ведь маленькая белая точка загружается очень быстро и совершенно не будет
71
видна в момент медленной загрузки второго рисунка. То есть мы просто будем
видеть белый полупрозрачный фон до тех пор, пока не появится новое изображение.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Выбор для просмотра</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
.im {border: 1px solid #000000; width: 300px;
cursor: pointer; margin: 10px;}
#bas, #view {position: absolute; left: 0; top: 0;
width: 100%; height: 100%; visibility: hidden;}
#bas {z-index: 1; background: #FFFFFF; opacity: 0.95;}
#view {z-index: 2; display: flex;
justify-content: center; align-items: center;}
#pict {border: 1px solid #000000; cursor: pointer;}
</style>
<script>
addEventListener("load", function()
{
addEventListener("scroll", del);
let view=document.getElementById("view");
let bas=document.getElementById("bas").style;
let pict=document.getElementById("pict");
view.addEventListener("click", del);
document.getElementById("basis").
addEventListener("click", function(ev)
{
if(ev.target.tagName=="IMG")
{
let sc=window.pageYOffset;
bas.top=sc+"px";
view.style.top=sc+"px";
});
pict.src=ev.target.src;
view.style.visibility="visible";
bas.visibility="visible";
}
function del()
{
view.style.visibility="hidden";
bas.visibility="hidden";
pict.src="pict/net.jpg";
}
});
</script>
</head>
72
<body>
<div id="bas"></div>
<div id="view">
<img id="pict" src="pict/net.jpg" alt="Фото">
</div>
<div id="basis">
<img class="im" src="nat/im1.jpg" alt="Фото">
<img class="im" src="nat/im2.jpg" alt="Фото">
<img class="im" src="nat/im3.jpg" alt="Фото"><br>
<img class="im" src="nat/im4.jpg" alt="Фото">
<img class="im" src="nat/im5.jpg" alt="Фото">
<img class="im" src="nat/im6.jpg" alt="Фото"><br>
<img class="im" src="nat/im7.jpg" alt="Фото">
<img class="im" src="nat/im8.jpg" alt="Фото">
<img class="im" src="nat/im9.jpg" alt="Фото">
</div>
</body>
</html>
7.2. Увеличиваем непрозрачность
Файл transp.html.
В этом примере мы не станем увеличивать фото, а будем просто выделять
интересующий нас кадр из остальных, присутствующих в документе.
Перейдите по ссылке Увеличиваем непрозрачность. Вы увидите 9 полупрозрачных изображений с картинами природы (см. рис. 7.2.1).
Наведите указатель мыши на один из рисунков. Его вид плавно изменится.
В течение одной секунды он из полупрозрачного станет полностью ярким и
четким. При этом остальные по-прежнему будут еле видны (см. рис. 7.2.2). Тем
самым мы получили желаемый результат, выделив одну фотографию. Если теперь переместить указатель мыши с выбранной фотографии, она вновь станет
полупрозрачной, а страница примет исходный вид.
В теле документа прописаны теги 9 изображений:
<img id="i1" class="im" src="nat/im1.jpg" alt="Фото">
<img id="i2" class="im" src="nat/im2.jpg" alt="Фото">
<img id="i3" class="im" src="nat/im3.jpg" alt="Фото">
<br>
<img id="i4" class="im" src="nat/im4.jpg" alt="Фото">
<img id="i5" class="im" src="nat/im5.jpg" alt="Фото">
<img id="i6" class="im" src="nat/im6.jpg" alt="Фото">
<br>
<img id="i7" class="im" src="nat/im7.jpg" alt="Фото">
<img id="i8" class="im" src="nat/im8.jpg" alt="Фото">
<img id="i9" class="im" src="nat/im9.jpg" alt="Фото">
73
Рис. 7.2.1. Исходный вид страницы
Рис. 7.2.2. Выбранное фото становится ярким и четким
74
Всем рисункам установлен уровень непрозрачности 0.2:
.im {... opacity: 0.2; ... }
Сценарий обрабатывает 2 события: mouseover и mouseout. Для сокращения программы используем в качестве обработчиков стрелочные функции:
addEventListener("mouseover", (ev)=>
{
...
});
addEventListener("mouseout", (ev)=>
{
...
});
В качестве аргумента ev функции будут получать параметры из интерфейса
event (объекта события).
Как видите, оба обработчика приписаны к событиям уровня окна. Такой
подход выбран, чтобы не регистрировать множество обработчиков для каждого
фото в отдельности. Поэтому первое, что делается внутри стрелочных функций, — это определяется, произошло ли событие именно на картинке:
let e=ev.target;
if(e.tagName=="IMG")
{
...
}
Приведенный фрагмент одинаков для обеих функций. Отличается «начинка» внутри тела каждого из условий.
Если указатель мыши оказался наведен на один из рисунков, определяем
его id:
let b=e.id;
Затем вводим переменную t для сокращения кода
let t=document.getElementById(b).style;
и плавно в течение 1 секунды увеличиваем непрозрачность фотографии до 1:
t.transition="opacity 1s";
t.opacity=1;
Если указатель мыши покидает границы изображения, происходит почти
то же самое: определяется id рисунка, после чего изображение вновь плавно в
течение 2 секунд меняется, только теперь уже «растворяясь»:
75
let t=document.getElementById(b).style;
t.transition="opacity 2s";
t.opacity=0.2;
Обращаю ваше внимание, что время проявления 1 секунда и растворения
2 секунды выбраны экспериментальным путем. По мнению автора, при таких
настройках данные эффекты смотрятся лучше всего.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Увеличиваем непрозрачность</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
.im {width: 300px; border: 1px solid #000000;
opacity: 0.2; margin: 10px;}
</style>
<script>
addEventListener("mouseover", (ev)=>
{
let e=ev.target;
if(e.tagName=="IMG")
{
let b=e.id;
let t=document.getElementById(b).style;
t.transition="opacity 1s";
t.opacity=1;
}
});
addEventListener("mouseout", (ev)=>
{
let e=ev.target;
if(e.tagName=="IMG")
{
let b=e.id;
let t=document.getElementById(b).style;
t.transition="opacity 2s";
t.opacity=0.2;
}
});
</script>
</head>
<body>
<div id="basis">
<img id="i1" class="im" src="nat/im1.jpg" alt="Фото">
<img id="i2" class="im" src="nat/im2.jpg" alt="Фото">
76
<img id="i3" class="im" src="nat/im3.jpg" alt="Фото">
<br>
<img id="i4" class="im" src="nat/im4.jpg" alt="Фото">
<img id="i5" class="im" src="nat/im5.jpg" alt="Фото">
<img id="i6" class="im" src="nat/im6.jpg" alt="Фото">
<br>
<img id="i7" class="im" src="nat/im7.jpg" alt="Фото">
<img id="i8" class="im" src="nat/im8.jpg" alt="Фото">
<img id="i9" class="im" src="nat/im9.jpg" alt="Фото">
</div>
</body>
</html>
7.3. «Гасим» лишнее
Файл select.html.
В этом примере мы опять не станем увеличивать фото, а рассмотрим сценарий, который при выделении одного рисунка меняет вид остальных.
Перейдите по ссылке «Гасим» лишнее. Вы увидите 9 изображений (см.
рис. 7.3.1).
Наведите указатель мыши на одну из картинок. Ее вид не изменится. А вот
остальные плавно «растворятся», да так, что будут еле видны (см. рис. 7.3.2).
Тем самым мы выделили одно изображение на фоне остальных. Если теперь
переместить указатель мыши с выбранной фотографии, остальные снимки
вновь станут полностью непрозрачными.
В новом примере, как и в предыдущем, все те же 9 фотографий. Уровень
непрозрачности для них в таблице стилей не указан, а это значит, что он устанавливается по умолчанию и равен 1.
В сценарии этой программы обрабатывается только одно событие ⸻
mouseover.
Опять мы используем стрелочную функцию
addEventListener("mouseover", (ev)=>
{
...
});
Первым делом проверяем, где событие произошло:
if(e.tagName=="IMG")
{
...
}
else
{
...
}
77
Рис. 7.3.1. Исходный вид страницы
Данные об этом мы получаем из интерфейса event:
let e=ev.target;
Если выясняется, что указатель мыши был наведен на одну из картинок, то
начинается выполнение первого блока условного выражения:
if(e.tagName=="IMG")
{
...
}
Определим id рисунка:
e.id
Таким образом мы узнаем, какой из рисунков останется в неизменном виде.
Остальные надо сделать менее заметными.
Для этого в первой части условного выражения напишем цикл, в котором
все картинки, кроме выделенной, будут «мутнеть»:
for(let i=1; i<10; i++)
{
let b="i"+i;
78
if(e.id!=b)
{
let t=document.getElementById(b).style;
t.transition="opacity 1s";
t.opacity=0.1;
}
}
Рис. 7.3.2. «Лишние» фото стали полупрозрачными
Поскольку рисунков 9, то условие выполнения цикла ⸻ i<10.
В каждом проходе мы вычисляем id очередного рисунка:
let b="i"+i;
Если текущий id не совпадает с id выделенного изображения
e.id!=b
то происходит плавное «растворение» очередного пейзажа в течение одной секунды:
if(e.id!=b)
{
let t=document.getElementById(b).style;
t.transition="opacity 1s";
t.opacity=0.1;
}
79
Как видите, здесь мы меняем значение свойства opacity, которое отвечает
за уровень непрозрачности элемента.
Обратите внимание: картинки «растворяются» одновременно, а не последовательно друг за другом, как могут предположить некоторые читатели.
Теперь представим, что мы переместили указатель мыши с картинки на
свободное пространство страницы. Тогда станет выполняться вторая часть
условного выражения
else
{
for(let i=1; i<10; i++)
{
let b="i"+i;
let t=document.getElementById(b).style;
t.transition="opacity 2s";
t.opacity=1;
}
}
В этой ситуации на каждом проходе мы плавно возвращаем каждое изображение к исходному уровню максимальной непрозрачности. Здесь выделенный рисунок можно не исключать из цикла for.
При наведении указателя мыши на другое изображение все будет происходить точно таким же образом.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>"Гасим" лишнее</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
.im {width: 300px; border: 1px solid #000000;
margin: 10px;}
</style>
<script>
addEventListener("mouseover", (ev)=>
{
let e=ev.target;
if(e.tagName=="IMG")
{
for(let i=1; i<10; i++)
{
let b="i"+i;
if(e.id!=b)
{
let t=document.getElementById(b).style;
t.transition="opacity 1s";
t.opacity=0.1;
}
}
80
}
else
{
for(let i=1; i<10; i++)
{
let b="i"+i;
let t=document.getElementById(b).style;
t.transition="opacity 2s";
t.opacity=1;
}
}
});
</script>
</head>
<body>
<div id="basis">
<img id="i1" class="im" src="nat/im1.jpg" alt="Фото">
<img id="i2" class="im" src="nat/im2.jpg" alt="Фото">
<img id="i3" class="im" src="nat/im3.jpg" alt="Фото">
<br>
<img id="i4" class="im" src="nat/im4.jpg" alt="Фото">
<img id="i5" class="im" src="nat/im5.jpg" alt="Фото">
<img id="i6" class="im" src="nat/im6.jpg" alt="Фото">
<br>
<img id="i7" class="im" src="nat/im7.jpg" alt="Фото">
<img id="i8" class="im" src="nat/im8.jpg" alt="Фото">
<img id="i9" class="im" src="nat/im9.jpg" alt="Фото">
</div>
</body>
</html>
7.4. Выбор из списка
Файл option.html.
Единственная программа в данной главе, где на странице в исходном состоянии представлен только один рисунок.
Кликните ссылку Выбор из списка. Вы увидите страницу, на которой есть
крупное изображение лесной дороги, а под ним выпадающий список с названиями других фотографий (см. рис. 7.4.1). Выберите интересующую вас картинку
из списка, и она появится вместо исходной (см. рис. 7.4.2). Как видите, программа максимально простая.
В теле документа прописаны теги одного изображения
<img src="nat/im1.jpg" id="photo" alt="Фото">
и выпадающего списка с перечнем фотографий, которые могут быть предложены вниманию посетителя:
81
<select id="sel"><option selected value="1">Лес
</option>
<option value="3">Небо</option>
<option value="4">Бабочки</option>
<option value="5">Роса</option>
<option value="10">Мостик</option>
<option value="22">Залив</option></select>
Рис. 7.4.1. Исходный вид страницы с фотографией леса
Рис. 7.4.2. На странице появилось новое изображение, выбранное из списка
82
В качестве значений использованы числовые индексы перечисленных
снимков.
После загрузки страницы
addEventListener("load", function()
{
...
});
мы регистрируем обработчик события change для выпадающего списка. Роль
обработчика у нас выполняет анонимная функция
document.getElementById("sel").
addEventListener("change", function()
{
let a=document.getElementById("sel").value;
document.getElementById("photo").src=
"nat/im"+a+".jpg";
});
Функция содержит всего две инструкции. Сначала мы получаем значение,
выбранное в списке:
let a=document.getElementById("sel").value;
А затем присваиваем исходному рисунку новый адрес:
document.getElementById("photo").src=
"nat/im"+a+".jpg";
Вот и все.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Выбор из списка</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
#sel {width: 200px; font-size: 20px;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("sel").
addEventListener("change", function()
{
let a=document.getElementById("sel").value;
document.getElementById("photo").src=
"nat/im"+a+".jpg";
83
});
});
</script>
</head>
<body>
<div id="basis">
<img src="nat/im1.jpg" id="photo" alt="Фото"><br><br>
<select id="sel"><option selected value="1">Лес
</option>
<option value="3">Небо</option>
<option value="4">Бабочки</option>
<option value="5">Роса</option>
<option value="10">Мостик</option>
<option value="22">Залив</option></select>
</div>
</body>
</html>
7.5. Увеличение и растворение
Файл raising.html.
Разберем следующий пример выделения изображений из галереи картинок.
Чтобы посмотреть сценарий в действии, кликните ссылку Увеличение и растворение.
Внешний вид страницы показан на рисунке 7.5.1. Щелкните указателем
мыши на любом рисунке и вы увидите, как он плавно увеличится в размерах и
одновременно сместится в центр (см. рис. 7.5.2). При этом оставшиеся фото не
менее плавно исчезнут (см. рис. 7.5.3). В таком состоянии страница может
находиться сколь угодно долго. Чтобы вернуть ей исходный вид, вторично
щелкните по увеличенной картинке. Она уменьшится и займет свое место, а
остальные рисунки вновь станут видны. И опять все изменения произойдут
плавно. Так можно увеличивать и просматривать любые картинки, находящиеся на странице.
С чем мы имеем дело?
В основе страницы ⸻ 6 фотографий:
<img
<img
<img
<img
<img
<img
id="i1"
id="i2"
id="i3"
id="i4"
id="i5"
id="i6"
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
src="nat/im6.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
Для всех из них задано абсолютное позиционирование
.im {position: absolute; ... z-index: 1;}
84
Рис. 7.5.1. Исходный вид страницы
с привязкой к конкретным точкам:
#i1
#i2
#i3
#i4
#i5
#i6
{left:
{left:
{left:
{left:
{left:
{left:
10px; top: 10px;}
322px; top: 10px;}
634px; top: 10px;}
10px; top: 220px;}
322px; top: 220px;}
634px; top: 220px;}
Сценарий начинается с объявления трех глобальных переменных:
let y=1;
let w=0;
let h=0;
Переменная y выполняет роль идентификатора кликов. Она позволяет сценарию определить ⸻ первый или второй щелчок был на рисунке. То есть увеличивать изображение или, наоборот, уменьшать. Если y принимает значение 1,
это означает первый клик, если 2 ⸻ второй.
Переменные w и h нужны для временного хранения координат рисунка, на
котором произошел клик, чтобы программа «знала», куда возвращать эту картинку.
Далее мы регистрируем обработчик события click уровня окна:
addEventListener("click", ...);
85
И опять, как и в некоторых предыдущих случаях, используем функциюстрелку
Рис. 7.5.2. Выбранный снимок начинает увеличиваться и смещаться к центру, а остальные
«растворяются»
addEventListener("click", (ev)=>
{
...
});
Так как обращений к интерфейсу event будет несколько, сократим код,
объявив переменную e:
let e=ev.target;
Проверяем, где выполнен клик:
if(e.tagName=="IMG")
Если на одной из картинок, то выполняются программные блоки функции.
В ее теле мы неоднократно станем обращаться к стилевым параметрам
изображения, на котором был сделан щелчок. Поэтому для сокращения кода
объявим переменную t:
let t=document.getElementById(e.id).style;
86
Рис. 7.5.3. Изображение заняло центральное положение, остальные картинки в это время
не видны
Если на данной картинке случился первый щелчок
if(y==1)
то последовательно выполняются следующие инструкции. Сначала выясняются
координаты рисунка относительно границ слоя-контейнера:
let d=document.getElementById(e.id);
w=d.offsetLeft;
h=d.offsetTop;
Затем переменной-идентификатору присваивается новое значение:
y=2;
Дальше стартует цикл, в котором выполняются операции «растворения»
остальных изображений:
for(let i=1; i<7; i++)
{
let b="i"+i;
if(e.id!=b)
{
let p=document.getElementById(b).style;
87
}
p.transition="opacity 1s";
p.opacity=0;
}
Как видите, за счет условия
if(e.id!=b)
«растворяются» лишь те фото, id которых не совпадает с id выбранного.
Одновременно с этим процессом меняется состояние «главного действующего лица». Сначала увеличивается z-index картинки, чтобы она в процессе
движения располагалась поверх остальных рисунков:
t.zIndex=2;
Потом одновременно плавно увеличиваем ее размер и смещаем к центру
страницы:
t.transition="width 1s, left 1s, top 1s";
t.width=600+"px";
t.left=200+"px";
t.top=100+"px";
Суммарно результат выполнения первой части условного выражения выглядит именно так, как описано в начале этого раздела: незадействованные
снимки растворяются, а помеченный увеличивается и смещается в центр, оказываясь в одиночестве на белом фоне.
Снова щелкнем на изображении. Теперь выполняется вторая часть условного выражения:
else
{
...
}
Первым делом изменится значение, хранящееся в идентификаторе:
y=1;
Потом стартует цикл, в котором фоновые снимки «проявляются» вновь,
так как меняется значение их непрозрачности:
for(let i=1; i<7; i++)
{
let b="i"+i;
let p=document.getElementById(b).style;
p.transition="opacity 2s";
p.opacity=1;
}
88
После чего запускается процесс уменьшения и обратного перемещения
просмотренного рисунка в точку, которая определена координатами, сохраненными в переменных w и h:
t.transition="width 1s, left 1s, top 1s";
t.width=300+"px";
t.left=w+"px";
t.top=h+"px";
В последнюю очередь меняется свойство z-index. Оно возвращается к исходному значению:
t.zIndex=1;
Так как идентификатор в данный момент хранит единицу, сценарий готов
обработать следующий щелчок и увеличить любую другую картинку (или ту же
самую).
На этом описание работы программы завершено.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Увеличение и растворение</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
.im {position: absolute; width: 300px;
border: 1px solid #000000;
cursor: pointer; z-index: 1;}
#i1 {left: 10px; top: 10px;}
#i2 {left: 322px; top: 10px;}
#i3 {left: 634px; top: 10px;}
#i4 {left: 10px; top: 220px;}
#i5 {left: 322px; top: 220px;}
#i6 {left: 634px; top: 220px;}
</style>
<script>
let y=1;
let w=0;
let h=0;
addEventListener("click", (ev)=>
{
let e=ev.target;
if(e.tagName=="IMG")
{
let t=document.getElementById(e.id).style;
if(y==1)
{
89
let d=document.getElementById(e.id);
w=d.offsetLeft;
h=d.offsetTop;
y=2;
for(let i=1; i<7; i++)
{
let b="i"+i;
if(e.id!=b)
{
let p=document.getElementById(b).style;
p.transition="opacity 1s";
p.opacity=0;
}
}
t.zIndex=2;
t.transition="width 1s, left 1s, top 1s";
t.width=600+"px";
t.left=200+"px";
t.top=100+"px";
}
else
{
y=1;
for(let i=1; i<7; i++)
{
let b="i"+i;
let p=document.getElementById(b).style;
p.transition="opacity 2s";
p.opacity=1;
}
t.transition="width 1s, left 1s, top 1s";
t.width=300+"px";
t.left=w+"px";
t.top=h+"px";
t.zIndex=1;
}
}
});
</script>
</head>
<body>
<div id="basis">
<img
<img
<img
<img
<img
<img
id="i1"
id="i2"
id="i3"
id="i4"
id="i5"
id="i6"
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
src="nat/im6.jpg"
</div>
</body>
</html>
90
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
7.6. Вращаем изображения
Файл rotate.html.
Новая программа имеет много общего с предыдущей, за исключением того, что она дополнена одним интересным эффектом.
Перейдем с главной страницы по ссылке Вращаем изображения. Опять
перед нами 6 картинок (см. рис. 7.6.1). Щелкните указателем мыши на любом
рисунке и вы увидите, как он плавно увеличится в размерах и сместится в центр
(см. рис. 7.6.2). Но не просто сместится, а одновременно совершив разворот на
360°. При этом оставшиеся фото плавно исчезнут (см. рис. 7.5.3). Чтобы вернуть странице исходный вид, вторично щелкните по увеличенной картинке.
Она уменьшится и займет свое место, совершив обратный разворот, а остальные рисунки вновь станут видны. И опять все изменения произойдут плавно.
Так можно увеличивать и просматривать любые картинки, находящиеся на
странице.
Количество, адреса фотографий, их настройки полностью совпадают с теми, что мы видели в программе из предыдущего раздела. И сценарии очень похожи, за небольшими дополнениями, которые мы и разберем.
Итак, после того, как вы кликнули на выбранном изображении, начинают
выполняться уже знакомые нам инструкции. Определяем, что щелчок был на
рисунке, затем запоминаем начальные координаты нужного снимка, после чего
«растворяем» остальные фотографии. Так происходит до тех пор, пока не придет черед манипуляций с выбранной картинкой. На этом этапе возникают дополнения.
Рис. 7.6.1. Страница в исходном состоянии
91
Рис. 7.6.2. Выбранный снимок начинает увеличиваться и смещаться к центру с одновременным вращением, а остальные «растворяются»
Во-первых, в настройках свойства transition помимо размера и координат
мы устанавливаем значение параметра transform:
t.transition="width 1s, left 1s, top 1s,
transform 1s";
Во-вторых, задаем величину, на которую будет выполнен поворот рисунка (на 360° ⸻ то есть рисунок совершит один полный оборот вокруг своей оси):
t.transform="rotate(360deg)";
Благодаря этим дополнениям наше фото перемещается в центр с одновременным вращением.
Движение в обратном направлении, на исходную позицию, тоже сопровождается вращением снимка:
t.transition="width 1s, left 1s, top 1s,
transform 1s";
...
t.transform="rotate(0deg)";
92
Только сейчас, как вы видите, картинка вращается в противоположную сторону:
rotate(0deg)
Рис. 7.6.3. Изображение заняло центральное положение, остальные картинки в это время
не видны
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Вращаем изображения</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
.im {position: absolute; width: 300px;
border: 1px solid #000000;
cursor: pointer; z-index: 1;}
#i1 {left: 10px; top: 10px;}
#i2 {left: 322px; top: 10px;}
#i3 {left: 634px; top: 10px;}
#i4 {left: 10px; top: 220px;}
#i5 {left: 322px; top: 220px;}
#i6 {left: 634px; top: 220px;}
</style>
<script>
let y=1;
let w=0;
93
let h=0;
addEventListener("click", (ev)=>
{
let e=ev.target;
if(e.tagName=="IMG")
{
let t=document.getElementById(e.id).style;
if(y==1)
{
let d=document.getElementById(e.id);
w=d.offsetLeft;
h=d.offsetTop;
y=2;
for(let i=1; i<7; i++)
{
let b="i"+i;
if(e.id!=b)
{
let p=document.getElementById(b).style;
p.transition="opacity 1s";
p.opacity=0;
}
}
t.zIndex=2;
t.transition="width 1s, left 1s, top 1s,
transform 1s";
t.width=600+"px";
t.left=200+"px";
t.top=100+"px";
t.transform="rotate(360deg)";
}
else
{
y=1;
for(let i=1; i<7; i++)
{
let b="i"+i;
let p=document.getElementById(b).style;
p.transition="opacity 2s";
p.opacity=1;
}
}
});
t.transition="width 1s, left 1s, top 1s,
transform 1s";
t.width=300+"px";
t.left=w+"px";
t.top=h+"px";
t.transform="rotate(0deg)";
t.zIndex=1;
}
94
</script>
</head>
<body>
<div id="basis">
<img
<img
<img
<img
<img
<img
id="i1"
id="i2"
id="i3"
id="i4"
id="i5"
id="i6"
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
src="nat/im6.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
</div>
</body>
</html>
7.7. Колонка фотографий
Файл column.html.
Следующая галерея будет состоять из двух блоков. Такую программу вы
можете видеть, перейдя по ссылке Колонка фотографий. Слева на странице
узкое пространство с миниатюрами, справа ⸻ более широкое для просмотра
увеличенных снимков (см. рис. 7.7.1). В исходном состоянии в правой части
демонстрируется первое фото, загружаемое по умолчанию. Если кликнуть на
любом рисунке из коллекции миниатюр, то справа появится его увеличенное
изображение (см. рис. 7.7.2).
Рис. 7.7.1. Страница с миниатюрами и начальным изображением
95
Рис. 7.7.2. На странице появилось увеличенное изображение выбранного рисунка
Помимо внешних отличий от предыдущих галерей, у нынешней есть еще
одно ⸻ мы впервые прибегли к помощи серверной программы, написанной на
PHP.
До сих пор у нас в галереях было строго заданное количество снимков со
строго прописанными адресами. Между тем нередко бывают ситуации, когда
программисту необходимо загружать на страницу все картинки, имеющиеся в
той или иной директории сайта. Все бы ничего, но количество изображений
может меняться ежедневно, ежечасно и даже ежеминутно. Следовательно, блок
с миниатюрами необходимо формировать «на лету» в процессе загрузки страницы в браузер клиента. Тут и приходит на помощь серверный скрипт, который
считывает содержимое директории с рисунками и загружает их на страницу.
Сначала мы разберем, как работает сценарий на JavaScript, а потом выясним, как необходимые манипуляции выполняет серверная программа.
Документ содержит два основных элемента.
Во-первых, контейнер для загрузки миниатюр:
<div id="list"></div>
Контейнер имеет фиксированные размеры и для него установлена возможность
вертикальной прокрутки содержимого при переполнении:
#list {... width: 300px; height: 600px; ...
overflow-y: scroll;}
96
Сами изображения в контейнере имеют ширину 130 пикселей:
.roster {width: 130px; ...}
Второй элемент ⸻ основное изображение:
<img src="nat/im1.jpg" id="im" alt="Фото">
Напомню, что в исходном состоянии демонстрируется первый снимок из списка превьюшек.
Сразу после загрузки страницы сценарий запускает обращение к серверному скрипту. Первым делом создается экземпляр прикладного интерфейса для
связи с сервером:
let re=new XMLHttpRequest();
Затем формируется
re.open("GET", "ins.php", true);
и отправляется запрос
re.send();
После загрузки ответа
re.addEventListener("load", function()
{
...
});
создаем переменную и помещаем в нее данные, полученные от сервера:
let resp=this.responseText;
А затем добавляем теги рисунков в контейнер методом insertAdjacentHTML:
document.getElementById("list").
insertAdjacentHTML("beforeend", resp);
Итак, миниатюры загрузились (длительность этого процесса зависит от
скорости интернет-соединения, количества и «веса» снимков). Когда посетитель щелкает на одной из картинок, запускается обработчик события click для
контейнера list:
document.getElementById("list").
addEventListener("click", function(ev)
{
...
});
97
Проверяем, был ли щелчок на фотографии:
if(ev.target.tagName=="IMG")
Если «да», то заменяем исходный рисунок на выбранный:
document.getElementById("im").src=ev.target.src;
Теперь про серверный скрипт.
Сразу после его запуска создается переменная
$res="";
необходимая для записи в нее тегов изображений, хранящихся в папке nat.
На следующем шаге программа открывает эту папку
$opdir=opendir("nat");
и в цикле while считывает ее содержимое:
while($redir=readdir($opdir))
{
if(strpos($redir, "."))
$res.='<img class="roster" src="nat/'.$redir.
'" alt="Фото">';
}
Затем папка закрывается
closedir($opdir);
а данные, сохраненные в переменной $res, отправляются в качестве ответа сценарию основной страницы:
echo $res;
Теперь обращу ваше внимание на тот факт, что в теле цикла на каждом
проходе выполняется проверка условия
if(strpos($redir, "."))
Для чего это нужно? Дело в том, что при чтении директории в списке файлов окажутся такие элементы, как точка и две точки (. и ..), которые обозначают
текущий и вышестоящий каталоги. Введенное в условие выражение «отсекает»
обозначения каталогов:
strpos($redir, "."))
98
Точка и две точки вернут ноль ⸻ индекс первого вхождения элемента.
Условие if воспримет данный результат как false и не включит эти элементы в
список. Зато у остальных файлов, у которых точка стоит перед расширением
после нескольких символов имени, индекс вхождения окажется больше нуля и
условие примет значение true. То есть реальные файлы пройдут «тест».
Как видите, изящный и простой скрипт на PHP помог нам вывести на
страницу все миниатюры, которые есть в директории nat на данный момент.
Если впоследствии количество снимков в этом каталоге изменится, разработчику не придется ничего менять в основной программе.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Колонка фотографий</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#list {position: absolute; left: 0; top: 0;
width: 300px; height: 600px;
border: 1px solid #000000;
overflow-y: scroll;}
.roster {width: 130px; border: 1px solid #000000;
margin: 3px; cursor: pointer;}
#im {position: absolute; left: 350px; top: 50px;
border: 1px solid #000000;}
</style>
<script>
addEventListener("load", function()
{
let re=new XMLHttpRequest();
re.open("GET", "ins.php", true);
re.send();
re.addEventListener("load", function()
{
let resp=this.responseText;
document.getElementById("list").
insertAdjacentHTML("beforeend", resp);
});
document.getElementById("list").
addEventListener("click", function(ev)
{
if(ev.target.tagName=="IMG")
document.getElementById("im").src=
ev.target.src;
});
});
</script>
</head>
<body>
<div id="basis">
<div id="list"></div>
99
<img src="nat/im1.jpg" id="im" alt="Фото">
</div>
</body>
</html>
Код файла ins.php:
<?php
$res="";
$opdir=opendir("nat");
while($redir=readdir($opdir))
{
if(strpos($redir, "."))
$res.='<img class="roster" src="nat/'.$redir.
'" alt="Фото">';
}
closedir($opdir);
echo $res;
7.8. Список альбомов
Файл list.html.
Иногда бывает удобнее показывать клиенту не все картинки сразу, а разбить их по категориям и демонстрировать по частям. Пример такой программы
вы можете видеть, кликнув ссылку Список альбомов.
В исходном состоянии на странице только выпадающий список с перечнем
из трех альбомов, которые предлагаются для просмотра (см. рис. 7.8.1). Выберите интересующий вас альбом. Все миниатюрные фото из него появятся под
списком (см. рис. 7.8.2). Если теперь кликнуть на любом из рисунков, то его
увеличенное изображение возникнет посередине экрана на белом полупрозрачном фоне (см. рис. 7.8.3). Прокрутите страницу или щелкните мышью в любой
ее точке, и увеличенное изображение скроется. Теперь можно загрузить другой
альбом. Если же выбрать пункт «Выберите альбом», все картинки пропадут и
останется только сам список.
Рис. 7.8.1. В исходном состоянии на странице только выпадающий список
100
Рис. 7.8.2. Миниатюры из выбранного альбома
Рис. 7.8.3. Просмотр изображения, выбранного из альбома
Данная программа состоит из двух частей: уже знакомой нам системы просмотра изображений, которую мы подробно изучили в разделе 7.1, и сценария,
загружающего фотографии из альбома.
В исходном состоянии на странице находятся три элемента.
101
1. Выпадающий список:
<select id="sel"><option selected value="99">
Выберите альбом</option>
<option value="0">Лес</option>
<option value="1">Водоемы</option>
<option value="2">Закат</option>
</select>
Для пункта, выбранного по умолчанию, установлено значение 99. Его мы будем
использовать, проверяя, необходимо загружать альбом или нет.
2. Пустой контейнер для фотографий из альбома:
<p id="ins"></p>
3. Два слоя для показа увеличенных снимков (знакомые нам по разделу 7.1):
<div id="bas"></div>
<div id="view">
<img id="pict" src="nat/im1.jpg" alt="Фото">
</div>
После загрузки страницы создаем массив из трех элементов, каждый из которых, в свою очередь, тоже является массивом ⸻ с числовыми индексами рисунков трех альбомов:
let ar=[[1, 2, 14, 20, 30, 70],
[18, 22, 29, 35, 60, 74],
[3, 6, 13, 27, 88, 89]];
Когда посетитель выбирает какой-либо пункт из списка, запускается обработчик события change, роль которого выполняет анонимная функция
document.getElementById("sel").
addEventListener("change", function()
{
...
});
Первым делом из контейнера
<p id="ins"></p>
удаляем предыдущие снимки (если они были вставлены ранее):
document.getElementById("ins").innerHTML="";
Затем создаем переменную, в которую помещаем значение выбранного
пункта:
let a=document.getElementById("sel").value;
102
Следом проверяем, что именно выбрал клиент ⸻ альбом или пункт «Выберите альбом»:
if(a!=99)
{
...
}
Если условие ложно (то есть выбран первый пункт), то на этом выполнение программы прерывается и вы видите чистую страницу с выпадающим
списком.
Если условие истинно (выбран альбом), то создается переменная для записи в нее тегов необходимых фотографий:
let sum="";
Затем в цикле происходит наполнение переменной:
for(let i=0; i<ar[a].length; i++)
sum+='<img src="nat/im'+ar[a][i]+
'.jpg" class="im" alt="Фото">';
Количество проходов зависит от количества элементов соответствующего вложенного массива
i<ar[a].length
На последнем этапе помещаем изображения в контейнер:
document.getElementById("ins").innerHTML=sum;
Таким образом, под выпадающим списком появляются рисунки из выбранного альбома.
Увеличение снимков происходит с помощью сценария, рассмотренного в
разделе 7.1:
– слои смещаются на величину прокрутки страницы (или остаются на месте, если страница не прокручивалась);
– на верхний слой загружается выбранный рисунок в натуральную величину;
– слои и картинка становятся видимыми.
При прокрутке страницы или щелчке в любой ее точке запускается функция del, которая завершает просмотр и скрывает слои и фотографию.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Список альбомов</title>
<style>
#basis {position: relative; margin: auto;
103
width: 1000px; text-align: center;}
#sel {width: 200px; font-size: 20px;}
.im {width: 300px; border: 1px solid #000000;
margin: 10px; cursor: pointer;}
#bas, #view {position: absolute; left: 0; top: 0;
width: 100%; height: 100%; visibility: hidden;}
#bas {z-index: 1; background: #FFFFFF;
opacity: 0.95;}
#view {z-index: 2; display: flex;
justify-content: center; align-items: center;}
#pict {border: 1px solid #000000; cursor: pointer;}
</style>
<script>
addEventListener("load", function()
{
let ar=[[1, 2, 14, 20, 30, 70],
[18, 22, 29, 35, 60, 74],
[3, 6, 13, 27, 88, 89]];
document.getElementById("sel").
addEventListener("change", function()
{
document.getElementById("ins").innerHTML="";
let a=document.getElementById("sel").value;
if(a!=99)
{
let sum="";
for(let i=0; i<ar[a].length; i++)
sum+='<img src="nat/im'+ar[a][i]+
'.jpg" class="im" alt="Фото">';
});
document.getElementById("ins").innerHTML=sum;
}
addEventListener("scroll", del);
let view=document.getElementById("view");
let bas=document.getElementById("bas").style;
let pict=document.getElementById("pict");
view.addEventListener("click", del);
document.getElementById("basis").
addEventListener("click", function(ev)
{
if(ev.target.tagName=="IMG")
{
let sc=window.pageYOffset;
bas.top=sc+"px";
view.style.top=sc+"px";
});
pict.src=ev.target.src;
view.style.visibility="visible";
bas.visibility="visible";
}
104
function del()
{
view.style.visibility="hidden";
bas.visibility="hidden";
pict.src="pict/net.jpg";
}
});
</script>
</head>
<body>
<div id="bas"></div>
<div id="view">
<img id="pict" src="nat/im1.jpg" alt="Фото">
</div>
<div id="basis">
<select id="sel"><option selected value="99">
Выберите альбом</option>
<option value="0">Лес</option>
<option value="1">Водоемы</option>
<option value="2">Закат</option>
</select>
<p id="ins"></p>
</div>
</body>
</html>
7.9. Слои вместо фото
Файл layer.html.
Перейдите по ссылке Слои вместо фото. Вы увидите на странице большую картинку с изображением горных сельскохозяйственных угодий (см.
рис. 7.9.1). На этом фото есть шесть маленьких снимков фруктов и ягод. В чем
особенность примера? Дело в том, что все это единый рисунок. Наша задача
добиться того, чтобы мы могли увеличивать фрагменты с фруктами и ягодами
для более крупного просмотра. И нам это удастся. Наведите указатель мыши,
допустим, на изображение клубники. Вы обнаружите, что форма курсора поменяла свой вид ⸻ теперь он выглядит как рука. Это означает, что перед нами
ссылка, которую можно нажать. Что мы и сделаем. Документ скроется за полупрозрачным белым фоном, на котором появится крупная фотография клубники
(см. рис. 7.9.2). Если теперь щелкнуть мышью на снимке, фоне или прокрутить
страницу вниз, снимок и фон исчезнут и страница вернется к первоначальному
виду. То же можно проделать и с остальными фрагментами ⸻ то есть вы можете просмотреть все шесть увеличенных фото.
Как нам удалось получить такой результат? Дело в том, что над каждым
ягодно-фруктовым кадром находится прозрачный слой, полностью охватыва105
ющий площадь данного изображения. Соответственно, программа реагирует на
щелчок по слою. А дальше уже запускает сценарий обработки этого щелчка.
Впрочем, давайте по порядку.
Рис. 7.9.1. Начальный вид страницы с единственным рисунком
Рис. 7.9.2. Смотрим увеличенное фото
106
У нас есть базовый слой
<div id="basis">...</div>
Он содержит основное изображение
<img src="pict/fon.jpg" alt="Фото">
и шесть слоев над каждым фрагментом с рисунком фрукта или ягоды:
<div
<div
<div
<div
<div
<div
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
id="fr1"></div>
id="fr2"></div>
id="fr3"></div>
id="fr4"></div>
id="fr5"></div>
id="fr6"></div>
Слои имеют абсолютное позиционирование:
.im {position: absolute; cursor: pointer;}
#fr1 {top: 56px; left: 88px; width: 200px;
height:
#fr2 {top: 84px; left: 374px; width: 200px;
height:
#fr3 {top: 36px; left: 665px; width: 200px;
height:
#fr4 {top: 274px; left: 158px; width: 200px;
height:
#fr5 {top: 308px; left: 454px; width: 200px;
height:
#fr6 {top: 267px; left: 743px; width: 200px;
height:
150px;}
150px;}
150px;}
150px;}
150px;}
150px;}
Кроме того, для просмотра увеличенных снимков мы вновь используем
уже знакомую нам комбинацию из двух фоновых слоев:
<div id="bas"></div>
<div id="view">
<img id="pict" src="pict/net.jpg" alt="Фото">
</div>
Зарегистрируем два обработчика для трех событий:
– клика на поверхности базового слоя ⸻ функцию look;
– клика на фоне увеличенного изображения ⸻ функцию del;
– прокрутки страницы ⸻ снова функцию del.
Вот необходимый код:
document.getElementById("basis").
addEventListener("click", look);
document.getElementById("view").
addEventListener("click", del);
addEventListener("scroll", del);
107
Как и в предыдущих аналогичных случаях, объявим три переменные:
let bas=document.getElementById("bas").style;
let view=document.getElementById("view").style;
let pict=document.getElementById("pict");
Функцию del мы не станем разбирать, так как уже сделали это в разделе 7.1.
А вот функцию look рассмотрим подробно, поскольку в ней есть отличия
от аналогичных функций из разделов 7.1 и 7.8.
Первая операция данной функции ⸻ выяснение id элемента, на котором
произошел щелчок мышью:
let ni=ev.target.id;
На следующем шаге определяем, является ли этот элемент слоем над основным рисунком:
if(ni.indexOf("fr")==0)
{
...
}
Здесь мы берем первые два символа fr, которые есть в id всех интересующих
нас слоев, и проверяем индекс вхождения этих символов. Если индекс вхождения равен 0, значит событие произошло на одном из слоев. Если индекс вхождения равен –1, значит клик случился между слоями.
Если приведенное выше условие истинно, то дальше выполняются инструкции, в точности совпадающие с теми, что мы видели в разделе 7.1, когда
рассматривали принципы перемещения фоновых слоев и демонстрации увеличенных снимков:
let sc=window.pageYOffset;
bas.top=sc+"px";
view.top=sc+"px";
pict.src="pict/"+ni+".jpg";
view.visibility="visible";
bas.visibility="visible";
Хотя мы и внесли ряд изменений в сценарий просмотра отдельных изображений, его основа осталась прежней, очень схожей с тем, что мы видели в
разделах 7.1 и 7.8.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Слои вместо фото</title>
108
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#bas, #view {position: absolute; left: 0; top: 0;
width: 100%; height: 100%; visibility: hidden;}
#bas {z-index: 1; background: #FFFFFF;
opacity: 0.95;}
#view {z-index: 2; display: flex;
justify-content: center; align-items: center;}
#pict {border: 1px solid #000000; cursor: pointer;}
.im {position: absolute; cursor: pointer;}
#fr1 {top: 56px; left: 88px; width: 200px;
height: 150px;}
#fr2 {top: 84px; left: 374px; width: 200px;
height: 150px;}
#fr3 {top: 36px; left: 665px; width: 200px;
height: 150px;}
#fr4 {top: 274px; left: 158px; width: 200px;
height: 150px;}
#fr5 {top: 308px; left: 454px; width: 200px;
height: 150px;}
#fr6 {top: 267px; left: 743px; width: 200px;
height: 150px;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("basis").
addEventListener("click", look);
document.getElementById("view").
addEventListener("click", del);
addEventListener("scroll", del);
let bas=document.getElementById("bas").style;
let view=document.getElementById("view").style;
let pict=document.getElementById("pict");
function look(ev)
{
let ni=ev.target.id;
if(ni.indexOf("fr")==0)
{
let sc=window.pageYOffset;
bas.top=sc+"px";
view.top=sc+"px";
}
pict.src="pict/"+ni+".jpg";
view.visibility="visible";
bas.visibility="visible";
}
function del()
{
view.visibility="hidden";
bas.visibility="hidden";
109
pict.src="pict/net.jpg";
}
});
</script>
</head>
<body>
<div id="bas"></div>
<div id="view">
<img id="pict" src="pict/net.jpg" alt="Фото">
</div>
<div id="basis">
<img
<div
<div
<div
<div
<div
<div
src="pict/fon.jpg" alt="Фото">
class="im" id="fr1"></div>
class="im" id="fr2"></div>
class="im" id="fr3"></div>
class="im" id="fr4"></div>
class="im" id="fr5"></div>
class="im" id="fr6"></div>
</div>
</body>
</html>
110
8. Вставка фото
До сих пор мы рассматривали случаи, когда список размещаемых фотографий был определен заранее. Обычно у каждой страницы есть основная тема,
которую можно проиллюстрировать несколькими изображениями. Подбором
снимков занимается либо сам разработчик (если он выполняет проект единолично), либо контент-менеджер (если сайт делает студия web-дизайна). После
того, как страница скомпонована и опубликована в сети, ее содержание «фиксируется» до следующего обновления (которое может произойти очень нескоро). Таким образом, выбранные фото «прописываются» в HTML-коде опытными специалистами с применением соответствующих технологий и методов.
Но существует немало сайтов, где контент меняется ежеминутно, а наполнением страниц занимаются их многочисленные посетители. Речь, как вы уже
догадались, идет о социальных сетях.
Типичное сообщение пользователя такой сети состоит из текста, а также
одного или нескольких снимков. Добавить в сообщение фотографию можно,
закачав ее со своего компьютера или смартфона. Этот случай мы не будем рассматривать. Есть еще другая возможность разместить картинку ⸻ выбрать ее
из тех, что вы закачивали ранее для предыдущих постов или в альбомы. Такая
функция реализована не во всех социальных сетях, но в некоторых российских
она присутствует.
В таких сетях форма создания очередной записи выглядит так: поле для
ввода текста, а под ним пиктограмма фотоаппарата. Если ее нажать, откроется
дополнительная вкладка, на которой вам будет предложено загрузить фотографию с компьютера или выбрать из уже имеющихся. Последние представлены
на этой же вкладке, только в уменьшенном размере. Щелкаете на интересующем вас снимке, и он появляется в сообщении, а вкладка закрывается. Вот, собственно, и все.
Попробуем сделать нечто подобное и мы. Конечно, оформлены наши примеры будут чуть проще, чем в социальных сетях, но суть останется та же: клиент станет добавлять на страницу снимки из имеющихся на сервере.
8.1. Фото со страниц
Файл pages.html.
Перейдите по ссылке Фото со страниц. На первый взгляд покажется, что
перед вами уже знакомая по разделу 7.8 картина ⸻ выпадающий список с перечнем из трех альбомов, которые предлагаются для просмотра (см. рис. 8.1.1).
Но это не совсем так. Во-первых, здесь снимок вставляется не на отдельный
слой, а непосредственно на страницу, и скрыть фото можно, только заменив
другим рисунком. Во-вторых, в новом примере списки изображений хранятся
во внешних HTML-файлах. Программа из данного раздела наглядно демонстрирует взаимодействие основной страницы со вспомогательными, загружаемыми во фрейм.
111
Выберите интересующий вас альбом. Все миниатюрные фото из него появятся под списком (см. рис. 8.1.2). Если теперь кликнуть на любом из рисунков, то его увеличенное изображение возникнет посередине экрана под выпадающим списком (см. рис. 8.1.3), а фрейм с миниатюрами скроется. Выберите
другой альбом. Предыдущий снимок исчезнет, а вместо него появятся миниатюры из следующего альбома. Теперь можно вставлять другую фотографию.
Страница включает три элемента.
1. Выпадающий список
<select id="sel"><option selected value="99">
Выберите альбом</option>
<option value="al1.html">Лес</option>
<option value="al2.html">Водоемы</option>
<option value="al3.html">Закат</option>
</select>
2. Фрейм
<iframe id="lay" src="v1.html"></iframe>
Рис. 8.1.1. Список альбомов
Рис. 8.1.2. Фрейм с миниатюрами альбома
112
Рис. 8.1.3. Просмотр выбранного снимка
В исходном состоянии он скрыт от посетителей:
#lay {... visibility: hidden; ...}
При этом изначально, пока не демонстрируется ни один альбом, в него загружена пустая страница v1.html. Так сделано, чтобы соответствовать требованиям Консорциума Всемирной паутины, стандарты которого диктуют обязательное наличие у фрейма атрибута src с установленным значением.
3. Пустой контейнер для размещения картинок
<p id="ins"></p>
Теперь о сценарии.
Первым делом регистрируем обработчик для события выбора пункта из
списка:
addEventListener("load", function()
{
document.getElementById("sel").
addEventListener("change", see);
});
Выполнение функции see начинается с того, что из контейнера удаляются
предыдущие снимки (если они были вставлены ранее):
document.getElementById("ins").innerHTML='';
113
Затем создаем две переменные. Первая нужна для последующего сокращенного обращения к свойствам фрейма:
let a=document.getElementById("lay");
Во вторую помещаем значение выбранного пункта из списка:
let s=document.getElementById("sel").value;
Далее проверяем, что именно выбрал клиент ⸻ альбом или пункт «Выберите альбом»:
if(s!=99)
{
...
}
Если условие ложно (то есть выбран первый пункт), то на этом выполнение программы прерывается и вы видите чистую страницу с выпадающим
списком.
Если условие истинно (выбран альбом), то выполняются две инструкции.
Сначала присваиваем фрейму адрес страницы, полученной из выпадающего
списка:
a.src=s;
А затем показываем фрейм
a.style.visibility="visible";
благодаря чему клиент видит миниатюры того или иного альбома.
На каждой из внешних страниц по 6 изображений (дается фрагмент кода
страницы al1.html):
<img
<img
<img
<img
<img
<img
src="nat/im1.jpg" class="im" alt="Фото">
src="nat/im2.jpg" class="im" alt="Фото">
src="nat/im14.jpg" class="im" alt="Фото"><br>
src="nat/im20.jpg" class="im" alt="Фото">
src="nat/im30.jpg" class="im" alt="Фото">
src="nat/im70.jpg" class="im" alt="Фото">
Теперь посетитель может кликнуть на одной из картинок или на пустом
пространстве фрейма. В этот момент запускается сценарий, который встроен в
каждую из внешних страниц с альбомами (во всех страницах сценарии одинаковые):
addEventListener("click", function(ev)
{
if(ev.target.tagName=="IMG")
114
parent.opt(ev.target.src);
else
parent.hid();
});
Если щелчок мышью произошел на рисунке
if(ev.target.tagName=="IMG")
то на основной странице запускается функция opt, которой в качестве аргумента передается адрес «кликнутого» фото:
parent.opt(ev.target.src);
Если щелчок выполнен на свободном пространстве, то на основной странице запускается функция hid (без аргументов):
else
parent.hid();
Функция opt выполняет три операции. Скрывает фрейм с миниатюрами
альбома:
document.getElementById("lay").style.visibility=
"hidden";
добавляет в контейнер выбранный снимок:
document.getElementById("ins").innerHTML=
'<img src="'+snap+'" alt="Фото">';
и устанавливает в качестве выбранного первый пункт выпадающего списка:
document.getElementById("sel").selectedIndex=0;
Таким образом, клиент видит увеличенное фото, а программа готова к
дальнейшему просмотру того же или другого альбома.
Если клиент передумал смотреть фотографии из альбома, он может:
– выбрать другой альбом;
– кликнуть на пустом пространстве текущего альбома.
В последнем случае запускается функция hid:
function hid()
{
let d=document.getElementById("lay");
d.style.visibility="hidden";
d.src="v1.html";
document.getElementById("sel").selectedIndex=0;
}
115
Вводится переменная для сокращенного обращения к свойствам фрейма,
после чего фрейм скрывается, его атрибуту src присваивается адрес пустой
страницы v1.html, а первый пункт списка устанавливается в качестве выбранного.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Фото со страниц</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
#sel {width: 200px; font-size: 20px;}
#lay {position: absolute; left: 200px; top: 100px;
width: 600px; height: 300px;
box-shadow: 15px 15px 10px #000000;
border: 1px solid #000000;
visibility: hidden; z-index: 5;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("sel").
addEventListener("change", see);
});
function see()
{
document.getElementById("ins").innerHTML='';
let a=document.getElementById("lay");
let s=document.getElementById("sel").value;
if(s!=99)
{
a.src=s;
a.style.visibility="visible";
}
}
function opt(snap)
{
document.getElementById("lay").style.visibility=
"hidden";
document.getElementById("ins").innerHTML=
'<img src="'+snap+'" alt="Фото">';
document.getElementById("sel").selectedIndex=0;
}
function hid()
{
let d=document.getElementById("lay");
d.style.visibility="hidden";
d.src="v1.html";
document.getElementById("sel").selectedIndex=0;
}
116
</script>
</head>
<body>
<div id="basis">
<select id="sel"><option selected value="99">
Выберите альбом</option>
<option value="al1.html">Лес</option>
<option value="al2.html">Водоемы</option>
<option value="al3.html">Закат</option>
</select><br>
<iframe id="lay" src="v1.html"></iframe>
<p id="ins"></p>
</div>
</body>
</html>
Код одного из внешних файлов (al1.html):
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Лес</title>
<style>
body {text-align: center; font-size: 30px;
margin: 0px;}
.im {width: 170px; cursor: pointer;}
</style>
<script>
addEventListener("click", function(ev)
{
if(ev.target.tagName=="IMG")
parent.opt(ev.target.src);
else
parent.hid();
});
</script>
</head>
<body>
<p>Лес</p>
<img src="nat/im1.jpg" class="im" alt="Фото">
<img src="nat/im2.jpg" class="im" alt="Фото">
<img src="nat/im14.jpg" class="im" alt="Фото"><br>
<img src="nat/im20.jpg" class="im" alt="Фото">
<img src="nat/im30.jpg" class="im" alt="Фото">
<img src="nat/im70.jpg" class="im" alt="Фото">
</body>
</html>
117
8.2. PHP на помощь
Файл ins.html.
Как уже ясно из названия раздела, в этом примере мы вновь воспользуемся
помощью серверной программы, написанной на PHP.
Кликните ссылку PHP на помощь. В новой вкладке браузера появится
страница с кнопкой «Показать» (см. рис. 8.2.1). У программы четыре стадии
исполнения ⸻ тремя последними из них управляет посетитель. О первой мы
скажем, разбирая сценарий, а пока коснемся этапов 2–4.
Нажмите кнопку. На странице появится окно с миниатюрами из папки nat
(см. рис. 8.2.2). Это первый этап. Дальше у посетителя есть выбор:
– нажать кнопку «Закрыть» в окне ⸻ в этом случае оно исчезнет;
– кликнуть на интересующей картинке ⸻ в этом случае окно закроется, а
на странице появится выбранное фото в натуральную величину (см. рис. 8.2.3).
Рис. 8.2.1. Начальный вид страницы
Рис. 8.2.2. Картинки с сервера загружены на страницу
118
Рис. 8.2.3. Просмотр выбранного кадра
Документ содержит три главных элемента.
1. Кнопку «Показать»
<input type="button" value="Показать" id="bu">
2. Пустой контейнер для демонстрации увеличенного рисунка
<p id="ima"></p>
3. Пустой контейнер для миниатюр из директории nat
<div id="list">
<input type="button" value="Закрыть" id="vis"><br>
</div>
Единственный элемент, который присутствует в контейнере с самого начала, ⸻
кнопка «Закрыть». В исходном состоянии этот контейнер скрыт от посетителя:
#list {... visibility: hidden; ...}
Сразу после загрузки страницы миниатюры добавляются в соответствующий контейнер:
let re=new XMLHttpRequest();
re.open("GET", "ins.php", true);
re.send();
119
re.addEventListener("load", function()
{
let resp=this.responseText;
document.getElementById("list").
insertAdjacentHTML("beforeend", resp);
});
Этот код вам хорошо знаком по примеру из раздела 7.7. Принцип работы
серверной программы ins.php мы тоже рассмотрели в разделе 7.7.
Обращаю ваше внимание на то, что даже после загрузки картинки не видны. Чтобы «проявить» их, необходимо нажать кнопку «Показать». В этом случае будет запущена вот такая функция:
document.getElementById("bu").
addEventListener("click", function()
{
document.getElementById("ima").innerHTML="";
document.getElementById("list").style.visibility=
"visible";
});
Сначала из контейнера для увеличенных изображений удаляется предыдущий снимок (если он был вставлен ранее):
document.getElementById("ima").innerHTML="";
А затем содержимое контейнера с миниатюрами выводится на экран:
document.getElementById("list").style.visibility=
"visible";
Если теперь нажать кнопку «Закрыть», то контейнер для миниатюр вновь
станет невидимым:
document.getElementById("vis").
addEventListener("click", function()
{
document.getElementById("list").style.visibility=
"hidden";
});
Если же кликнуть на одном из рисунков, то запустится анонимная функция,
которая управляет просмотром:
document.getElementById("list").
addEventListener("click", function(ev)
{
if(ev.target.tagName=="IMG")
{
document.getElementById("ima").innerHTML=
'<img src="'+ev.target.src+'" alt="Фото">';
document.getElementById("list").style.
visibility="hidden";
}
});
120
Функция выполняет инструкции только при условии клика на снимке:
if(ev.target.tagName=="IMG")
{
...
}
В случае истинности условия производятся две операции. Демонстрируется увеличенное изображение выбранной фотографии
document.getElementById("ima").innerHTML=
'<img src="'+ev.target.src+'" alt="Фото">';
и одновременно скрывается контейнер с превьюшками:
document.getElementById("list").style.
visibility="hidden";
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>PHP на помощь</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#bu, #vis {width: 250px; height: 40px;
border: 1px solid #000000;
box-shadow: #333333 5px 5px 8px;
font-size: 20px; cursor: pointer;}
#bu {margin-bottom: 20px;}
#list {position: absolute; left: 100px; top: 80px;
width: 800px; height: 400px; padding: 10px;
border: 1px solid #000000; text-align: center;
overflow-y: scroll; visibility: hidden;
background: #FFFFFF;}
.roster {width: 130px; margin: 10px;
cursor: pointer;}
#ima {text-align: center;}
</style>
<script>
addEventListener("load", function()
{
let re=new XMLHttpRequest();
re.open("GET", "ins.php", true);
re.send();
re.addEventListener("load", function()
{
let resp=this.responseText;
document.getElementById("list").
insertAdjacentHTML("beforeend", resp);
});
121
document.getElementById("bu").
addEventListener("click", function()
{
document.getElementById("ima").innerHTML="";
document.getElementById("list").style.visibility=
"visible";
});
document.getElementById("vis").
addEventListener("click", function()
{
document.getElementById("list").style.visibility=
"hidden";
});
document.getElementById("list").
addEventListener("click", function(ev)
{
if(ev.target.tagName=="IMG")
{
document.getElementById("ima").innerHTML=
'<img src="'+ev.target.src+'" alt="Фото">';
document.getElementById("list").style.
visibility="hidden";
}
});
});
</script>
</head>
<body>
<div id="basis">
<input type="button" value="Показать" id="bu">
<p id="ima"></p>
<div id="list">
<input type="button" value="Закрыть" id="vis"><br>
</div>
</div>
</body>
</html>
Код файла ins.php:
<?php
$res="";
$opdir=opendir("nat");
while($redir=readdir($opdir))
{
if(strpos($redir, "."))
$res.='<img class="roster" src="nat/'.$redir.
'" alt="Фото">';
}
closedir($opdir);
echo $res;
122
9. Галереи
В главе 7 мы познакомились с коллекциями изображений. Каждый снимок
можно было просмотреть в отдельности, щелкнув на фото, наведя на него указатель мыши или выбрав из списка.
Теперь познакомимся с примерами коллекций, в которых просмотром
управляют с помощью специальных кнопок.
В сети встречаются два варианта названий для таких наборов изображений:
галереи или слайдеры. Так как рисунки у нас будут меняться «вручную», автор
решил называть программы из данной главы галереями. Слайдерами мы станем
именовать сценарии, которые выполняют смену фотографий автоматически,
без участия посетителя. Разная терминология необходима для разграничения
функциональных особенностей примеров.
Кстати, особенность всех программ из данный главы в том, что для просмотра изображений их необходимо «пролистывать» тем или иным способом.
9.1. Смещаем фото вверх
Файл contr.html.
В разделе «Галереи» щелкните на ссылке Смещаем фото вверх. Вы увидите страницу, показанную на рисунке 9.1.1.
В середине экрана расположено фото лесной дороги, а под снимком ⸻
кнопка перемотки с надписью «Следующее фото». Нажмем ее. Первое изображение плавно уедет вверх, уступив место второму (см. рис. 9.1.2). Снова
нажмем кнопку. Второе изображение будет заменено третьим. И так далее ⸻
до последней, шестой картинки. Когда она на экране, нажмем кнопку еще раз.
Последнее изображение исчезнет за верхней границей окна браузера, и останется только белый «лист» с кнопкой. Но буквально через секунду на странице
плавно возникнет первый рисунок. Теперь можно смотреть картинки по второму кругу.
Для создания такой программы мы разместили в теле документа 6 фотографий:
<img
<img
<img
<img
<img
<img
id="i1"
id="i2"
id="i3"
id="i4"
id="i5"
id="i6"
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
src="nat/im6.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
и кнопку
<input type="button" value="Следующее фото" id="bu">
Чтобы добиться необходимого эффекта, мы указали в дескрипторе style
ряд важных настроек для изображений.
Во-первых, позиционировали их на странице
.im {position: absolute; top: 10px; left: 200px; ...}
123
Рис. 9.1.1. Первый снимок галереи
Рис. 9.1.2. Смена изображений
124
Во-вторых, присвоили каждому рисунку значения z-index, уменьшающиеся по мере увеличения номера фото:
#i1
#i2
#i3
#i4
#i5
#i6
{z-index:
{z-index:
{z-index:
{z-index:
{z-index:
{z-index:
7;}
6;}
5;}
4;}
3;}
2;}
Благодаря этому все снимки расположились «стопкой».
Теперь приступим к описанию сценария.
Первым делом у нас зарегистрирован обработчик события нажатия кнопки
перемотки:
addEventListener("load", function()
{
document.getElementById("bu").
addEventListener("click", but);
});
Объявим две глобальные переменные:
let k=10;
let s=0;
Переменная k необходима для временного хранения текущей координаты
рисунка, движущегося вверх. Переменная s ⸻ счетчик кадров.
Первое, что делает функция but после щелчка на кнопке, ⸻ увеличивает
на единицу счетчик кадров
s++;
и присваивает переменной k начальное значение верхней координаты рисунка:
k=10;
На этом моменте остановимся подробнее. Зачем переменной k вновь присваивать значение, которое присвоено ей при объявлении? Как мы уже сказали,
эта переменная хранит текущую координату движущейся картинки. Допустим,
первый рисунок уехал вверх за границы браузера. В момент, когда он остановится, k будет хранить значение точки остановки, равное –700 пикселей. Значит,
при втором щелчке на кнопке переменной k нужно вернуть начальное значение
координаты по оси Y. Ведь именно эта координата взята за основу положения
второго рисунка в исходном состоянии (как, впрочем, и всех остальных).
Обработчик события имеет 2 стадии выполнения:
if(s<6)
...
125
и
if(s==6)
{
...
}
Пока мы не промотали все кадры, выполняется первое условие. Здесь все
просто:
if(s<6)
mov();
Как вы видите, при каждом щелчке запускается рекурсивная функция mov
function mov()
{
if(k>=-700)
{
document.getElementById("i"+s).style.top=k+"px";
k-=10;
setTimeout(mov, 10);
}
}
Она вызывает сама себя до тех пор, пока движущийся рисунок не достигнет верхней границы:
if(k>=-700)
Когда условие if(k>=-700) верно, свойству top рисунка последовательно с
интервалом 10 миллисекунд присваивается новое значение координаты, на
10 пикселей меньше предыдущего:
document.getElementById("i"+s).style.top=k+"px";
k-=10;
setTimeout(mov, 10);
Достигнув верхнего предела, картинка останавливается.
Так происходит со всеми изображениями вплоть до предпоследнего, пятого. Щелчок на кнопке перемотки ⸻ и очередной кадр уезжает вверх.
Что меняется, когда вы в шестой раз нажимаете кнопку? Выполняется
условие
if(s==6)
В действие вступает второй блок инструкций
if(s==6)
{
...
}
126
Опять запускается функция mov, которая отправляет последнее изображение за границы экрана:
mov();
Через одну секунду переменным k и s присваиваются исходные значения:
setTimeout(()=>{k=10; s=0;}, 1000);
Тем самым сценарий подготавливается к новому запуску с самого начала.
Далее объявляем переменную h
let h=document.getElementById("i1").style;
посредством которой мы станем обращаться к свойствам первого рисунка. Делаем его полностью невидимым:
h.opacity=0;
Теперь запускаем два таймера, один вложенный в другой:
setTimeout(()=>
{
h.top="10px";
h.transition="opacity 1s";
h.opacity=1;
setTimeout(()=>
{
if(h.opacity==1)
{
for(let a=2; a<7; a++)
document.getElementById("i"+a).style.top="10px";
}
}, 1000);
}, 1000);
Первый таймер сработает через одну секунду. Второй будет запущен через
одну секунду после первого.
Инструкции первого таймера возвращают первый рисунок в исходное положение
h.top="10px";
а затем в течение одной секунды плавно делают картинку видимой:
h.transition="opacity 1s";
h.opacity=1;
Теперь про вложенный таймер. Он стартует после того, как непрозрачность первого изображения достигла максимума:
if(h.opacity==1)
127
После этого запускается цикл
for(let a=2; a<7; a++)
document.getElementById("i"+a).style.top="10px";
который проходит по всем кадрам, начиная со второго, и возвращает их в исходное положение. Теперь можно смотреть рисунки по новой.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Смещаем фото вверх</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
.im {position: absolute; top: 10px; left: 200px;
border: 1px solid #000000;}
#bu {position: absolute; top: 450px; left: 200px;
width: 250px; height: 40px;
border: 1px solid #000000;
box-shadow: #333333 5px 5px 8px; font-size: 20px;
cursor: pointer;}
#i1 {z-index: 7;}
#i2 {z-index: 6;}
#i3 {z-index: 5;}
#i4 {z-index: 4;}
#i5 {z-index: 3;}
#i6 {z-index: 2;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("bu").
addEventListener("click", but);
});
let k=10;
let s=0;
function but()
{
s++;
k=10;
if(s<6)
mov();
if(s==6)
{
mov();
setTimeout(()=>{k=10; s=0;}, 1000);
let h=document.getElementById("i1").style;
h.opacity=0;
128
setTimeout(()=>
{
h.top="10px";
h.transition="opacity 1s";
h.opacity=1;
}
setTimeout(()=>
{
if(h.opacity==1)
{
for(let a=2; a<7; a++)
document.getElementById("i"+a).style.
top="10px";
}
}, 1000);
}, 1000);
}
function mov()
{
if(k>=-700)
{
document.getElementById("i"+s).style.top=k+"px";
k-=10;
setTimeout(mov, 10);
}
}
</script>
</head>
<body>
<div id="basis">
<img
<img
<img
<img
<img
<img
id="i1"
id="i2"
id="i3"
id="i4"
id="i5"
id="i6"
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
src="nat/im6.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
<input type="button" value="Следующее фото" id="bu">
</div>
</body>
</html>
9.2. Фото по номерам
Файл numb.html.
Напишем сценарий для галереи, где роль кнопок выполняют ссылки на
номера картинок.
Такую галерею вы можете увидеть, кликнув на главной странице ссылку
Фото по номерам (см. рис. 9.2.1).
129
Рис. 9.2.1. Начальный вид галереи
В начальный момент в окне браузера показана фотография лесной дороги.
Ссылка на него подсвечена красным цветом и не активна. Нажмите на ссылку с
любым другим номером, и соответствующее изображение появится на странице.
Одновременно ссылка с номером 1 активируется, а нажатая, наоборот, станет
неактивной (см. рис. 9.2.2). Плюс такой галереи в том, что просматривать картинки можно в любом порядке.
Приступим к изучению данной программы.
В центре страницы ⸻ рисунок номер один:
<img id="im" src="nat/im1.jpg" alt="Фото">
Под ним ⸻ расположенные в ряд ссылки с цифрами:
<p id="bu">
<a href="nat/im1.jpg" class="curs">1</a>
<a href="nat/im2.jpg">2</a>
<a href="nat/im3.jpg">3</a>
<a href="nat/im4.jpg">4</a>
<a href="nat/im5.jpg">5</a>
<a href="nat/im6.jpg">6</a>
</p>
При этом первая из них
<a href="nat/im1.jpg" class="curs">1</a>
не активна:
.curs {cursor: auto; color: #CC0000;}
130
Рис. 9.2.2. Пролистываем изображения
В начале сценария объявляем переменную a
let a;
Она понадобится для сохранения адреса контейнера <p id="bu">...</p>, в который помещены ссылки.
После загрузки страницы присваиваем переменной a адрес контейнера и
регистрируем в качестве обработчика события click функцию but:
addEventListener("load", function()
{
a=document.getElementById("bu");
a.addEventListener("click", but);
});
Функция but очень простая:
function but(ev)
{
let h=ev.target.href;
if(h)
{
document.getElementById("im").src=h;
for(let n=0; n<a.children.length; n++)
{
let b=a.children[n];
131
b.className=(b==ev.target)?"curs":"";
}
}
ev.preventDefault();
}
Из интерфейса event получаем значение атрибута href той ссылки, на которой был сделан щелчок
let h=ev.target.href;
и выясняем, действительно ли клик был именно на ссылке:
if(h)
{
...
}
Когда щелчок выполнен на ссылке в контейнере <p id="bu">...</p>, переменная h получает значение адреса картинки и условие оказывается истинным. Если клик был сделан в любой другой части контейнера <p
id="bu">...</p>, то h будет иметь значение undefined и условие станет ложным.
Если клик случился вне рамок контейнера, то в этом случае переменная h не
существует и условие опять ложно.
Итак, если условие истинно, присваиваем значение атрибута href атрибуту
src рисунка:
document.getElementById("im").src=h;
Таким образом, мы загружаем выбранную картинку вместо исходной.
Затем вычисляем ссылку, которая должна стать неактивной:
for(let n=0; n<a.children.length; n++)
{
let b=a.children[n];
b.className=(b==ev.target)?"curs":"";
}
В этом цикле количество проходов ограничивается количеством дочерних
элементов контейнера <p id="bu">...</p>:
n<a.children.length
В теле цикла выполняем две операции.
1. Присваиваем переменной b адрес очередной ссылки (для сокращения
кода):
let b=a.children[n];
132
2. Посредством тернарного оператора выясняем, какие ссылки должны
стать активными, а какая ссылка, наоборот, неактивной:
b.className=(b==ev.target)?"curs":"";
Для этого мы используем условие
b==ev.target
Ссылке, на которой произошло событие click, присваивается значение curs
атрибута class. У остальных ссылок атрибут class получает пустое значение.
Благодаря этому ссылка, на которой был щелчок, становится неактивной, а
остальные ⸻ активными.
Последняя инструкция
ev.preventDefault();
отменяет поведение браузера по умолчанию. Если бы ее не было, то при первом
же щелчке на ссылке загружалась бы другая страница с фотографией на темном
фоне.
Как видите, ничего сложного.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Фото по номерам</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
a {margin: 20px; color: #0000CC; font-size: 30px;}
.curs {cursor: auto; color: #CC0000;}
</style>
<script>
let a;
addEventListener("load", function()
{
a=document.getElementById("bu");
a.addEventListener("click", but);
});
function but(ev)
{
let h=ev.target.href;
if(h)
{
document.getElementById("im").src=h;
133
for(let n=0; n<a.children.length; n++)
{
let b=a.children[n];
b.className=(b==ev.target)?"curs":"";
}
}
ev.preventDefault();
}
</script>
</head>
<body>
<div id="basis">
<img id="im" src="nat/im1.jpg" alt="Фото">
<p id="bu">
<a href="nat/im1.jpg" class="curs">1</a>
<a href="nat/im2.jpg">2</a>
<a href="nat/im3.jpg">3</a>
<a href="nat/im4.jpg">4</a>
<a href="nat/im5.jpg">5</a>
<a href="nat/im6.jpg">6</a>
</p>
</div>
</body>
</html>
9.3. Три галереи
Файл number.html.
В предыдущем разделе мы рассматривали ситуацию, когда документ содержал всего одну галерею изображений. Настало время усложнить задачу. Попробуем написать страницу, где будет сразу 3 галереи. А для этого воспользуемся методом, который мы использовали в примере из предыдущего раздела.
С одной оговоркой. Метод необходимо подкорректировать.
Сценарий из раздела 9.2 составлен так, что функция but может работать
только с конкретным набором фотографий, размещенных в узле с id="bu".
Наша задача изменить ситуацию и написать такую функцию, которая могла бы
«обслуживать» произвольное, не заданное изначально количество галерей. Что
мы успешно и реализуем в новом примере.
Итак, есть страница, на которую вы можете перейти по ссылке Три галереи. Здесь три набора изображений: лесные дороги, цветы и водоемы (см.
рис. 9.3.1). Под каждым рисунком ссылки на остальные картинки из соответствующего набора. Ссылки можно щелкать в любом порядке (см. рис. 9.3.2).
Поэкспериментируем, чтобы убедиться в корректной работе программы, а
затем приступим к разбору сценария, который управляет галереями.
134
Рис. 9.3.1. Первые фотографии в галереях
Рис. 9.3.2. Пролистываем фотографии сразу во всех галереях
Поскольку у нас теперь 3 галереи, для их размещения мы использовали
таблицу
<table>
<tr>
<td><img src="nat/im19.jpg" alt="Фото">
<p id="bu1">
<a href="nat/im19.jpg" class="curs">1</a>
...
<a href="nat/im57.jpg">6</a>
</p></td>
<td><img src="nat/im8.jpg" alt="Фото">
<p id="bu2">
<a href="nat/im8.jpg" class="curs">1</a>
...
<a href="nat/im71.jpg">4</a>
</p></td>
<td><img src="nat/im18.jpg" alt="Фото">
<p id="bu3">
135
<a href="nat/im18.jpg" class="curs">1</a>
...
<a href="nat/im41.jpg">5</a>
</p></td>
</tr>
</table>
в каждой ячейке которой находятся начальные изображения и соответствующее
количество ссылок. Как и прежде, рисунки располагаются в контейнерах
<p>...</p>. Только теперь в их id, кроме символов bu, добавлены порядковые
номера.
Во всех галереях первые ссылки неактивны:
.curs {cursor: auto; color: #CC0000;}
Поскольку мы считаем количество галерей произвольным, для регистрации обработчиков надо применить следующий подход:
addEventListener("load", function()
{
let t=document.getElementsByTagName("P");
for(let k=0; k<t.length; k++)
t[k].addEventListener("click", but);
});
На первом этапе получаем массив узлов p:
let t=document.getElementsByTagName("P");
А затем для каждого узла регистрируем обработчик, который вызывает
одну и ту же функцию but:
for(let k=0; k<t.length; k++)
t[k].addEventListener("click", but);
Сама функция содержит набор простых инструкций:
function but(ev)
{
let a=parseFloat(ev.target.parentElement.id.
substr(2))-1;
document.getElementsByTagName("IMG")[a].src=
ev.target.href;
for(let n=0; n<this.children.length; n++)
{
let b=this.children[n];
b.className=(b==ev.target)?"curs":"";
}
ev.preventDefault();
}
136
Вычисляем номер галереи, где произошло событие click, удаляя из id латинские буквы:
let a=parseFloat(ev.target.parentElement.id.
substr(2))-1;
Так как полученное значение относится к строковому типу, приводим его к
числовому:
parseFloat(...)-1;
Операция –1 добавлена, поскольку нумерация id узлов начинается с 1, а нумерация элементов массива этих узлов ⸻ с 0.
Обратите внимание: щелчок мышью произошел на дочернем элементе
контейнера p. Поэтому мы обратились к свойству parentElement ⸻ оно возвращает родительский узел для данной ссылки.
Из интерфейса event получаем значение атрибута href той ссылки, на которой был сделан щелчок, и присваиваем это значение атрибуту src рисунка
соответствующей галереи:
document.getElementsByTagName("IMG")[a].src=
ev.target.href;
Здесь
document.getElementsByTagName("IMG")
массив изображений, видимых на странице после ее загрузки, а
document.getElementsByTagName("IMG")[a]
изображение из той галереи, где произошло событие click.
Как и в предыдущем примере, вычисляем ссылку, которая должна стать
неактивной:
for(let n=0; n<this.children.length; n++)
{
let b=this.children[n];
b.className=(b==ev.target)?"curs":"";
}
Опять у нас количество проходов ограничивается количеством дочерних
элементов контейнера p:
n<this.children.length
Снова в цикле две операции.
1. Присваиваем переменной b адрес очередной ссылки:
let b=this.children[n];
137
2. При помощи тернарного оператора выясняем, какие ссылки должны
стать активными, а какая ссылка ⸻ неактивной:
b.className=(b==ev.target)?"curs":"";
Ссылке из текущей галереи, на которой произошло событие click, присваивается значение curs атрибута class. У остальных ссылок атрибут class получает пустое значение. Ссылка, на которой был щелчок, становится неактивной,
остальные ⸻ активными.
Последняя инструкция
ev.preventDefault();
отменяет поведение браузера по умолчанию.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Три галереи</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
a {margin: 10px; color: #0000CC; font-size: 30px;}
img {width: 300px; border: 1px solid #000000;}
.curs {cursor: auto; color: #CC0000;}
</style>
<script>
addEventListener("load", function()
{
let t=document.getElementsByTagName("P");
for(let k=0; k<t.length; k++)
t[k].addEventListener("click", but);
});
function but(ev)
{
let a=parseFloat(ev.target.parentElement.id.
substr(2))-1;
document.getElementsByTagName("IMG")[a].src=
ev.target.href;
for(let n=0; n<this.children.length; n++)
{
let b=this.children[n];
b.className=(b==ev.target)?"curs":"";
}
ev.preventDefault();
}
</script>
</head>
138
<body>
<div id="basis">
<table>
<tr>
<td><img src="nat/im19.jpg" alt="Фото">
<p id="bu1">
<a href="nat/im19.jpg" class="curs">1</a>
<a href="nat/im20.jpg">2</a>
<a href="nat/im30.jpg">3</a>
<a href="nat/im39.jpg">4</a>
<a href="nat/im44.jpg">5</a>
<a href="nat/im57.jpg">6</a>
</p></td>
<td><img src="nat/im8.jpg" alt="Фото">
<p id="bu2">
<a href="nat/im8.jpg" class="curs">1</a>
<a href="nat/im12.jpg">2</a>
<a href="nat/im16.jpg">3</a>
<a href="nat/im71.jpg">4</a>
</p></td>
<td><img src="nat/im18.jpg" alt="Фото">
<p id="bu3">
<a href="nat/im18.jpg" class="curs">1</a>
<a href="nat/im22.jpg">2</a>
<a href="nat/im29.jpg">3</a>
<a href="nat/im35.jpg">4</a>
<a href="nat/im41.jpg">5</a>
</p></td>
</tr>
</table>
</div>
</body>
</html>
9.4. Перемотка от центра
Файл rewind.html.
В этом примере мы будем пролистывать изображения с помощью двух
кнопок: «Вперед» и «Назад».
Щелкните указателем мыши на ссылке Перемотка от центра. Вы увидите
страницу, показанную на рисунке 9.4.1. В центре окна браузера есть фотография, а под ней две графические кнопки, показывающие направление «перемотки» галереи.
Кликнем левую кнопку. Начальный рисунок плавно начнет смещаться влево и одновременно справа станет выдвигаться следующая картинка (см.
рис. 9.4.2). Обратите внимание: снимки появляются или исчезают так, словно
по бокам от исходного фото есть невидимые шторки, за которые или из-за которых скрываются или выезжают кадры. Они действительно присутствуют, в
чем мы убедимся позже, посмотрев разметку и структуру документа.
139
Перемотку можно выполнять в двух направлениях. Количество элементов
в галерее ограничено девятью штуками. Когда на экране появится первая или
последняя фотография, соответствующая кнопка исчезнет, показывая, что в
данном направлении уже нечего просматривать (см. рис. 9.4.3).
Рис. 9.4.1. Исходный вид галереи
Рис. 9.4.2. Смена изображений
Начнем изучение программы с выяснения особенностей разметки.
На странице есть базовый контейнер
<div id="basis">
...
</div>
140
вмещающий все элементы. Контейнер располагается по центру экрана:
#basis {position: relative; margin: auto;
width: 1000px;}
В документе 9 изображений:
<img
<img
<img
<img
class="im"
class="im"
class="im"
class="im"
id="i1"
id="i2"
id="i3"
id="i4"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
<img class="im" id="i5" src="nat/im5.jpg" alt="Фото">
<img
<img
<img
<img
class="im"
class="im"
class="im"
class="im"
id="i6"
id="i7"
id="i8"
id="i9"
src="nat/im6.jpg"
src="nat/im7.jpg"
src="nat/im8.jpg"
src="nat/im9.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
Пятое располагается по центру страницы:
#i5 {left: 350px;}
Смещение в 350 пикселей внутри базового контейнера как раз и позволяет
рисунку быть в центре.
Первые четыре смещены влево:
#i1, #i2, #i3, #i4 {left: 50px;}
Последние четыре ⸻ вправо:
#i6, #i7, #i8, #i9 {left: 650px;}
Рис. 9.4.3. Пролистывание снимков влево завершено
141
Под галереей две кнопки
<img id="nz" src="pict/nz.png" alt="Назад">
<img id="vp" src="pict/vp.png" alt="Вперед">
со следующими настройками:
#nz, #vp {position: absolute; top: 280px;
cursor: pointer;}
#nz {left: 430px;}
#vp {left: 550px;}
Также есть два слоя, выполняющие роль «шторок» по бокам от основной
картинки:
<div id="fon1"></div>
<div id="fon2"></div>
Установки слоев:
#fon1 {position: absolute; top: 0; left: 0;
z-index: 5; width: 350px; height: 400px;
background: #FFFFFF;}
#fon2 {position: absolute; top: 0; right: 0;
z-index: 5; width: 350px; height: 400px;
background: #FFFFFF;}
Как видите, оба слоя имеют цвет фона ⸻ белый ⸻ и поэтому не видны.
Чтобы структура документа была понятней, можно посмотреть на рисунок 9.4.4. Слои изображены серым цветом в ограничивающих рамках, полупрозрачные фото показывают, где они располагаются в тот момент, когда не видны.
После загрузки страницы регистрируются два обработчика нажатия кнопок:
addEventListener("load", function()
{
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
...
});
и создается переменная
let i=5;
которая выполняет роль счетчика рисунков. В качестве ее начального значения
выбран числовой индекс картинки, которая находится на экране в момент загрузки страницы.
142
Изучение сценария начнем с разбора функции nz, которая управляет движением снимков влево.
Первая инструкция функции:
document.getElementById("vp").style.visibility=
"visible";
Она необходима на случай, когда все кадры прокручены вправо и, соответственно, кнопка «Вперед» скрыта. Если теперь нажать кнопку «Назад», то влево уйдет одно изображение (первое). А значит с этого момента нужно «проявить» кнопку «Вперед», так как в этом направлении уже можно просматривать
первый элемент галереи.
Рис. 9.4.4. Схема расположения слоев и фотографий
Дальше проверяем условие:
if(i<9)
{
...
}
То есть функция работает, пока значение счетчика не достигло верхнего
предела. В этой ситуации выполняются следующие инструкции. Сначала запускается влево центральный снимок:
document.getElementById("i"+i).style.
transition="left 2s";
document.getElementById("i"+i).style.left="50px";
Как видите, конечная позиция и время движения выбраны так, чтобы за
две секунды элемент полностью скрылся за «шторкой».
143
Следом добавляем новую переменную, значение которой на единицу
больше значения счетчика:
let n=i+1;
Она нужна, чтобы отправить влево следующий снимок из-за правой «шторки»:
document.getElementById("i"+n).style.
transition="left 2s";
document.getElementById("i"+n).style.left="350px";
Так как процессы движения кадров синхронизированы, то они перемещаются одновременно, создавая впечатление непрерывной ленты, появляющейся
из тела страницы и скрывающейся в нем.
Теперь увеличим значение счетчика
i++;
и проверим, не достигло ли оно максимально возможного уровня:
if(i==9)
Если «да», то скрываем кнопку «Назад»:
document.getElementById("nz").style.
visibility="hidden";
Функция vp работает по схожему алгоритму.
«Проявляем» кнопку «Назад», если она была скрыта
document.getElementById("nz").style.visibility=
"visible";
Проверяем условие:
if(i>1)
{
...
}
То есть достигнут или нет нижний предел. Если «нет», запускается вправо центральный снимок:
document.getElementById("i"+i).style.transition=
"left 2s";
document.getElementById("i"+i).style.left="650px";
Добавляем новую переменную и отправляем вправо следующий снимок:
let n=i-1;
document.getElementById("i"+n).style.
transition="left 2s";
document.getElementById("i"+n).style.left="350px";
144
Уменьшаем значение счетчика
i--;
и проверим, не достигло ли оно минимального уровня:
if(i==1)
Если «да», то скрываем кнопку «Вперед»:
document.getElementById("vp").style.visibility=
"hidden";
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Перемотка от центра</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#fon1 {position: absolute; top: 0; left: 0;
z-index: 5; width: 350px; height: 400px;
background: #FFFFFF;}
#fon2 {position: absolute; top: 0; right: 0;
z-index: 5; width: 350px; height: 400px;
background: #FFFFFF;}
.im {position: absolute; top: 50px; width: 300px;}
#i1, #i2, #i3, #i4 {left: 50px;}
#i5 {left: 350px;}
#i6, #i7, #i8, #i9 {left: 650px;}
#nz, #vp {position: absolute; top: 280px;
cursor: pointer;}
#nz {left: 430px;}
#vp {left: 550px;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
let i=5;
function nz()
{
document.getElementById("vp").style.visibility=
"visible";
if(i<9)
{
145
document.getElementById("i"+i).style.
transition="left 2s";
document.getElementById("i"+i).style.left=
"50px";
let n=i+1;
document.getElementById("i"+n).style.
transition="left 2s";
document.getElementById("i"+n).style.left=
"350px";
i++;
}
if(i==9)
document.getElementById("nz").style.
visibility="hidden";
}
function vp()
{
document.getElementById("nz").style.
visibility="visible";
if(i>1)
{
document.getElementById("i"+i).style.
transition="left 2s";
document.getElementById("i"+i).style.left=
"650px";
let n=i-1;
document.getElementById("i"+n).style.
transition="left 2s";
document.getElementById("i"+n).style.left=
"350px";
i--;
if(i==1)
document.getElementById("vp").style.
visibility="hidden";
}
}
});
</script>
</head>
<body>
<div id="basis">
<div id="fon1"></div>
<div id="fon2"></div>
<img
<img
<img
<img
class="im"
class="im"
class="im"
class="im"
id="i1"
id="i2"
id="i3"
id="i4"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
<img class="im" id="i5" src="nat/im5.jpg" alt="Фото">
146
<img
<img
<img
<img
class="im"
class="im"
class="im"
class="im"
id="i6"
id="i7"
id="i8"
id="i9"
src="nat/im6.jpg"
src="nat/im7.jpg"
src="nat/im8.jpg"
src="nat/im9.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
<img id="nz" src="pict/nz.png" alt="Назад">
<img id="vp" src="pict/vp.png" alt="Вперед">
</div>
</body>
</html>
9.5. Перемотка с растворением
Файл rew.html.
Этот пример построен на основе предыдущего. Только теперь изображения станут растворяться, а не скрываться за «шторками».
Перейдите по ссылке Перемотка с растворением. Перед вами будет страница, показанная на рисунке 9.5.1. В центре окна браузера есть фотография, а
под ней две графические кнопки, показывающие направление «перемотки» галереи.
Кликнем левую кнопку. Начальный рисунок плавно начнет смещаться влево и одновременно справа станет выдвигаться следующая картинка (см.
рис. 9.5.2). При этом снимок, уходящий влево, растворяется по ходу движения,
а входящий справа, наоборот, проявляется сквозь белый фон страницы.
Как и в предыдущем разделе, перемотку можно выполнять в двух направлениях. Количество элементов в галерее ограничено девятью штуками. Когда
на экране появится первая или последняя фотография, соответствующая кнопка
исчезнет, показывая, что в данном направлении уже нечего просматривать (см.
рис. 9.5.3).
Рис. 9.5.1. Начальный вид страницы
147
Рис. 9.5.2. Смена изображений
Рис. 9.5.3. Новое изображение заняло центральное положение
Разметка страницы похожа на ту, что мы видели в разделе 9.4. За исключением одного момента ⸻ отсутствуют слои-«шторки».
В остальном все то же самое. Базовый контейнер, 9 изображений и две
кнопки перемотки галереи:
<div id="basis">
<img class="im" id="i1" src="nat/im1.jpg" alt="Фото">
...
<img class="im" id="i4" src="nat/im4.jpg" alt="Фото">
<img class="im" id="i5" src="nat/im5.jpg" alt="Фото">
148
<img class="im" id="i6" src="nat/im6.jpg" alt="Фото">
...
<img class="im" id="i9" src="nat/im9.jpg" alt="Фото">
<img id="nz" src="pict/nz.png" alt="Назад">
<img id="vp" src="pict/vp.png" alt="Вперед">
</div>
Важное дополнение есть в настройках свойств картинок 1‒4 и 6‒9. Они
сделаны полностью прозрачными:
opacity: 0;
Опять регистрируем два обработчика и создаем переменную-счетчик:
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
let i=5;
Функции nz и vp очень похожи на то, что мы видели раньше. Только теперь операции манипулирования снимками чуть изменены и в них добавлены
по одной новой инструкции. Для перемотки влево новый вариант теперь выглядит так:
document.getElementById("i"+i).style.
transition="left 2s, opacity 2s";
document.getElementById("i"+i).style.left="50px";
document.getElementById("i"+i).style.opacity=0;
let n=i+1;
document.getElementById("i"+n).style.
transition="left 2s, opacity 2s";
document.getElementById("i"+n).style.left="350px";
document.getElementById("i"+n).style.opacity=1;
Как видите, здесь мы добавили код, который необходим для изменения непрозрачности элементов галереи. Во-первых установили время растворения и
проявления ⸻ 2 секунды:
opacity 2s
Во-вторых, снизили непрозрачность уходящего фото
document.getElementById("i"+i).style.opacity=0;
и увеличили непрозрачность появляющегося:
document.getElementById("i"+n).style.opacity=1;
149
Аналогичные изменения в случае перемотки вправо:
document.getElementById("i"+i).style.
transition="left 2s, opacity 2s";
document.getElementById("i"+i).style.left="650px";
document.getElementById("i"+i).style.opacity=0;
let n=i-1;
document.getElementById("i"+n).style.
transition="left 2s, opacity 2s";
document.getElementById("i"+n).style.left="350px";
document.getElementById("i"+n).style.opacity=1;
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Перемотка с растворением</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
.im {position: absolute; top: 50px; width: 300px;}
#i1, #i2, #i3, #i4 {left: 50px; opacity: 0;}
#i5 {left: 350px;}
#i6, #i7, #i8, #i9 {left: 650px; opacity: 0;}
#nz, #vp {position: absolute; top: 280px;
cursor: pointer;}
#nz {left: 430px;}
#vp {left: 550px;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
let i=5;
function nz()
{
document.getElementById("vp").style.visibility=
"visible";
if(i<9)
{
document.getElementById("i"+i).style.
transition="left 2s, opacity 2s";
document.getElementById("i"+i).style.left=
"50px";
document.getElementById("i"+i).style.opacity=0;
let n=i+1;
document.getElementById("i"+n).style.
150
transition="left 2s, opacity 2s";
document.getElementById("i"+n).style.left=
"350px";
document.getElementById("i"+n).style.opacity=1;
i++;
if(i==9)
document.getElementById("nz").style.
visibility="hidden";
}
}
function vp()
{
document.getElementById("nz").style.visibility=
"visible";
if(i>1)
{
document.getElementById("i"+i).style.
transition="left 2s, opacity 2s";
document.getElementById("i"+i).style.left=
"650px";
document.getElementById("i"+i).style.opacity=0;
let n=i-1;
document.getElementById("i"+n).style.
transition="left 2s, opacity 2s";
document.getElementById("i"+n).style.left=
"350px";
document.getElementById("i"+n).style.opacity=1;
i--;
if(i==1)
document.getElementById("vp").style.
visibility="hidden";
}
}
});
</script>
</head>
<body>
<div id="basis">
<img
<img
<img
<img
class="im"
class="im"
class="im"
class="im"
id="i1"
id="i2"
id="i3"
id="i4"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
<img class="im" id="i5" src="nat/im5.jpg" alt="Фото">
<img
<img
<img
<img
class="im"
class="im"
class="im"
class="im"
id="i6"
id="i7"
id="i8"
id="i9"
src="nat/im6.jpg"
src="nat/im7.jpg"
src="nat/im8.jpg"
src="nat/im9.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
<img id="nz" src="pict/nz.png" alt="Назад">
151
<img id="vp" src="pict/vp.png" alt="Вперед">
</div>
</body>
</html>
9.6. Галерея-аккордеон
Файл accord.html.
На взгляд автора, эта программа из данной книги одна из наиболее интересных с точки зрения визуального эффекта. Как мехи аккордеона или гармони
сжимаются и расправляются, так и фотографии в новой галерее будут вести себя похожим образом. При этом описанный результат будет достигнут максимально простым методом.
Перейдем по ссылке Галерея-аккордеон. Вы увидите начальное изображение (см. рис. 9.6.1). Оно довольно крупное, чтобы заданный эффект был более наглядным.
Под картинкой есть кнопка «Следующее фото». Нажмем ее. Исходный
снимок начнет сжиматься по горизонтали влево, пока совсем не исчезнет. Одновременно с этим справа «из ничего» начнет также по горизонтали разворачиваться следующее фото (см. рис. 9.6.2). В результате первый кадр совсем скроется, уступив место второму (см. рис. 9.6.3).
Рис. 9.6.1. Страница в исходном состоянии
152
Рис. 9.6.2. Смена картинок
Рис. 9.6.3. Новый рисунок занял место исходного
В галерее 6 элементов. Когда на экране покажется последний, на кнопке
появится надпись «Просмотр завершен».
153
Кроме начального снимка
<img class="im" id="i1" src="nat/im4.jpg" alt="Фото">
#i1 {width: 600px;}
в документе прописаны еще 5:
<img class="im" id="i2" src="nat/im8.jpg" alt="Фото">
...
<img class="im" id="i6" src="nat/im71.jpg" alt="Фото">
Эти пять снимков в исходном состоянии сжаты по ширине до 0 пикселей:
.im {... width: 0; height: 400px;}
Под ними ⸻ кнопка:
<input type="button" value="Следующее фото" id="bu">
Ее нажатие запускает анонимную функцию
document.getElementById("bu").
addEventListener("click", function()
{
...
});
Но обратим внимание, перед этим создается переменная, которая будет играть
роль счетчика картинок:
let i=1;
Ее значение соответствует числовому индексу первого рисунка.
Сценарий выполняется, пока счетчик не достигнет верхнего предела:
if(i<6)
{
...
}
В основе функции ⸻ уже знакомый нам по предыдущим двум примерам
алгоритм.
Первое фото сжимается до ширины в 0 пикселей в течение 2 секунд
document.getElementById("i"+i).style.
transition="width 2s";
document.getElementById("i"+i).style.width=0;
154
оставаясь неподвижным относительно левой координаты
document.getElementById("i"+i).style.left=0;
контейнера
<div id="bas">
...
</div>
вмещающего изображения.
Одновременно с этим разворачивается следующий рисунок
let n=i+1;
document.getElementById("i"+n).style.
transition="width 1.95s";
document.getElementById("i"+n).style.width="600px";
после чего значение счетчика увеличивается на единицу:
i++;
Когда переменная i станет равна 6
if(i==6)
просмотр остановится, а на кнопке появится сообщение об этом:
document.getElementById("bu").value=
"Просмотр завершен";
Чтобы запустить процесс по новой, перезагрузите документ.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Галерея-аккордеон</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
#bas {position: relative; margin: auto; width: 600px;
height: 400px; border: 1px solid #000000;}
.im {position: absolute; top: 0; right: 0; width: 0;
height: 400px;}
#i1 {width: 600px;}
#bu {width: 250px; height: 40px;
border: 1px solid #000000;
box-shadow: #333333 5px 5px 8px;
font-size: 20px; cursor: pointer;
margin-top: 20px;}
</style>
155
<script>
addEventListener("load", function()
{
let i=1;
document.getElementById("bu").
addEventListener("click", function()
{
if(i<6)
{
document.getElementById("i"+i).style.
transition="width 2s";
document.getElementById("i"+i).style.width=0;
document.getElementById("i"+i).style.left=0;
let n=i+1;
document.getElementById("i"+n).style.
transition="width 1.95s";
document.getElementById("i"+n).style.width=
"600px";
i++;
if(i==6)
document.getElementById("bu").value=
"Просмотр завершен";
}
});
});
</script>
</head>
<body>
<div id="basis">
<div
<img
<img
<img
id="bas">
class="im" id="i1" src="nat/im4.jpg" alt="Фото">
class="im" id="i2" src="nat/im8.jpg" alt="Фото">
class="im" id="i3" src="nat/im9.jpg" alt="Фото">
<img class="im" id="i4" src="nat/im15.jpg" alt="Фото">
<img class="im" id="i5" src="nat/im16.jpg" alt="Фото">
<img class="im" id="i6" src="nat/im71.jpg" alt="Фото">
</div>
<input type="button" value="Следующее фото" id="bu">
</div>
</body>
</html>
9.7. Галерея с ограничителями
Файл emph.html.
Перейдем по ссылке Галерея с ограничителями. Вы увидите изображение лесной дороги (см. рис. 9.7.1). Справа от него находится указатель-стрелка.
156
Нажмем ее. Изображение поменяется и одновременно слева появится еще один
указатель (см. рис. 9.7.2). Продолжаем нажимать правую стрелку до тех пор,
пока не загрузится последний, девятый снимок. В этот момент правая стрелка
исчезнет (см. рис. 9.7.3). Кстати, вы можете начать перемотку галереи в обратную сторону сразу, как только появилась кнопка слева. По достижении начала
галереи она скроется и перемотка остановится.
Рис. 9.7.1. В исходном состоянии пролистывание можно начать только вправо
Рис. 9.7.2. Здесь можно листать картинки как вперед, так и назад
157
Рис. 9.7.3. Пролистывание вправо завершено
Как и в предыдущих примерах, стрелки-указатели выполняют роль кнопок
перемотки вперед или назад. Когда загружается последнее фото, выключается
перемотка вперед. После загрузки самого первого фото выключается перемотка
назад. Вот такая простая галерея картинок.
В исходном состоянии документ содержит три элемента.
1. Рисунок
<img id="im" src="nat/im1.jpg" alt="Фото">
Как видите, сначала загружен файл im1.jpg.
2. Кнопка перемотки назад
<img id="nz" src="pict/nz.png" alt="Назад">
3. Кнопка перемотки вперед
<img id="vp" src="pict/vp.png" alt="Вперед">
Сразу после загрузки документа кнопка перемотки назад скрыта:
#nz {... visibility: hidden;}
Для управления процессом у нас зарегистрированы 2 обработчика событий
click на кнопках:
158
addEventListener("load", function()
{
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
});
Кроме того, мы предварительно объявили глобальную переменную i ⸻
счетчик изображений. Поскольку на начальном этапе загружен рисунок с индексом 1, переменной присвоено значение 1:
let i=1;
Рассмотрим сначала, что произойдет, если нажать кнопку перемотки вперед. Будет запущена функция vp:
function vp()
{
if(i<9)
{
i++;
document.getElementById("nz").style.visibility=
"visible";
document.getElementById("im").src=
"nat/im"+i+".jpg";
}
if(i==9)
document.getElementById("vp").style.
visibility="hidden";
}
Как видите, она очень простая. Ее инструкции выполняются до тех пор,
пока значение счетчика не превышает 9, то есть общего количества изображений:
if(i<9)
Щелкнем мышью на кнопке перемотки вперед. Первым делом произойдет
увеличение значения переменной:
i++;
Затем станет видимой кнопка перемотки назад:
document.getElementById("nz").style.visibility=
"visible";
После этого рисунку будет присвоен новый адрес:
document.getElementById("im").src="nat/im"+i+".jpg";
159
Так как пока мы щелкнули только однажды, загрузится изображение
im2.jpg ⸻ следующее по очереди. Кликнем на кнопке перемотки вперед еще
раз и увидим уже третью картинку. Так будет происходить до тех пор, пока выполняется главное условие функции.
Когда галерея промотана до конца
if(i==9)
выполняется еще одна инструкция, скрывающая кнопку перемотки вперед:
document.getElementById("vp").style.
visibility="hidden";
жа:
Теперь посмотрим на функцию перемотки галереи назад. Она очень похо-
function nz()
{
if(i>1)
{
i--;
document.getElementById("vp").style.visibility=
"visible";
document.getElementById("im").src=
"nat/im"+i+".jpg";
}
if(i==1)
document.getElementById("nz").style.visibility=
"hidden";
}
Только здесь главное условие другое: функция работает, пока перемотка не достигла начала галереи:
if(i>1)
Поскольку рисунки следуют в обратном порядке, после каждого щелчка на
кнопке перемотки назад переменная-счетчик уменьшается:
i--;
Теперь вспомним, что при достижении конца галереи кнопка перемотки
вперед будет скрыта. Поскольку сценарий «не знает», произошло данное событие или нет, лучше на каждом проходе функции выполнять вот такую инструкцию:
document.getElementById("vp").style.visibility=
"visible";
160
Это гарантирует, что при обратном движении изображений от последнего
кадра к началу скрытая кнопка перемотки вперед «объявится» вновь.
Пойдем дальше. После щелчка на кнопке перемотки назад будет показано
предыдущее изображение:
document.getElementById("im").src="nat/im"+i+".jpg";
Когда на странице появится первый рисунок
if(i==1)
кнопка перемотки назад станет невидимой:
document.getElementById("nz").style.visibility=
"hidden";
Просмотр не обязательно выполнять строго от начала до конца или наоборот. Вы можете изучить 2–3 первых картинки, а потом вернуться назад. Прокрутить галерею до конца, потом отмотать ее на пару снимков назад и снова
прокрутить вперед. Последовательность роли не играет. Во всех случаях сценарий будет работать корректно.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Галерея с ограничителями</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#im {position: absolute; top: 20px; left: 200px;
border: 1px solid #000000;}
#nz, #vp {position: absolute; top: 210px;
cursor: pointer;}
#nz {left: 150px; visibility: hidden;}
#vp {left: 822px;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
});
let i=1;
function nz()
{
if(i>1)
161
{
i--;
document.getElementById("vp").style.visibility=
"visible";
document.getElementById("im").src=
"nat/im"+i+".jpg";
if(i==1)
document.getElementById("nz").style.visibility=
"hidden";
}
}
function vp()
{
if(i<9)
{
i++;
document.getElementById("nz").style.visibility=
"visible";
document.getElementById("im").src=
"nat/im"+i+".jpg";
if(i==9)
document.getElementById("vp").style.
visibility="hidden";
}
}
</script>
</head>
<body>
<div id="basis">
<img id="nz" src="pict/nz.png" alt="Назад">
<img id="im" src="nat/im1.jpg" alt="Фото">
<img id="vp" src="pict/vp.png" alt="Вперед">
</div>
</body>
</html>
9.8. Замкнутая галерея
Файл circle.html.
Теперь мы попробуем написать сценарий галереи, которая «замкнута» в
кольцо. Проще говоря, достигнув конечного снимка, программа снова будет
выводить на экран первый ⸻ и далее по кругу. Или в обратном направлении:
достигнув первой фотографии, скрипт вернется к последней ⸻ и все по новой.
Кликните ссылку Замкнутая галерея и вы увидите именно такую программу (см. рис. 9.8.1).
Сразу после загрузки документа в окне браузера демонстрируется снимок
лесной дороги. Щелкнем правой кнопкой с изображением стрелки. Появится
фото с другим лесным пейзажем. Еще щелчок ⸻ возникает картина вечернего
162
неба. И так далее по порядку увеличения номера фото. В галерее всего 9 рисунков. Последний демонстрирует цветы на поляне. Если теперь щелкнуть на правой стрелке, вновь появится снимок лесной дороги. Круг замкнулся. Дальнейшие щелчки на этой кнопке будут выводить на экран уже знакомые нам кадры в
том же порядке. Такая замкнутая «круговерть» может продолжаться, пока у посетителя хватает интереса и терпения. Если щелкать левой кнопкой со стрелкой,
то последовательность демонстрации фотографий будет обратной ⸻ и тоже по
замкнутому кругу.
Рис. 9.8.1. Замкнутая галерея, где снимки меняются по кругу
Итак, все отличие двух событий click, происходящих на разных кнопках, ⸻ в направлении пролистывания фото.
Чтобы создать такую галерею, снова разместим на странице картинку и
две кнопки, причем теперь сразу видны обе:
<img id="nz" src="pict/nz.png" alt="Назад">
<img id="im" src="nat/im1.jpg" alt="Фото">
<img id="vp" src="pict/vp.png" alt="Вперед">
Зарегистрируем обработчики:
window.addEventListener("load", function()
{
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
});
163
и переменную-счетчик:
let i=1;
Для разнообразия начнем с ситуации, когда фотографии демонстрируются
в обратном порядке. Эти манипуляции выполняет функция nz:
function nz()
{
if(i>1)
{
i--;
document.getElementById("im").src=
"nat/im"+i+".jpg";
}
else
{
i=9;
document.getElementById("im").src=
"nat/im"+i+".jpg";
}
}
Действия обработчика зависят от истинности или ложности условия if(i>1).
Так как в момент первого клика на кнопке «Назад» данное условие ложно, то
выполняются операторы второго блока:
i=9;
document.getElementById("im").src="nat/im"+i+".jpg";
Переменной i присваивается значение 9 и на страницу выводится последний снимок. После этого условие if(i>1) становится истинным. В результате
при следующем клике «в дело» вступит первый блок инструкций:
i--;
document.getElementById("im").src="nat/im"+i+".jpg";
Переменная i уменьшится на единицу, и появится фото с номером 8. Новый щелчок опять уменьшает переменную i, благодаря чему демонстрируется
картинка под номером 7. Так происходит до тех пор, пока i > 1. Как только на
экране появится первый рисунок, очередной клик приведет к тому, что вновь
будет запущен второй блок, переменная i получит значение 9, цикл замкнется и
просмотр изображений пойдет по второму кругу.
Функция перемотки снимков вперед выглядит похоже:
function vp()
{
if(i<9)
{
i++;
document.getElementById("im").src=
"nat/im"+i+".jpg";
164
}
else
{
i=1;
document.getElementById("im").src=
"nat/im"+i+".jpg";
}
}
Здесь проверяется условие if(i<9). Когда оно истинно, работает первый
блок инструкций. Каждый новый клик увеличивает переменную i на единицу, а
в результате демонстрируется следующая по возрастанию номеров фотография.
Когда на странице оказывается последний снимок, очередной щелчок мышью
приводит в действие второй блок инструкций, в котором переменная i получает
значение 1 и вновь показывается самая первая фотография. Так замыкается
цикл прямого направления прокрутки снимков.
В завершение добавлю, что менять направление просмотра фотографий
можно в любой момент ⸻ обработчики легко справятся с этой задачей, так как
текущее значение переменной i доступно в обеих функциях.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Замкнутая галерея</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#im {position: absolute; top: 20px; left: 200px;
border: 1px solid #000000;}
#nz, #vp {position: absolute; top: 210px;
cursor: pointer;}
#nz {left: 150px;}
#vp {left: 822px;}
</style>
<script>
window.addEventListener("load", function()
{
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
});
let i=1;
function nz()
{
if(i>1)
{
i--;
document.getElementById("im").src=
"nat/im"+i+".jpg";
165
}
else
{
i=9;
document.getElementById("im").src=
"nat/im"+i+".jpg";
}
}
function vp()
{
if(i<9)
{
i++;
document.getElementById("im").src=
"nat/im"+i+".jpg";
}
else
{
i=1;
document.getElementById("im").src=
"nat/im"+i+".jpg";
}
}
</script>
</head>
<body>
<div id="basis">
<img id="nz" src="pict/nz.png" alt="Назад">
<img id="im" src="nat/im1.jpg" alt="Фото">
<img id="vp" src="pict/vp.png" alt="Вперед">
</div>
</body>
</html>
9.9. Оптимальная галерея
Файл gallery.html.
Последний сценарий данной главы является комбинацией из отдельных
составляющих примеров, показанных в разделах 7.1 и 9.7. Особенность этой
галереи в том, что она сразу демонстрирует все превью фотографий. Но, увеличив одну из них, можно с помощью кнопок «Вперед» и «Назад» смотреть
остальные увеличенные снимки, не возвращаясь к миниатюрам.
Перейдите по ссылке Оптимальная галерея и вы увидите в окне браузера
9 картинок (см. рис. 9.9.1). Кликните на любой из них. Изображение в натуральную величину возникнет на белом полупрозрачном фоне поверх страницы
(см. рис. 9.9.2). Рядом с фото появятся кнопки просмотра галереи (см.
рис. 9.9.3). Она имеет ограничения по перемотке вперед и назад, как это было
сделано в примере из раздела 9.7.
166
Рис. 9.9.1. Коллекция фотографий на странице
Рис. 9.9.2. Просмотр увеличенного фото с возможностью пролистать большие изображения без возврата на базовую часть страницы
167
Если кликнуть первый кадр, то будет отсутствовать левая стрелка. Если
кликнуть последний рисунок, то отсутствовать будет правая стрелка. Кнопки
работают как и в знакомой нам галерее с ограничителями.
Документ содержит 9 изображений:
<img class="im" src="nat/im1.jpg" alt="Фото">
...
<img class="im" src="nat/im9.jpg" alt="Фото">
и два фоновых слоя с кнопками для демонстрации увеличенного снимка:
<div id="bas"></div>
<div id="view">
<img id="nz" src="pict/nz.png" alt="Назад">
<img id="pict" src="pict/net.jpg" alt="Фото">
<img id="vp" src="pict/vp.png" alt="Вперед">
</div>
В сценарии надо зарегистрировать четыре обработчика для пяти событий.
Для скрытия большой картинки по щелчку на ней или при прокрутке страницы служит функция del:
addEventListener("scroll", del);
document.getElementById("pict").
addEventListener("click", del);
Рис. 9.9.3. Пролистывание галереи вправо завершено
168
Нажатие кнопок-стрелок обрабатывают две функции:
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
Клик на любой миниатюре запускает анонимную функцию
document.getElementById("basis").
addEventListener("click", function(ev)
{
...
});
Как уже было в аналогичных случаях, создаем переменные для обращения
к соответствующим элементам страницы:
let view=document.getElementById("view").style;
let bas=document.getElementById("bas").style;
let pict=document.getElementById("pict");
Кроме того, вводим еще две переменные. Для хранения данных о количестве снимков в документе
let n=document.querySelectorAll(".im").length;
а также идентификатор индекса выбранного фото:
let i=1;
При щелчке на одной из миниатюр вычисляется прокрутка страницы
let sc=window.pageYOffset;
выполняется смещение фоновых слоев на эту величину:
bas.top=sc+"px";
view.top=sc+"px";
демонстрируемому увеличенному изображению присваивается адрес выбранного снимка
pict.src=ev.target.src;
и фоновые слои делаются видимыми:
view.visibility="visible";
bas.visibility="visible";
169
Затем определяем числовой индекс «кликнутого» рисунка, разбивая его
имя по первым символам im:
let rig=ev.target.src.split("im");
и по символам расширения:
let lef=rig[1].split(".j");
Полученный результат присваиваем переменной i:
i=lef[0];
Далее «включаем» демонстрацию кнопок:
document.getElementById("vp").style.visibility=
"visible";
document.getElementById("nz").style.visibility=
"visible";
Теперь выясняем, надо ли скрыть правую или левую кнопки. Если был запущен просмотр первого изображения, то скрываем кнопку «Назад»:
if(i==1)
document.getElementById("nz").style.
visibility="hidden";
Если был запущен просмотр последнего изображения, то скрываем кнопку
«Вперед»:
if(i==n)
document.getElementById("vp").style.
visibility="hidden";
Предположим, что сейчас на фоновом слое видны обе кнопки. Посмотрим,
как их нажатие будет приводить к перемотке элементов галереи.
Когда мы нажимаем кнопку «Назад», запускается функция nz:
function nz()
{
...
}
Первым делом включаем видимость кнопки «Вперед», если она была
скрыта:
document.getElementById("vp").style.visibility=
"visible";
170
Уже знакомым нам способом узнаем номер увеличенного снимка:
let posi=document.getElementById("pict").src;
let rig=posi.split("im");
let lef=rig[1].split(".j");
i=lef[0];
Функция работает, пока значение идентификатора i больше единицы:
if(i>1)
{
...
}
Если условие истинно, уменьшаем значение идентификатора:
i--;
«Проявляем» кнопку «Вперед», если она была скрыта:
document.getElementById("vp").style.visibility=
"visible";
Загружаем на фоновый слой рисунок, индекс которого меньше на единицу:
document.getElementById("pict").src=
"nat/im"+i+".jpg";
Если демонстрируемое теперь фото имеет индекс первого элемента, скрываем кнопку «Назад»:
if(i==1)
document.getElementById("nz").style.
visibility="hidden";
Функция vp работает похожим образом.
function vp()
{
...
}
Включаем видимость кнопки «Назад», если она была скрыта:
document.getElementById("nz").style.visibility=
"visible";
Узнаем номер увеличенного снимка:
let posi=document.getElementById("pict").src;
171
let rig=posi.split("im");
let lef=rig[1].split(".j");
i=lef[0];
Инструкции функции выполняются, пока значение идентификатора i
меньше n:
if(i<n)
{
...
}
Ели условие истинно, увеличиваем значение идентификатора:
i++;
«Проявляем» кнопку «Назад», если она была скрыта:
document.getElementById("nz").style.visibility=
"visible";
Загружаем на фоновый слой рисунок, индекс которого больше на единицу:
document.getElementById("pict").src=
"nat/im"+i+".jpg";
Если демонстрируемое теперь фото имеет индекс последнего элемента,
скрываем кнопку «Вперед»:
if(i==n)
document.getElementById("vp").style.
visibility="hidden";
Функция del вам уже хорошо знакома по нескольким предыдущим сценариям:
function del()
{
view.visibility="hidden";
bas.visibility="hidden";
pict.src="pict/net.jpg";
document.getElementById("nz").style.
visibility="hidden";
document.getElementById("vp").style.
visibility="hidden";
}
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
172
<head>
<meta charset="utf-8">
<title>Оптимальная галерея</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
.im {border: 1px solid #000000; width: 300px;
cursor: pointer; margin: 10px;}
#bas, #view {position: absolute; left: 0; top: 0;
width: 100%; height: 100%; visibility: hidden;}
#bas {z-index: 1; background: #FFFFFF;
opacity: 0.95;}
#view {z-index: 2; display: flex;
justify-content: center; align-items: center;}
#pict {border: 1px solid #000000; cursor: pointer;}
#nz, #vp {cursor: pointer;}
#nz {margin-right: 20px;}
#vp {margin-left: 20px;}
</style>
<script>
addEventListener("load", function()
{
addEventListener("scroll", del);
document.getElementById("pict").
addEventListener("click", del);
document.getElementById("nz").
addEventListener("click", nz);
document.getElementById("vp").
addEventListener("click", vp);
let view=document.getElementById("view").style;
let bas=document.getElementById("bas").style;
let pict=document.getElementById("pict");
let n=document.querySelectorAll(".im").length;
let i=1;
document.getElementById("basis").
addEventListener("click", function(ev)
{
if(ev.target.tagName=="IMG")
{
let sc=window.pageYOffset;
bas.top=sc+"px";
view.top=sc+"px";
pict.src=ev.target.src;
view.visibility="visible";
bas.visibility="visible";
let rig=ev.target.src.split("im");
let lef=rig[1].split(".j");
i=lef[0];
document.getElementById("vp").style.visibility=
"visible";
173
document.getElementById("nz").style.visibility=
"visible";
if(i==1)
document.getElementById("nz").style.
visibility="hidden";
if(i==n)
document.getElementById("vp").style.
visibility="hidden";
}
});
function del()
{
view.visibility="hidden";
bas.visibility="hidden";
pict.src="pict/net.jpg";
document.getElementById("nz").style.
visibility="hidden";
document.getElementById("vp").style.
visibility="hidden";
}
function nz()
{
document.getElementById("vp").style.visibility=
"visible";
let posi=document.getElementById("pict").src;
let rig=posi.split("im");
let lef=rig[1].split(".j");
i=lef[0];
if(i>1)
{
i--;
document.getElementById("vp").style.visibility=
"visible";
document.getElementById("pict").src=
"nat/im"+i+".jpg";
if(i==1)
document.getElementById("nz").style.
visibility="hidden";
}
}
function vp()
{
document.getElementById("nz").style.visibility=
"visible";
let posi=document.getElementById("pict").src;
let rig=posi.split("im");
let lef=rig[1].split(".j");
i=lef[0];
if(i<n)
{
i++;
174
document.getElementById("nz").style.visibility=
"visible";
document.getElementById("pict").src=
"nat/im"+i+".jpg";
if(i==n)
document.getElementById("vp").style.
visibility="hidden";
}
}
});
</script>
</head>
<body>
<div id="bas"></div>
<div id="view">
<img id="nz" src="pict/nz.png" alt="Назад">
<img id="pict" src="pict/net.jpg" alt="Фото">
<img id="vp" src="pict/vp.png" alt="Вперед">
</div>
<div id="basis">
<img class="im" src="nat/im1.jpg" alt="Фото">
<img class="im" src="nat/im2.jpg" alt="Фото">
<img class="im" src="nat/im3.jpg" alt="Фото"><br>
<img class="im" src="nat/im4.jpg" alt="Фото">
<img class="im" src="nat/im5.jpg" alt="Фото">
<img class="im" src="nat/im6.jpg" alt="Фото"><br>
<img class="im" src="nat/im7.jpg" alt="Фото">
<img class="im" src="nat/im8.jpg" alt="Фото">
<img class="im" src="nat/im9.jpg" alt="Фото">
</div>
</body>
</html>
175
10. Автоматические слайдеры
«Фишка» многих ресурсов ⸻ дать посетителям возможность выбирать
разные способы просмотра галерей фотографий: в ручном режиме или в автоматическом. Последний вариант мы назовем автоматическими слайдерами.
У всех разные вкусы, и способность программиста удовлетворить их повышает
рейтинг сайта. Мы не станем отставать от лидеров web-индустрии и создадим
свои слайд-шоу. В этой главе мы рассмотрим два примера таких программ.
В первом случае слайды будут «уезжать» влево за границы экрана. Во втором они станут растворяться, уступая место лежащим ниже.
10.1. «Левый» слайдер
Файл left.html.
Итак, щелкаем по ссылке «Левый» слайдер. На странице появится изображение лесной дороги (см. рис. 10.1.1). Не спешим, ждем. Спустя 2 секунды
снимок «уедет» влево, а вместо него останется изображение другой лесной дороги (см. рис. 10.1.2). Еще через 2 секунды эта картинка плавно сместиться влево за границы экрана, и вы увидите фотографию заката с птицами, кружащими
в вечернем небе. Ждем. Этот рисунок тоже отправится за границы монитора и
на его месте возникнет новый. И так далее. В этой серии последним будет шестой кадр. После него вновь появится первая картинка, и просмотр возобновится.
Рис. 10.1.1. Начальный вид страницы
176
Рис. 10.1.2. Верхнее изображение уходит влево, открывая следующее
Для этого примера необходимо определенное расположение фотографий.
Если быть точным, они сложены «стопкой»:
<img
<img
<img
<img
<img
<img
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
src="nat/im6.jpg"
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
id="p1"
id="p2"
id="p3"
id="p4"
id="p5"
id="p6"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
Это подтверждается их настройками:
.im
#p1
#p2
#p3
#p4
#p5
#p6
тия:
{position: absolute; left: 200px; top: 20px; ...}
{z-index: 16;}
{z-index: 15;}
{z-index: 14;}
{z-index: 13;}
{z-index: 12;}
{z-index: 11;}
Для автоматического запуска слайд-шоу зарегистрируем обработчик собы-
addEventListener("load", drive);
Перед функцией drive() (в переводе на русский язык ⸻ ездить) объявим
четыре переменные:
let
let
let
let
i=1;
k=200;
s=1;
t="";
177
Переменная i ⸻ идентификатор начала процесса. Рассматривая работу
программы, мы первым делом объясним ее назначение. k ⸻ счетчик смещения
фотографии влево, s ⸻ счетчик снимков, t ⸻ идентификатор таймера.
Теперь сама функция:
function drive()
{
let ph="p"+s;
if(i==1)
{
i=0;
window.setTimeout(drive, 2000);
}
else
{
if(s<7)
{
if(k>=-3000)
{
document.getElementById(ph).style.left=
k+"px";
k-=10;
t=window.setTimeout(drive, 10);
}
else
{
k=200;
s++;
t=window.setTimeout(drive, 10);
}
}
if(s==6)
{
document.getElementById("p1").style.zIndex=10;
document.getElementById("p1").style.left=
"200px";
}
if(s==7)
{
document.getElementById("p1").style.zIndex=16;
for(let n=2; n<7; n++)
document.getElementById("p"+n).style.left=
"200px";
s=1;
}
}
window.clearTimeout(t);
drive();
}
178
В переменную ph поочередно «загружается» id каждого снимка
(ph="p"+s).
Первым выполняется блок
if(i==1)
{
i=0;
window.setTimeout(drive, 2000);
}
Если бы он отсутствовал, верхнее изображение начало бы движение сразу
после загрузки страницы. При наличии такого блока мы даем посетителю 2 секунды на просмотр первой фотографии. Затем i становится равно нулю, и
функция вызывается заново. Теперь первый блок пропускается, так как условие
if(i==1) ложно, и начинают выполняться следующие инструкции. Таким образом, программа, «ориентируясь» на значение переменной i, «понимает», первый
это вызов или нет, надо задержать верхний снимок или нет.
Дальше все просто. Если значение счетчика рисунков меньше 7
if(s<7)
а значение смещения первой картинки меньше –3000
if(k>=-3000)
свойству left фотографии присваивается значение переменной k. Сейчас у нас
идет речь о верхнем снимке, поэтому id="p1", а значение left составляет 200px
(начальное значение k = 200 выбрано именно таким, поскольку в исходном положении все фотографии внутри базового слоя смещены на 200 пикселей).
Происходит выполнение оператора k‒ = 10, и функция drive() спустя 10 миллисекунд вызывается снова. Теперь значение left составляет 190px, и посетитель
видит, как изображение начинает смещаться влево. Так повторяется до тех пор,
пока выполняется условие k> = ‒3000. То есть снимок «уходит» влево в общей
сложности на 3200 пикселей от начального положения. Этого достаточно, чтобы скрыться с экрана самого большого монитора.
Когда верхняя фотография полностью исчезла, программа переходит к
следующему блоку инструкций:
k=200;
s++;
window.setTimeout(drive, 10);
Теперь переменная s увеличивается на единицу, и функция приступает к
работе с фотоснимком im2.jpg. Поскольку условие k>= ‒3000 снова истинно,
повторяется выполнение блока
document.getElementById(ph).style.left=k+"px";
k-=10;
t=window.setTimeout(drive, 10);
179
Затем исчезает фото im2.jpg, и программа «берется» за третий снимок.
И так далее. Таким образом, дело доходит до последнего ⸻ im6.jpg. В этот момент становится истинным условие if(s==6) и самое первое изображение возвращается на исходную позицию
document.getElementById("p1").style.left="200px";
но при этом располагаясь ниже последнего, шестого рисунка:
document.getElementById("p1").style.zIndex=10;
После его исчезновения условие if(s<7) становится ложным и выполнение программы возобновляется:
if(s==7)
{
document.getElementById("p1").style.zIndex=16;
for(let n=2; n<7; n++)
document.getElementById("p"+n).style.left=
"200px";
s=1;
window.clearTimeout(t);
drive();
}
На этом этапе первой картинке возвращается ее исходный z-index:
document.getElementById("p1").style.zIndex=16;
Затем в цикле остальные рисунки перемещаются в исходное положение:
for(let n=2; n<7; n++)
document.getElementById("p"+n).style.left="200px";
Счетчику снимков вновь присваивается значение 1:
s=1;
Таймер останавливается
window.clearTimeout(t);
и функция запускается по новой:
drive();
Начинается повторный просмотр снимков.
180
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>"Левый" слайдер</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
.im {position: absolute; left: 200px; top: 20px;
border: 1px solid #000000;}
#p1 {z-index: 16;}
#p2 {z-index: 15;}
#p3 {z-index: 14;}
#p4 {z-index: 13;}
#p5 {z-index: 12;}
#p6 {z-index: 11;}
</style>
<script>
addEventListener("load", drive);
let
let
let
let
i=1;
k=200;
s=1;
t="";
function drive()
{
let ph="p"+s;
if(i==1)
{
i=0;
window.setTimeout(drive, 2000);
}
else
{
if(s<7)
{
if(k>=-3000)
{
document.getElementById(ph).style.left=
k+"px";
k-=10;
t=window.setTimeout(drive, 10);
}
else
{
k=200;
s++;
t=window.setTimeout(drive, 10);
}
}
if(s==6)
{
document.getElementById("p1").style.zIndex=10;
181
document.getElementById("p1").style.left=
"200px";
}
if(s==7)
{
document.getElementById("p1").style.zIndex=16;
for(let n=2; n<7; n++)
document.getElementById("p"+n).style.left=
"200px";
s=1;
window.clearTimeout(t);
drive();
}
}
}
</script>
</head>
<body>
<div id="basis">
<img
<img
<img
<img
<img
<img
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
src="nat/im6.jpg"
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
id="p1"
id="p2"
id="p3"
id="p4"
id="p5"
id="p6"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
</div>
</body>
</html>
10.2. Слайдер c растворением
Файл slide.html.
В новом слайдере смена изображений происходит методом «растворения».
Кликните ссылку Слайдер c растворением. Вы увидите страницу, аналогичную той, что наблюдали в разделе 10.1 (см. рис. 10.2.1). Только теперь картинки не уезжают в сторону, а медленно проявляются сквозь друг друга (см.
рис. 10.2.2).
В основе страницы все те же шесть рисунков:
<img
<img
<img
<img
<img
<img
id="i1"
id="i2"
id="i3"
id="i4"
id="i5"
id="i6"
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
src="nat/im6.jpg"
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
расположенные стопкой. Только теперь верхний снимок виден, а нижние ⸻ нет:
182
.im {position: absolute; top: 10px; left: 200px;
... opacity: 0;}
#i1 {opacity: 1;}
Рис. 10.2.1. Исходный вид страницы
Рис. 10.2.2. Верхний снимок «растворяется», сквозь него «проявляется» нижний
183
Программа работает по следующему принципу. После загрузки страницы
выдерживается пауза в 2 секунды, после чего запускается функция diss:
addEventListener("load", function()
{
window.setTimeout(diss, 2000);
});
Создается счетчик проходов сценария:
let s=1;
У функции diss две стадии исполнения. Первая ⸻ при условии, что количество продемонстрированных кадров меньше 6. Вторая ⸻ вслед за превышением этого показателя:
function diss()
{
if(s<6)
{
...
}
else
{
...
}
}
Сразу после запуска функции выполняются четыре операции. Вычисляется
id текущего рисунка
let a="i"+s;
создается переменная для обращения к свойствам картинки
let t=document.getElementById(a).style;
задается время «растворения»
t.transition="opacity 2s";
и плавно снижается показатель непрозрачности текущего изображения
t.opacity=0;
Затем значение счетчика увеличивается на единицу:
s++;
и происходит обратный процесс: вычисляется id следующего рисунка
a="i"+s;
создается переменная для обращения к свойствам следующей картинки
t=document.getElementById(a).style;
184
задается время ее «проявления»
t.transition="opacity 2s";
и плавно увеличивается показатель ее непрозрачности
t.opacity=1;
В результате вторая картинка проявляется сквозь исчезающую первую.
Затем по прошествии 3 секунд процесс возобновляется:
window.setTimeout(diss, 3000);
Когда на мониторе оказывается последний, шестой снимок, запускается
процесс повторной демонстрации изображений. Счетчик проходов получает
начальное значение
s=1;
последний, шестой кадр растворяется:
let t=document.getElementById("i6").style;
t.transition="opacity 2s";
t.opacity=0;
первый же, наоборот, проявляется:
t=document.getElementById("i1").style;
t.transition="opacity 2s";
t.opacity=1;
и через 3 секунды процесс возобновляется:
window.setTimeout(diss, 3000);
Так достигается замкнутый цикл автоматической демонстрации снимков.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Слайдер c растворением</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
.im {position: absolute; top: 10px; left: 200px;
border: 1px solid #000000; opacity: 0;}
#i1 {opacity: 1;}
185
</style>
<script>
addEventListener("load", function()
{
window.setTimeout(diss, 2000);
});
let s=1;
function diss()
{
if(s<6)
{
let a="i"+s;
let t=document.getElementById(a).style;
t.transition="opacity 2s";
t.opacity=0;
s++;
a="i"+s;
t=document.getElementById(a).style;
t.transition="opacity 2s";
t.opacity=1;
window.setTimeout(diss, 3000);
}
else
{
s=1;
let t=document.getElementById("i6").style;
t.transition="opacity 2s";
t.opacity=0;
t=document.getElementById("i1").style;
t.transition="opacity 2s";
t.opacity=1;
window.setTimeout(diss, 3000);
}
}
</script>
</head>
<body>
<div id="basis">
<img
<img
<img
<img
<img
<img
id="i1"
id="i2"
id="i3"
id="i4"
id="i5"
id="i6"
class="im"
class="im"
class="im"
class="im"
class="im"
class="im"
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
src="nat/im6.jpg"
</div>
</body>
</html>
186
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
alt="Фото">
11. Загрузка по частям
Далеко не всегда web-страницы содержат фиксированное количество
снимков. Достаточно часто они добавляются по мере необходимости в зависимости от тех или иных действий пользователей.
В этой главе мы рассмотрим три примера для двух разных случаев добавления графического контента:
– появление новых рисунков при нажатии на соответствующую кнопку;
– появление новых рисунков при прокрутке страницы вниз.
11.1. Добавляем снимки
Файл addit.html.
Пример, который вы можете видеть, перейдя по ссылке Добавляем снимки, очень простой. Есть страница, на которой расположены 9 фотографий природы (см. рис. 11.1.1). Под ними кнопка «Еще фото...». Каждое нажатие этой
кнопки приводит в тому, что в нижней части страницы появляются три очередных снимка (см. рис. 11.1.2). Когда все рисунки из папки nat окажутся загружены, на кнопке появится надпись «Просмотр завершен».
Рис. 11.1.1. Начальный вид страницы
187
Рис. 11.1.2. После нажатия кнопки «Еще фото» появились три новых рисунка
Это наиболее элементарный пример загрузки графического контента по
частям.
Основа документа ⸻ контейнер div, в котором изначально прописаны
9 картинок:
<div id="basis">
<img src="nat/im1.jpg" alt="Фото">
...
<img src="nat/im9.jpg" alt="Фото">
</div>
Под ними кнопка
<p id="addit">ЕЩЕ ФОТО...</p>
Ее нажатие запускает анонимную функцию:
document.getElementById("addit").
addEventListener("click", function()
{
...
});
188
Но перед этим создается счетчик кадров:
let i=10;
Фотографии добавляются при условии, что значение счетчика меньше 100
(в папке nat 99 изображений):
if(i<100)
{
...
}
Пока это условие истинно, при каждом щелчке выполняются несколько
операций. Создается переменная a с кодом фото, числовой индекс которого равен i:
let a='<br><img src="nat/im'+i+'.jpg" alt="Фото"> ';
Затем значение счетчика увеличивается на единицу, и создается код следующего рисунка:
i++;
let b='<img src="nat/im'+i+'.jpg" alt="Фото"> ';
После чего счетчик еще раз увеличивается, и формируется код третьей картинки:
i++;
let c='<img src="nat/im'+i+'.jpg" alt="Фото"> ';
Теперь счетчик подготавливается к следующему циклу. Подготовка заключается в увеличении значения переменной i еще на единицу:
i++;
Последняя операция цикла ⸻ добавление снимков в контейнер перед его
закрывающим тегом (то есть в конец галереи) с помощью метода
insertAdjacentHTML:
document.getElementById("basis").
insertAdjacentHTML("beforeend", a+b+c);
Когда загружаются три последних снимка, счетчик i получает значение 100.
В этот момент работа программы прерывается, а на кнопке появляется надпись
«Просмотр завершен»:
if(i>99)
document.getElementById("addit").innerHTML=
"Просмотр завершен";
189
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Добавляем снимки</title>
<style>
#basis {margin: auto; margin-top: 20px;
width: 1000px; text-align: center;}
img {width: 300px;}
#addit {margin: auto; width: 350px; font-size: 20px;
text-align: center; color: #FFFFFF;
font-weight: bold; background: #0000CC;
border-radius: 3px;
box-shadow: 5px 5px 10px #000000;
padding: 10px; margin-top: 20px;
cursor: pointer;}
</style>
<script>
addEventListener("load", function()
{
let i=10;
document.getElementById("addit").
addEventListener("click", function()
{
if(i<100)
{
let a='<br><img src="nat/im'+i+
'.jpg" alt="Фото"> ';
i++;
let b='<img src="nat/im'+i+'.jpg"
alt="Фото"> ';
i++;
let c='<img src="nat/im'+i+'.jpg"
alt="Фото"> ';
i++;
document.getElementById("basis").
insertAdjacentHTML("beforeend", a+b+c);
if(i>99)
document.getElementById("addit").innerHTML=
"Просмотр завершен";
}
});
});
</script>
</head>
<body>
<div id="basis">
<img src="nat/im1.jpg" alt="Фото">
<img src="nat/im2.jpg" alt="Фото">
<img src="nat/im3.jpg" alt="Фото"><br>
<img src="nat/im4.jpg" alt="Фото">
<img src="nat/im5.jpg" alt="Фото">
<img src="nat/im6.jpg" alt="Фото"><br>
190
<img src="nat/im7.jpg" alt="Фото">
<img src="nat/im8.jpg" alt="Фото">
<img src="nat/im9.jpg" alt="Фото">
</div>
<p id="addit">ЕЩЕ ФОТО...</p>
</body>
</html>
11.2. Последовательное проявление
Файл opac.html.
Наверное, вы не раз видели сайты, на страницах которых отдельные блоки
контента «проявляются» сквозь фон по мере прокрутки страницы вниз. Именно
такой эффект мы и попробуем создать.
Переходим по ссылке Последовательное проявление. Что мы видим? Ту
же самую картину, что и на рисунке 11.2.1. А именно ⸻ фото лесной дороги.
Начнем двигать ползунок вниз (см. рис. 11.2.2) ⸻ и по мере его прокрутки на
странице станут поочередно «проявляться» фотографии еще четырех пейзажей.
Заметим, что проявление будет плавным (см. рис. 11.2.3). Когда все пять картинок появятся на странице, процесс остановится. Это означает, что весь контент
загрузился полностью. Попутно добавим, что для наглядности лучше перемещать ползунок не спеша.
Рис. 11.2.1. Начальный вид страницы
191
Рис. 11.2.2. Начинаем прокручивать страницу вниз
Теперь разберемся в принципе работы программы.
Разместим на странице 5 разных снимков:
<img src="nat/im1.jpg" alt="Фото" id="im1"><br>
<img src="nat/im2.jpg" alt="Фото" id="im2"
class="ima"><br>
<img src="nat/im3.jpg" alt="Фото" id="im3"
class="ima"><br>
<img src="nat/im4.jpg" alt="Фото" id="im4"
class="ima"><br>
<img src="nat/im5.jpg" alt="Фото" id="im5"
class="ima">
В исходном состоянии 4 снимка (class="ima") не видны. Их непрозрачность равна нулю:
.ima {opacity: 0;}
«Проявлением» изображений управляет функция scro:
addEventListener("scroll", scro);
Для ее работы нам понадобятся две переменные:
let i=2;
let c=2;
192
Рис. 11.2.3. Появляется второй рисунок
Переменная i ⸻ счетчик фотографий, а c ⸻ идентификатор состояния программы. Его назначение вы поймете в процессе разбора функции scro. Вот она:
function scro()
{
if(i<6)
{
let a=400*i-800;
if(window.pageYOffset>a)
{
if(c==1)
{
let b="im"+i;
document.getElementById(b).style.transition=
"opacity 3s";
document.getElementById(b).style.opacity=1;
}
}
c=2;
i++;
}
if((window.pageYOffset>a+250)&&
(window.pageYOffset<a+390))
c=1;
}
193
Итак, вы только-только начали двигать ползунок. В этот момент условие
if(i<6) истинно, поэтому выполняется первая инструкция функции:
let a=400*i-800;
Здесь рассчитывается контрольная точка смещения ползунка на каждом шаге
выполнения программы (самая первая точка равна 0 пикселей, потому что исходное значение переменной i равно 2). Так как в начальном состоянии идентификатору c присвоено значение 2, первый блок инструкций пропускается
(условие if(c==1) ложно).
Продолжаем двигать ползунок. Когда его смещение от первой контрольной точки превысит 250 пикселей, но не достигнет 390
if((window.pageYOffset>a+250)&&
(window.pageYOffset<a+390))
идентификатору c будет присвоено значение 1
c=1;
и выполнится первый блок инструкций:
if(c==1)
{
let b="im"+i;
document.getElementById(b).style.transition=
"opacity 3s";
document.getElementById(b).style.opacity=1;
c=2;
i++;
}
Длительность проявления снимка 3 секунды. Какое фото должно быть «проявлено», вычисляется в выражении
let b="im"+i;
В самом начале это будет фото номер 2, так как исходное значение переменной i равно 2. Дальше счетчик фото i увеличится на единицу, а идентификатору
c опять присваивается стоп-значение 2.
Начинается следующий цикл сценария. Переменная a получает новое значение ⸻ на 400 пикселей больше предыдущего. Но пока при дальнейшей прокрутке на странице остаются две фотографии. Это происходит, потому что в
данное время первый блок инструкций не может быть выполнен из-за ложности
условия if(c==1). Когда смещение ползунка от новой контрольной точки превысит 250 пикселей, но не достигнет 390, идентификатор c снова изменит значение. В результате опять выполнится первый блок инструкций, который «про194
явит» третью фотографию и увеличит счетчик i еще на единицу. Думаю, следующие повторяющиеся шаги уже понятны.
Что мы имеем в итоге? Второе изображение появляется при смещении
ползунка на 250 пикселей. Затем каждая последующая прокрутка страницы на
400 пикселей увеличивает значение счетчика фотографий на единицу. То есть
следующие рисунки появляются с шагом в 400 пикселей. Идентификатор c
«следит», чтобы значение счетчика изменялось для одной контрольной точки
только один раз. Так как событие scroll происходит не на каждом пикселе полосы прокрутки, мы взяли не конкретную точку срабатывания второго блока
инструкций, а интервал от 250 до 390 пикселей, в рамках которого событие
scroll точно произойдет. Наконец, условие if(i<6) ограничивает наш сценарий
«проявлением» пяти снимков.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Последовательное проявление</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; padding-bottom: 100px;
padding-top: 100px; text-align: center;}
.ima {opacity: 0;}
</style>
<script>
addEventListener("scroll", scro);
let i=2;
let c=2;
function scro()
{
if(i<6)
{
let a=400*i-800;
if(window.pageYOffset>a)
{
if(c==1)
{
let b="im"+i;
document.getElementById(b).style.transition=
"opacity 3s";
document.getElementById(b).style.opacity=1;
}
c=2;
i++;
}
if((window.pageYOffset>a+250)&&
(window.pageYOffset<a+390))
195
c=1;
}
}
</script>
</head>
<body>
<div id="basis">
<img src="nat/im1.jpg" alt="Фото" id="im1"><br>
<img src="nat/im2.jpg" alt="Фото" id="im2"
class="ima"><br>
<img src="nat/im3.jpg" alt="Фото" id="im3"
class="ima"><br>
<img src="nat/im4.jpg" alt="Фото" id="im4"
class="ima"><br>
<img src="nat/im5.jpg" alt="Фото" id="im5"
class="ima">
</div>
</body>
</html>
11.3. Бесконечная лента
Файл tape.html.
Прежде чем рассказывать о сценарии бесконечной ленты, небольшой комментарий к нему. Дело в том, что для этих лент пишется специальная серверная
программа на одном из скриптовых языков. Подобная система работает так: со
страницы, открытой на компьютере клиента, серверу поступает запрос на передачу очередной порции данных. Серверная программа отбирает эти данные в
соответствии с заложенным в ней алгоритмом и отправляет обратно на страницу.
В примере из данной главы мы реализуем описанный метод, опять прибегнув к помощи серверных программ на PHP.
Итак, кликнем ссылку Бесконечная лента. Вы увидите страницу, показанную на рисунке 11.3.1. В исходном состоянии в документе 5 изображений.
Начинаем прокручивать страницу вниз. Ползунок на полосе прокрутки станет
уменьшатся, а на страницу отдельными порциями начнут загружаться новые
снимки (см. рис. 11.3.2).
Тут надо сделать оговорку. Вообще-то, любая бесконечная лента не может
быть бесконечной в истинном смысле этого слова. На самом деле длина такой
ленты ограничена количеством файлов, содержащихся на сервере и загружаемых в нее. В нашем примере аналогичная ситуация: в папке nat 99 фотографий,
следовательно длина нашей ленты составляет 99 элементов. Достигнув этого
значения, сценарий остановится (см. рис. 11.3.3).
Чтобы сделать программу универсальной, готовой к применению для лент
различной длины, сразу после загрузки страницы обратимся к серверному
скрипту tape1.php. Для этого в фоновом режиме создадим Ajax запрос, кото196
рый будет отправлен серверу (подобные запросы мы уже формировали в разделах 7.7 и 8.2):
let requ=new XMLHttpRequest();
requ.open("GET", "tape1.php", true);
requ.send();
requ.addEventListener("load", function()
{
t=Number(this.responseText)+1;
});
Но перед этим объявим две переменные:
let i=6;
let t=0;
Переменная i является счетчиком картинок. Поскольку пять из них уже на
«исходных позициях», начальное значение i установлено равным 6. t ⸻ переменная, предназначенная для получения данных о количестве рисунков на сервере.
Полученный от серверного скрипта tape1.php ответ преобразуем в число и
добавим к нему единицу, чтобы установить ограничение для количества загружаемых фото (в нашем случае значение t будет 99 плюс 1 ⸻ итого 100):
requ.addEventListener("load", function()
{
t=Number(this.responseText)+1;
});
Рис. 11.3.1. Исходный вид страницы. Обратите внимание на длину ползунка
197
Рис. 11.3.2. Прокручиваем страницу вниз. Обратите внимание на длину ползунка
Рис. 11.3.3. Все изображения загружены. Обратите внимание на длину ползунка
198
Почему мы установили в качестве ограничителя число, превышающее количество загружаемых элементов на единицу, вы поймете, разбирая основной
код сценария.
Разберем программу tape1.php:
<?php
$res=0;
$opdir=opendir("nat");
while($redir=readdir($opdir))
{
if(strpos($redir, "."))
$res+=1;
}
closedir($opdir);
echo $res;
Скрипт открывает директорию nat
$opdir=opendir("nat");
...
closedir($opdir);
и в цикле подсчитывает количество файлов в ней
while($redir=readdir($opdir))
{
if(strpos($redir, "."))
$res+=1;
}
одновременно отсекая символы текущего и вышестоящего каталогов:
if(strpos($redir, "."))
После чего данные отправляются запросившему их сценарию:
echo $res;
Теперь все готово к добавлению новых картинок.
Начинаем прокручивать страницу вниз. Это приводит к запуску соответствующей анонимной функции
addEventListener("scroll", function()
{
...
});
Определяем уровень прокрутки документа:
if(window.pageYOffset+window.innerHeight>=
199
document.body.clientHeight)
Когда ползунок достиг нижнего края, проверяем следующее условие:
if(i<t)
{
...
}
Здесь мы выясняем, не превысило ли количество запусков функции количество
изображений на сервере.
Если условие истинно, отправляем запрос программе tape2.php:
let re=new XMLHttpRequest();
let adr="tape2.php?ins="+i;
re.open("GET", adr, true);
re.send();
где указываем числовой индекс фото, которое хотим получить в качестве ответа.
Файл tape2.php устроен следующим образом. Сначала проверяем наличие
данных в запросе
if(isset($_GET['ins']))
Если они есть, создаем переменную, в которую помещаем номер запрошенного
снимка:
$i=$_GET['ins'];
Если запрос был пустым ⸻ то есть сделан недоброжелателем из посторонней
программы ⸻ то выдаем ему вот такой ответ:
else
{
echo 'НЕКОРРЕКТНЫЙ ЗАПРОС !';
return;
}
Следующий шаг ⸻ проверка данных на наличие в них только цифр:
if(preg_match('/[^0-9]/', $i))
{
echo 'НЕКОРРЕКТНЫЕ ДАННЫЕ !';
}
else
{
echo '<br><img src="nat/im'.$i.'.jpg" alt="Фото">';
}
Когда в запросе присутствуют иные символы, отправляем недоброжелателям сообщение «НЕКОРРЕКТНЫЕ ДАННЫЕ !».
200
Запрос корректен? Пересылаем сценарию ответ в виде кода очередной фотографии:
echo '<br><img src="nat/im'.$i.'.jpg" alt="Фото">';
и в основном сценарии добавляем эту картинку на страницу:
re.addEventListener("load", function()
{
let resp=this.responseText;
document.getElementById("basis").
insertAdjacentHTML("beforeend", resp);
});
Последняя операция ⸻ увеличение счетчика i на единицу:
i++;
После загрузки девяносто девятого снимка счетчик i вновь увеличится и
его значение достигнет 100. Условие
if(i<t)
станет ложным, и загрузка файлов прекратится.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Бесконечная лента</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
</style>
<script>
let i=6;
let t=0;
let requ=new XMLHttpRequest();
requ.open("GET", "tape1.php", true);
requ.send();
requ.addEventListener("load", function()
{
t=Number(this.responseText)+1;
});
addEventListener("scroll", function()
{
201
if(window.pageYOffset+window.innerHeight>=
document.body.clientHeight)
{
if(i<t)
{
let re=new XMLHttpRequest();
let adr="tape2.php?ins="+i;
re.open("GET", adr, true);
re.send();
re.addEventListener("load", function()
{
let resp=this.responseText;
document.getElementById("basis").
insertAdjacentHTML("beforeend", resp);
});
i++;
}
}
});
</script>
</head>
<body>
<div id="basis">
<img
<img
<img
<img
<img
src="nat/im1.jpg"
src="nat/im2.jpg"
src="nat/im3.jpg"
src="nat/im4.jpg"
src="nat/im5.jpg"
alt="Фото"><br>
alt="Фото"><br>
alt="Фото"><br>
alt="Фото"><br>
alt="Фото">
</div>
</body>
</html>
Код файла tape1.php:
<?php
$res=0;
$opdir=opendir("nat");
while($redir=readdir($opdir))
{
if(strpos($redir, "."))
$res+=1;
}
closedir($opdir);
echo $res;
Код файла tape2.php:
<?php
if(isset($_GET['ins']))
$i=$_GET['ins'];
else
{
echo 'НЕКОРРЕКТНЫЙ ЗАПРОС !';
202
return;
}
if(preg_match('/[^0-9]/', $i))
{
echo 'НЕКОРРЕКТНЫЕ ДАННЫЕ !';
}
else
{
echo '<br><img src="nat/im'.$i.'.jpg" alt="Фото">';
}
203
12. Перемещение изображений
Перемещение рисунков, фотографий, картинок используется разработчиками для разных целей. Наиболее часто эти методы применяются, чтобы повысить интерес посетителей к ресурсу за счет наличия на нем необычных функций. Другой пример ⸻ перемещение клиентами изображений тех или иных
продуктов в «корзину» для формирования заказов или для выбора вариантов
ответов в опросах.
В этой главе мы рассмотрим несколько простых случаев перемещения
изображений на страницах web-ресурсов.
12.1. Направляем ракету
Файл rocket.html.
В первом примере этой главы мы будем задавать направление движения
ракеты.
Перейдем по ссылке Направляем ракету. Появится страница с изображением космического аппарата в левом верхнем углу (см. рис. 12.1.1). Чтобы
управлять его перемещением, надо сначала кликнуть на изображении. А затем
вы можете щелкать мышью на любом пустом участке страницы. Если щелчок
произошел справа чуть выше исходного положения, то ракета переместится
вправо с наклоном тоже вправо (см. рис. 12.1.2). Теперь изменим координату
клика ⸻ пусть он будет ниже и левее. В этом случае ракета развернется вниз и
влево (см. рис.12.1.3). Таким образом, щелкая мышью в разных точках окна
браузера, вы меняете направление и угол наклона космического аппарата.
Рис. 12.1.1. В исходном состоянии ракета вверху слева
204
Рис. 12.1.2. После первого щелчка ракета сместилась в сторону с наклоном вправо
Рис. 12.1.3. После второго щелчка ракета сместилась вниз с наклоном влево
Откроем страницу с кодом примера. Что мы обнаружим? Рисунок ракеты в
теле документа
<img src="pict/rocket.png" id="roc" alt="Фото">
с настройками
#roc {position: absolute; top: 0px; left: 0px;
cursor: pointer;}
205
Регистрируется обработчик события click на картинке:
addEventListener("load", function()
{
document.getElementById("roc").
addEventListener("click", coor);
});
Создаем шесть переменных:
let
let
let
let
let
let
h=0;
v=0;
i=1;
c=0;
d=0;
t=1;
Переменные h и v нужны для сохранения в них координат самого первого
щелчка на ракете. Переменная i ⸻ идентификатор, по значению которого сценарий определяет, состоялся ли первый щелчок на изображении. с и d ⸻ элементы хранения текущих координат. t ⸻ идентификатор второго клика.
После щелчка на аппарате запускается функция coor:
function coor()
{
...
}
Если на картинке произошел первый клик
if(i==1)
{
...
}
вычисляются его координаты:
h=event.pageX;
v=event.pageY;
Затем переменной-идентификатору первого клика присваивается новое значение, которое отменяет повторные действия сценария при щелчке на ракете:
i=2;
Текущие координаты изображения присваиваются соответствующим переменным:
c=h;
d=v;
206
Последний шаг в выполнении функции ⸻ регистрация обработчика для
клика в любой части страницы:
addEventListener("click", rocket);
С этого момента программа готова перемещать ракету.
Итак, щелкнем мышью в произвольной точке экрана. Это приведет к вызову функции rocket:
function rocket()
{
...
}
Обратите внимание ⸻ на самом деле ее первый вызов произошел уже при
первом клике по ракете. Но в этом случае изображение останется на месте, так
как координаты клика совпадают с координатами, куда должна сместиться ракета. И поворот изображения тоже не произойдет, так как условие
if(t==2)
{
...
}
на начальном этапе дает результат false.
Тем не менее сразу будут выполнены следующие инструкции. Перемещение изображения (оно, как мы уже выяснили, не произойдет):
document.getElementById("roc").style.left=ih+"px";
document.getElementById("roc").style.top=iv+"px";
присвоение переменным координат текущего клика:
c=nh;
d=nv;
и, самое главное, изменение значения идентификатора нажатий кнопки мыши:
t=2;
Полноценная работа сценария начинается после второго щелчка. Функция
определяет координаты нового клика:
let nh=event.pageX;
let nv=event.pageY;
и высчитывает положение, в которое должно переместиться изображение:
let ih=nh-h;
let iv=nv-v;
207
Теперь условие
if(t==2)
{
...
}
истинно и в этом случае выясняется угол поворота ракеты:
if(c<nh)
{
document.getElementById("roc").style.transform=
"rotate(45deg)";
if(d<nv)
{
document.getElementById("roc").style.
transform="rotate(135deg)";
}
}
else
{
document.getElementById("roc").style.
transform="rotate(-45deg)";
if(d<nv)
{
document.getElementById("roc").style.
transform="rotate(-135deg)";
}
}
Этот угол определяется по разности координат щелчков. Если клик произошел правее и выше
if(c<nh)
то поворот выполняется на 45°:
document.getElementById("roc").style.transform=
"rotate(45deg)";
Если клик случился правее и ниже, то ракета поворачивается на 135°:
document.getElementById("roc").style.
transform="rotate(135deg)";
По аналогичному принципу рассчитываются повороты на отрицательные
углы. Если клик произошел левее и выше, то поворот выполняется на –45°:
document.getElementById("roc").style.transform=
"rotate(-45deg)";
Если клик случился левее и ниже, то ракета разворачивается на –135°:
document.getElementById("roc").style.
transform="rotate(-135deg)";
208
Вот таким образом и происходит перемещение космического аппарата.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Направляем ракету</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#roc {position: absolute; top: 0px; left: 0px;
cursor: pointer;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("roc").
addEventListener("click", coor);
});
let
let
let
let
let
let
h=0;
v=0;
i=1;
c=0;
d=0;
t=1;
function coor()
{
if(i==1)
{
h=event.pageX;
v=event.pageY;
i=2;
c=h;
d=v;
addEventListener("click", rocket);
}
}
function rocket()
{
let nh=event.pageX;
let nv=event.pageY;
let ih=nh-h;
let iv=nv-v;
if(t==2)
{
if(c<nh)
{
document.getElementById("roc").style.transform=
209
"rotate(45deg)";
if(d<nv)
{
document.getElementById("roc").style.
transform="rotate(135deg)";
}
}
else
{
document.getElementById("roc").style.transform=
"rotate(-45deg)";
if(d<nv)
{
document.getElementById("roc").style.
transform="rotate(-135deg)";
}
}
}
document.getElementById("roc").style.left=ih+"px";
document.getElementById("roc").style.top=iv+"px";
c=nh;
d=nv;
t=2;
}
</script>
</head>
<body>
<div id="basis">
<img src="pict/rocket.png" id="roc" alt="Фото">
</div>
</body>
</html>
12.2. Перемещаем солнце
Файл sun.html.
Эту программу можно посмотреть в действии, перейдя по ссылке Перемещаем солнце.
После загрузки документа вы увидите в левом верхнем углу браузера стилизованное изображение нашего светила (см. рис. 12.2.1). Наведите на него
курсор и нажмите левую кнопку мыши. Теперь солнце можно перетащить в
любое место страницы. Отпустите кнопку мыши. Солнце останется на том месте, где вы его «бросили» (см. рис. 12.2.2). Снова нажмите на изображении левую кнопку мыши и перетащите картинку в другое место, а затем отпустите
кнопку. Рисунок опять поменял свое местоположение. Таким способом вы можете передвигать солнце в пределах окна браузера.
Некоторые из вас могут подумать, что в данном сценарии реализована
технология drag-and-drop. Но это не так. Здесь мы применили другие методы.
А с технологией drag-and-drop мы познакомимся в следующем разделе.
210
Рис. 12.2.1. В исходном состоянии солнце вверху слева
Рис. 12.2.2. Перемещаем солнце в произвольном направлении
Написание программы начнем с размещения на странице изображения:
<div id="sun"></div>
Как видите, это обычный слой, фоновой картинкой которого является рисунок
солнца:
#sun {... background: url(pict/sun.png); ...}
211
В исходном состоянии «светило» находится в левом верхнем углу:
#sun {position: absolute; left: 10px; top: 10px; ...}
Перейдем к разбору примера. Как всегда, в самом начале сценария регистрируем обработчики. Их у нас два. Первый запускается, когда левая кнопка
мыши нажата над рисунком:
addEventListener("load", function()
{
document.getElementById("sun").
addEventListener("mousedown", coor);
});
Второй начинает действовать, когда кнопка мыши была отпущена:
addEventListener("mouseup", function()
{
removeEventListener("mousemove", neco);
});
Моменты запуска данных функций вы поймете, разбирая последовательность выполнения сценария.
Объявляем две глобальные переменные:
let dv=0;
let dh=0;
Их задача сохранять разности координат между начальным положением солнца
и местом первого щелчка мышью на нем. Необходимость этих переменных
станет ясна позже.
Рассмотрим функцию coor:
function coor()
{
let v=event.pageY;
let h=event.pageX;
let sv=document.getElementById("sun").offsetTop;
let sh=document.getElementById("sun").offsetLeft;
dv=v-sv;
dh=h-sh;
addEventListener("mousemove", neco);
}
Она запускается после нажатия кнопки мыши на изображении. В первых двух
строках определяются координаты указателя по осям X и Y во время нажатия
кнопки. Затем выясняются текущие координаты левого верхнего угла картинки:
let sv=document.getElementById("sun").offsetTop;
let sh=document.getElementById("sun").offsetLeft;
212
Теперь самое главное ⸻ вычисляем разницу между координатами указателя и рисунка:
dh=h-sh;
dv=v-sv;
Эти значения учитываются сценарием в дальнейших действиях. Каким образом?
Когда мы ведем мышью по странице, верхний левый угол рисунка будет все
время находиться на одном и том же ⸻ только что вычисленном ⸻ расстоянии
от указателя. Собственно, благодаря этому и обеспечивается перетаскивание
солнца ⸻ оно следует за указателем на постоянном расстоянии. Обеспечивает
такое движение функция neco, которая запускается последней инструкцией
функции coor:
addEventListener("mousemove", neco);
Функция neco ⸻ это обработчик события mousemove:
function neco()
{
let nv=event.pageY;
let nh=event.pageX;
let fv=nv-dv;
let fh=nh-dh;
document.getElementById("sun").style.top=fv+"px";
document.getElementById("sun").style.left=fh+"px";
}
В первых двух строках мы выясняем новые координаты указателя после
того, как мышь начала движение по странице:
let nv=event.pageY;
let nh=event.pageX;
Затем вычисляем смещение, которое должно получить солнце при таком движении курсора:
let fv=nv-dv;
let fh=nh-dh;
и отправляем рисунок в новое место:
document.getElementById("sun").style.top=fv+"px";
document.getElementById("sun").style.left=fh+"px";
Данные инструкции выполняются непрерывно, пока указатель «скользит» по
странице. За счет этого солнце тоже двигается за курсором.
213
Теперь представим, что мы перетащили картинку и отпустили кнопку мыши. Произойдет событие mouseup, на которое откликнется анонимная функция:
addEventListener("mouseup", function()
{
removeEventListener("mousemove", neco);
});
Ее единственная задача ⸻ прекратить обработку события mousemove, благодаря чему после отпускания кнопки мыши изображение останется на новом месте.
Еще раз переместите солнце, выбрав другую точку на картинке. «Светило»
будет следовать за указателем мыши на новом, но опять постоянном расстоянии.
Можно пробовать разные варианты переноса солнца. Во всех случаях вы
увидите, что выбранная точка картинки все время находится строго под курсором.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Перемещаем солнце</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#sun {position: absolute; left: 10px; top: 10px;
width: 200px; height: 193px;
background: url(pict/sun.png);
cursor: pointer;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("sun").
addEventListener("mousedown", coor);
});
addEventListener("mouseup", function()
{
removeEventListener("mousemove", neco);
});
let dv=0;
let dh=0;
function coor()
{
let v=event.pageY;
let h=event.pageX;
let sv=document.getElementById("sun").offsetTop;
let sh=document.getElementById("sun").offsetLeft;
dv=v-sv;
214
dh=h-sh;
addEventListener("mousemove", neco);
}
function neco()
{
let nv=event.pageY;
let nh=event.pageX;
let fv=nv-dv;
let fh=nh-dh;
document.getElementById("sun").style.top=fv+"px";
document.getElementById("sun").style.left=fh+"px";
}
</script>
</head>
<body>
<div id="basis">
<div id="sun"></div>
</div>
</body>
</html>
12.3. Освещаем пейзаж
Файл dad.html.
Наши эксперименты с изображением солнца продолжаются. В новом примере мы опробуем в действии технологию drag-and-drop.
Перейдите по ссылке Освещаем пейзаж. Вы увидите два прямоугольника
по бокам страницы. На левом ⸻ берег моря, освещенный солнцем, на правом ⸻ кромешная ночь (см. рис. 12.3.1). Нажмите левую клавишу мыши на
изображении солнца. Перетащите его на ночную картинку (см. рис. 12.3.2). Вы
увидите, как солнце зафиксируется в правом прямоугольнике, а темная ночь
сменится изображением яркого пейзажа (см. рис. 12.3.3).
Чтобы написать сценарий перемещения солнца и освещения марины, нам
необходимо создать обработчики для двух событий: dragover и drop.
Но начнем мы как всегда с компоновки необходимых элементов в теле
страницы. Для размещения изображений и создания между ними достаточного
интервала поместим в документ таблицу с тремя ячейками:
<table>
<tr>
<td id="td1"><img src="pict/sun.png" draggable="true"
id="sun" alt="Фото"></td>
<td id="td2"></td>
<td id="td3"></td>
</tr>
</table>
215
Рис. 12.3.1. Исходный вид страницы
Рис. 12.3.2. Начинаем перемещать изображение солнца на черный прямоугольник
216
Рис. 12.3.3. Солнце заняло новое положение, осветив затемненный пейзаж
В левой ячейке находится рисунок солнца
<img src="pict/sun.png" draggable="true" id="sun"
alt="Фото">
Атрибут draggable со значением true указывает, что элемент можно перетаскивать.
Фоном левой ячейки служит морской пейзаж:
#td1 {... background: url(pict/start.jpg); ...}
Правая ячейка пустая с черным фоном:
#td3 {... background: #000000; ...}
Зарегистрируем необходимые обработчики событий:
addEventListener("load", function()
{
document.getElementById("td2").
addEventListener("dragover", mid);
document.getElementById("td3").
addEventListener("dragover", mid);
document.getElementById("td3").
addEventListener("drop", fin);
});
и разберем их по порядку.
217
Итак, считаем, что перетаскивание объекта началось. Процесс затрагивает
среднюю и правую ячейки таблицы. По умолчанию браузеры блокируют перетаскивание элементов. Чтобы отменить такое поведение web-обозревателя, у
нас есть функция mid, которая обрабатывает события dragover, происходящие
в центральной и правой ячейках:
function mid()
{
event.preventDefault();
}
Метод preventDefault как раз и отменяет блокировку перетаскивания.
Второй этап ⸻ обработка события drop. Оно происходит, когда вы отпускаете изображение в узле-приемнике. Для этого события у нас есть функция fin:
function fin()
{
event.preventDefault();
document.getElementById("td3").
appendChild(document.getElementById("sun"));
document.getElementById("td3").style.background=
"url(pict/finish.jpg)";
}
Снова отменяем поведение браузера по умолчанию:
event.preventDefault();
Затем методом appendChild добавляем рисунок солнца в список дочерних
элементов данного родительского узла. В качестве такого узла или контейнераприемника у нас выступает правая ячейка:
document.getElementById("td3").
appendChild(document.getElementById("sun"));
Последняя операция ⸻ добавление фонового рисунка в третью ячейку:
document.getElementById("td3").style.background=
"url(pict/finish.jpg)";
что визуально выглядит так, словно солнце осветило ночной пейзаж.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Освещаем пейзаж</title>
218
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#sun {cursor: pointer;}
table {width: 100%;}
#td1 {width: 30%; height: 198px;
background: url(pict/start.jpg);
border: 1px solid #000000;}
#td2 {width: 40%;}
#td3 {width: 30%; height: 198px; background: #000000;
border: 1px solid #000000;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("td2").
addEventListener("dragover", mid);
document.getElementById("td3").
addEventListener("dragover", mid);
document.getElementById("td3").
addEventListener("drop", fin);
});
function mid()
{
event.preventDefault();
}
function fin()
{
event.preventDefault();
document.getElementById("td3").
appendChild(document.getElementById("sun"));
document.getElementById("td3").style.background=
"url(pict/finish.jpg)";
}
</script>
</head>
<body>
<div id="basis">
<table>
<tr>
<td id="td1"><img src="pict/sun.png" draggable="true"
id="sun" alt="Фото"></td>
<td id="td2"></td>
<td id="td3"></td>
</tr>
</table>
</div>
</body>
</html>
219
12.4. Тормозим шарики
Файл ball.html.
Теперь разберем последний сценарий, с помощью которого мы продемонстрируем еще один вариант перемещения изображений.
Запустите страницу Тормозим шарики. Перед вами букет из воздушных
шаров. Он с большой скоростью перемещается вперед-назад. Под шариками
находится выпадающий список для выбора разных вариантов скорости движения картинки. По умолчанию установлен режим «Быстро» (см. рис. 12.4.1). Выберите другой вариант ⸻ «Средне» или «Медленно». Скорость полета шариков
немного или основательно замедлится (см. рис. 12.4.2). После того, как вы притормозили картинку, можно вновь разогнать ее. Как вам уже, наверное, понятно,
вы можете выбирать один из трех скоростных режимов, тем самым разгоняя
или притормаживая изображение.
На этой странице два основных элемента.
1. Рисунок
<img src="pict/ball.png" id="ball" alt="Фото">
2. Выпадающий список
<select id="ran" class="sele">
<option selected value="10">Быстро</option>
<option value="30">Средне</option>
<option value="120">Медленно</option>
</select>
с тремя значениями для выбора скорости движения.
Объявляем две переменные:
let z=0;
let t=10;
где z – это показатель смещения рисунка от левого края документа, а t ⸻ временной интервал в миллисекундах.
Регистрируем обработчик для события change и одновременно запускаем
функцию balo, которая управляет движением рисунка вперед:
addEventListener("load", function()
{
balo();
document.getElementById("ran").
addEventListener("change", function()
{
t=this.value;
});
});
220
Рис. 12.4.1. Начало движения шариков после загрузки страницы
Рис. 12.4.2. Замедляем шарики
Инструкция
document.getElementById("ran").
addEventListener("change", function()
221
{
t=this.value;
});
необходима для изменения скорости полета шариков. Значения мы получаем из
выпадающего списка.
Как мы уже сказали, первой запускается функция balo:
function balo()
{
z+=10;
if(z<780)
{
document.getElementById("ball").style.left=z+"px";
window.setTimeout(balo, t);
}
else
window.setTimeout(rev, t);
}
Она сразу же увеличивает значение переменной z на 10 пикселей:
z+=10;
Если в этот момент выполняется условие if(z<780), то есть смещение рисунка
не превышает 780 пикселей, то его позиции присваивается новое значение:
document.getElementById("ball").style.left=z+"px";
а это значит, что шарики передвигаются на 10 пикселей правее. Затем через интервал времени t (в исходном состоянии это 10 миллисекунд) функция balo вызывается вновь:
window.setTimeout(balo, t);
z увеличивается еще раз на 10, а смещение картинки на этом шаге достигнет
уже 20 пикселей. Теперь инструкция
window.setTimeout(balo, t);
выполняется вновь.
Так происходит до тех пор, пока смещение рисунка от левого края не достигнет 780 пикселей. После этого условие if(z<780) становится ложным и выполняется альтернативная инструкция:
else
window.setTimeout(rev, t);
222
Здесь через интервал t запускается функция rev. Ее назначение ⸻ перемещать
рисунок от правого края страницы к левому.
Функция rev почти аналогична balo:
function rev()
{
z-=10;
if(z>20)
{
document.getElementById("ball").style.left=z+"px";
window.setTimeout(rev, t);
}
else
window.setTimeout(balo, t);
}
Но есть важные отличия. Во-первых, показатель смещения рисунка z теперь
уменьшается:
z-=10;
За счет этого шарики начинают двигаться в обратном направлении. Во-вторых,
теперь с интервалом t запускается функция обратного движения rev.
Шарики летят назад до тех пор, пока истинно условие if(z>20). Когда картинка достигнет предельного левого смещения в 20 пикселей, будет выполнена
инструкция
window.setTimeout(balo, t);
То есть вновь запустится функция balo. Процесс двинется по второму кругу.
Полет этот бесконечный и продолжается до тех пор, пока открыта страница с примером.
Вернемся к обработке события change. Для него у нас всего одна инструкция:
document.getElementById("ran").
addEventListener("change", function()
{
t=this.value;
});
Она присваивает переменной временного интервала t текущее значение из выпадающего списка. Если установленное в поле число небольшое, временной
интервал тоже невелик и картинка двигается быстро (так как функции движения вызываются часто). Если значение поля максимальное, то временной интервал увеличивается и картинка замедляется (так как функции движения вызываются реже).
Вот и все пояснения.
223
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Тормозим шарики</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px;}
#ball {position: absolute; left: 0px;}
#ran {position: absolute; top: 400px; left: 400px;
width: 200px; font-size: 20px;}
</style>
<script>
let z=0;
let t=10;
addEventListener("load", function()
{
balo();
document.getElementById("ran").
addEventListener("change", function()
{
t=this.value;
});
});
function balo()
{
z+=10;
if(z<780)
{
document.getElementById("ball").style.left=z+"px";
window.setTimeout(balo, t);
}
else
window.setTimeout(rev, t);
}
function rev()
{
z-=10;
if(z>20)
{
document.getElementById("ball").style.left=z+"px";
window.setTimeout(rev, t);
}
else
window.setTimeout(balo, t);
}
</script>
</head>
<body>
<div id="basis">
224
<img src="pict/ball.png" id="ball" alt="Фото">
<select id="ran" class="sele">
<option selected value="10">Быстро</option>
<option value="30">Средне</option>
<option value="120">Медленно</option>
</select>
</div>
</body>
</html>
225
13. Эффекты
Применение различных эффектов, меняющих свойства картинок, направлено на то, чтобы произвести на клиента особенное впечатление. За счет этого
повышается интерес к такому ресурсу по сравнению с ресурсами, не имеющими интерактивной составляющей.
Мы рассмотрим несколько эффектов, которые можно создать на страницах
вашего сайта. Некоторые из них достаточно простые, другие создают очень интересное впечатление и удивляют своей необычностью.
13.1. Пасьянс из картинок
Файл solit.html.
Перейдите по ссылке Пасьянс из картинок. Очередной сценарий получил
свое название от сходства с раскладыванием карточного пасьянса.
На странице программы мы увидим две кнопки ⸻ «Показать» и «Скрыть»
(см. рис. 13.1.1). Нажмем кнопку «Показать». Вверху слева плавно «проявится»
первое изображение (см. рис. 13.1.2). Сразу после того, как оно станет полностью непрозрачным, начнет проявляться второе изображение (см. рис. 13.1.3).
После второго ⸻ третье. И так далее, пока на странице не окажется 6 картинок
(см. рис. 13.1.4). Нажмем кнопку «Скрыть». Рисунки станут по очереди «растворяться», но в обратном порядке.
Эффект раскладывания пасьянса из фотографий достигается довольно простым способом.
В исходном состоянии на странице две кнопки:
<p><input type="button" value="Показать" id="bfor">
<input type="button" value="Скрыть" id="bbac"></p>
и 6 снимков:
<img
<img
<img
<br>
<img
<img
<img
id="i1" class="im" src="nat/im1.jpg" alt="Фото">
id="i2" class="im" src="nat/im2.jpg" alt="Фото">
id="i3" class="im" src="nat/im3.jpg" alt="Фото">
id="i4" class="im" src="nat/im4.jpg" alt="Фото">
id="i5" class="im" src="nat/im5.jpg" alt="Фото">
id="i6" class="im" src="nat/im6.jpg" alt="Фото">
которые в начальный момент не видны посетителю:
.im {... opacity: 0;}
Для кнопки «Показать» регистрируем обработчик события click, который
запускает функцию forw:
document.getElementById("bfor").
addEventListener("click", forw);
226
Рис. 13.1.1. Начальный вид страницы
Рис. 13.1.2. «Проявляется» первый рисунок
Для кнопки «Скрыть» регистрируем обработчик, запускающий функцию
back:
document.getElementById("bbac").
addEventListener("click", back);
После регистрации обработчиков мы объявляем переменную
let a=1;
которая будет выполнять роль счетчика изображений.
227
Рис. 13.1.3. «Проявляется» второй рисунок
Рис. 13.1.4. Все изображения заняли свои места
228
Итак, клиент запустил пасьянс, и начали выполняться инструкции функции forw:
function forw()
{
let d=document.getElementById("i"+a).style;
d.transition="opacity 2s";
d.opacity=1;
a++;
if(a<7)
setTimeout(forw, 1000);
else
a=6;
}
ков:
На первом шаге создается переменная для обращения к свойствам рисун-
let d=document.getElementById("i"+a).style;
затем устанавливается время проявления картинки:
d.transition="opacity 2s";
и задается конечная величина непрозрачности:
d.opacity=1;
Теперь значение счетчика увеличивается на единицу:
a++;
Дальше происходит проверка этого значения:
if(a<7)
setTimeout(forw, 1000);
else
a=6;
Если оно меньше 7, через 1 секунду функция forw будет запущена вновь:
setTimeout(forw, 1000);
Благодаря такому циклу сценарий последовательно проявляет все шесть
изображений. Когда шестое было проявлено, счетчик a снова увеличивается на
единицу, условие if(a<7) становится ложным и выполняется единственная операция из альтернативного блока:
else
a=6;
229
Выполнение сценария прерывается, а счетчику устанавливается его верхняя граница ⸻ значение 6. Теперь программа готова к растворению снимков,
которое выполняет функция back (после нажатия кнопки «Скрыть»):
function back()
{
document.getElementById("i"+a).style.opacity=0;
a--;
if(a>0)
setTimeout(back, 1000);
else
a=1;
}
Она немного проще. Так как время перехода уже было установлено в
функции forw, то теперь мы можем не прибегать к созданию специальной переменной для обращения к свойствам картинок, а сразу записать необходимое
выражение:
document.getElementById("i"+a).style.opacity=0;
Далее происходит уменьшение значения счетчика на единицу:
a--;
и проверяется условие ⸻ не достигнута ли его нижняя граница:
if(a>0)
setTimeout(back, 1000);
else
a=1;
Если «нет», то функция back запускается еще раз
setTimeout(back, 1000);
Если «да», то ее выполнение завершается, а счетчику устанавливается начальное значение
a=1;
Теперь все рисунки полностью растворились, и программа готова к запуску по новой.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Пасьянс из картинок</title>
230
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
.im {width: 300px; border: 1px solid #000000;
margin: 10px; opacity: 0;}
#bfor, #bbac {width: 250px; height: 40px;
border: 1px solid #000000;
box-shadow: #333333 5px 5px 8px;
font-size: 20px; cursor: pointer;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("bfor").
addEventListener("click", forw);
document.getElementById("bbac").
addEventListener("click", back);
let a=1;
function forw()
{
let d=document.getElementById("i"+a).style;
d.transition="opacity 2s";
d.opacity=1;
a++;
if(a<7)
setTimeout(forw, 1000);
else
a=6;
}
function back()
{
document.getElementById("i"+a).style.opacity=0;
a--;
if(a>0)
setTimeout(back, 1000);
else
a=1;
}
});
</script>
</head>
<body>
<div id="basis">
<p><input type="button" value="Показать" id="bfor">
<input type="button" value="Скрыть" id="bbac"></p>
<img
<img
<img
<br>
<img
<img
id="i1" class="im" src="nat/im1.jpg" alt="Фото">
id="i2" class="im" src="nat/im2.jpg" alt="Фото">
id="i3" class="im" src="nat/im3.jpg" alt="Фото">
id="i4" class="im" src="nat/im4.jpg" alt="Фото">
id="i5" class="im" src="nat/im5.jpg" alt="Фото">
231
<img id="i6" class="im" src="nat/im6.jpg" alt="Фото">
</div>
</body>
</html>
13.2. Раскрашиваем рисунки
Файл filter.html.
К сожалению, черно-белый формат изображений в книге не позволяет передать заявленный эффект. Поэтому его надо смотреть в реальных условиях ⸻
перейдя по ссылке Раскрашиваем рисунки.
На странице три морских пейзажа (см. рис. 13.2.1), показанные в режиме
«оттенки серого». Наведите указатель мыши на любой снимок ⸻ и он станет
цветным. Переместите указатель на свободный участок страницы ⸻ и фотография опять «превратится» в черно-белую.
Рис. 13.2.1. В исходном состоянии все картинки черно-белые
Эффект весьма простой и достигается с помощью не менее простого
скрипта.
Есть три цветные картинки:
<img src="nat/im51.jpg" id="w1" alt="Фото">
<img src="nat/im64.jpg" id="w2" alt="Фото">
<img src="nat/im72.jpg" id="w3" alt="Фото">
демонстрируемые в режиме «оттенки серого»:
img {... filter: grayscale(100%);}
И есть два обработчика для событий уровня окна браузера ⸻ mouseover и
mouseout. Разберем их по порядку.
232
Первый обработчик отслеживает все события, связанные с попаданием
указателя мыши на любые элементы страницы:
addEventListener("mouseover", function(ev)
{
...
});
и сразу создает переменную, в которую помещаются данные об объекте события:
let e=ev.target;
После этого выполняется проверка, не оказался ли указатель на одном из рисунков:
if(e.tagName=="IMG")
Если условие истинно, то соответствующий кадр «раскрашивается» (точнее,
его свойству filter устанавливается нулевое значение для уровня оттенков серого):
document.getElementById(e.id).style.filter=
"grayscale(0)";
Когда указатель покидает пределы фото, запускается другой обработчик:
addEventListener("mouseout", function(ev)
{
...
});
Здесь также создается переменная, хранящая данные об объекте события
mouseout:
let e=ev.target;
и выполняется проверка ⸻ произошло ли это событие именно на картинке:
if(e.tagName=="IMG")
Если «да», то изображению возвращается режим оттенки серого:
document.getElementById(e.id).style.filter=
"grayscale(100%)";
Как видите, все действительно очень просто.
233
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Раскрашиваем рисунки</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
img {width: 300px; filter: grayscale(100%);}
</style>
<script>
addEventListener("mouseover", function(ev)
{
let e=ev.target;
if(e.tagName=="IMG")
document.getElementById(e.id).style.filter=
"grayscale(0)";
});
addEventListener("mouseout", function(ev)
{
let e=ev.target;
if(e.tagName=="IMG")
document.getElementById(e.id).style.filter=
"grayscale(100%)";
});
</script>
</head>
<body>
<div id="basis">
<img src="nat/im51.jpg" id="w1" alt="Фото">
<img src="nat/im64.jpg" id="w2" alt="Фото">
<img src="nat/im72.jpg" id="w3" alt="Фото">
</div>
</body>
</html>
13.3. Настраиваем фото
Файл manif.html.
Еще один случай, когда черно-белый формат рисунка в книге не позволяет
передать заявленный эффект. Поэтому, читая данный раздел, одновременно запустите страницу Настраиваем фото. Вы увидите в ее верхней части два ползунка с надписями, поясняющими их функции, ⸻ «Прозрачность» и «Цвет» (см.
рис. 13.3.1). Если перемещать верхний ползунок, то постепенно «проявится»
черно-белое изображение морского пейзажа с островом и лодкой (см. рис.
13.2.2). Нижним ползунком имеет смысл управлять только при хотя бы частич234
ном проявлении снимка. Этот ползунок меняет уровень оттенков серого фотографии со 100% до 0 и обратно.
«Начинкой» страницы служат три элемента.
Рис. 13.3.1. В исходном состоянии видны только ползунки настройки
Рис. 13.3.2. Управляя ползунками, меняем прозрачность и цветность картинки
Первый элемент ⸻ ползунок для изменения непрозрачности:
Прозрачность:<br><input type="range" min="0" max="1"
step="0.01" value="0" id="ran1">
Он управляет свойством opacity в пределах значений от 0 до 1 с шагом в 0.01.
Второй элемент ⸻ ползунок для управления цветностью:
Цвет:<br><input type="range" min="0" max="100"
step="1" value="100" id="ran2">
235
Он меняет значения свойства filter от grayscale(100%) до grayscale(0) с шагом
1.
Третий элемент ⸻ изображение морского пейзажа
<img src="nat/im64.jpg" id="im" alt="Фото">
с начальными настройками
#im {opacity: 0; filter: grayscale(100%);}
То есть в исходном состоянии картинка черно-белая и она не видна.
Перемещая верхний ползунок, мы запускаем анонимную функцию, которая обрабатывает событие mousemove на данном элементе:
document.getElementById("ran1").
addEventListener("mousemove", function()
{
...
});
Функция выполняет единственную операцию ⸻ получает текущее значение
данного элемента и присваивает его свойству opacity рисунка:
document.getElementById("im").style.opacity=
this.value;
Перемещение нижнего ползунка обрабатывает вторая функция:
document.getElementById("ran2").
addEventListener("mousemove", function()
{
document.getElementById("im").style.filter=
"grayscale("+this.value+"%)";
});
Ее задача ⸻ получить текущее значение из этого элемента и присвоить его значению оттенков серого свойства filter.
Как видите, и эта программа позволяет создавать простые эффекты весьма
простыми методами.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Настраиваем фото</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; text-align: center;}
#im {opacity: 0; filter: grayscale(100%);}
236
#ran1, #ran2 {width: 500px;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("ran1").
addEventListener("mousemove", function()
{
document.getElementById("im").style.opacity=
this.value;
});
document.getElementById("ran2").
addEventListener("mousemove", function()
{
document.getElementById("im").style.filter=
"grayscale("+this.value+"%)";
});
});
</script>
</head>
<body>
<div id="basis">
Прозрачность:<br><input type="range" min="0" max="1"
step="0.01" value="0" id="ran1"><br>
Цвет:<br><input type="range" min="0" max="100"
step="1" value="100" id="ran2"><br><br>
<img src="nat/im64.jpg" id="im" alt="Фото">
</div>
</body>
</html>
13.4. Проявляем картинку
Файл twist.html.
Сейчас нам предстоит разобрать довольно необычную программу. Для
этого кликните ссылку Проявляем картинку.
После загрузки документа мы видим только рамку изображения, которое
необходимо «проявить» (см. рис. 13.4.1). Пока указатель мыши не попадет
внутрь рамки, ничего не происходит.
Теперь медленно проведите курсором внутри рамки слева направо. Вы
увидите, как на белом фоне плавно возникнет уже знакомая нам фотография с
морским пейзажем (см. рис. 13.4.2 и 13.4.3). Проведите курсором в обратном
направлении ⸻ справа налево. Фотография также плавно «растворится».
Наилучший эффект достигается именно при медленном движении мыши. Если
быстро провести указателем по рабочей области, картинка проявится или растворится только частично. То же произойдет, если указатель начал двигаться не
от боковых сторон рамок, а, например, от середины изображения.
237
Рис. 13.4.1. В исходном состоянии видна только рамка фотографии
Рис. 13.4.2. Начинаем проявлять снимок
238
Рис. 13.4.3. Рисунок полностью проявлен
Не правда ли, интересный пример? Посмотрим, как он запрограммирован.
На странице есть базовый слой
<div id="basis">...</div>
внутри которого размещен снимок
<img src="nat/im64.jpg" id="ocean" alt="Фото">
Слой имеет размеры 600 на 400 пикселей (по размерам картинки) и рамку толщиной 1 пиксель:
#basis {... border: 1px solid #000000; width: 600px;
height: 400px;}
У рисунка задан нулевой уровень непрозрачности:
#ocean {opacity: 0;}
Его изменением управляет функция opa (название происходит от свойства
opacity, что переводится как непрозрачность):
addEventListener("load", function()
{
document.getElementById("ocean").
addEventListener("mousemove", opa);
});
239
Прежде чем разбирать принципы работы этой функции, зададимся вопросом: а зачем нам слой div? Только для демонстрации рамки? Но ведь ее можно
создать непосредственно у фотоснимка. Да, можно. Только тогда в исходном
состоянии она не будет видна так же, как и картинка. Поэтому нам трудно будет обнаружить, где находится снимок.
Вернемся к сценарию. У нас объявлены две переменные:
let d=0;
let i=0;
Переменная d предназначена для хранения предыдущей по отношению к текущей координате мыши по оси X. Это определение станет более понятным в
процессе разбора сценария. Переменная i ⸻ счетчик уровня непрозрачности.
Как только событие mousemove произойдет над рисунком (то есть указатель мыши начнет движение над рисунком), будет выполнен запуск обработчика. Вот его код:
function opa()
{
let h=event.pageX;
if(h-d>3)
{
if(i<=1)
{
i+=0.01;
document.getElementById("ocean").style.opacity=i;
d=h;
}
else
i=1;
}
if(d-h>3)
{
if(i>=0)
{
i-=0.01;
document.getElementById("ocean").style.opacity=i;
d=h;
}
else
{
i=0;
d=0;
}
}
}
Начинается сценарий с определения горизонтальной координаты указателя:
let h=event.pageX;
240
Давайте считать, что сейчас курсор двигается слева направо. Первым делом проверяется условие if(h‒d>3). В начальный момент d имеет значение 0,
поэтому разность между h и d удовлетворяет условию (понятно, что горизонтальная координата указателя мыши в районе рамки намного превышает значение 0). Таким образом, при попадании указателя мыши на фото будут выполняться инструкции первого блока if.
Поясним, что шаг в 3 пикселя выбран путем экспериментов. При таком
значении разницы текущей и предыдущей координаты программа работает
наиболее стабильно и точно.
Продолжим. Внутри первого блока выполняется проверка еще одного
условия:
if(i<=1)
Так как исходное значение переменной i равно 0, то это условие тоже будет истинным.
Таким образом станут выполняться три инструкции:
i+=0.01;
document.getElementById("car").style.opacity=i;
d=h;
В первой строке счетчик увеличивается на 0.01. Во второй строке его значение
присваивается свойству непрозрачности изображения. В третьей выполняется
операция присвоения текущей координаты мыши переменной d.
Смотрим, что произойдет дальше. Курсор мыши продолжает движение
вправо, а значит вторично запускается функция opa. Опять выполняется проверка условия if(h‒d>3). Как видите, теперь сравнивается новая координата
указателя со старой, полученной на предыдущем шаге и помещенной в переменную d. Если условие истинно, показатель непрозрачности опять увеличится.
Продолжаем вести мышь слева направо ⸻ значение переменной i все увеличивается и увеличивается. В какой-то момент уровень непрозрачности достигнет 1, и фотография станет видна полностью. Заметим, что переменная i может
увеличиться до значений, немного превышающих 1. Но это неважно, так как на
подобный случай у нас есть соответствующие инструкции:
if(i<=1)
{
...
}
else
i=1;
Сколько бы раз вы ни проводили мышью по картинке слева направо (минуя обратное движение над изображением), счетчик i всегда будет иметь максимальное значение 1 ⸻ и не больше.
241
Этот момент мы разберем подробнее. Если бы не было таких ограничений
по значению счетчика, мы обнаружили бы неприятное поведение сценария.
Представьте, что вы один раз провели по фото слева направо. Оно полностью
проявилось (то есть i стала равна единице или даже чуть большему числу). Теперь вы убираете мышь с рисунка, перемещаете ее указатель вновь к левому
краю и опять проводите по снимку. Внешне ничего не поменялось, но переменная i уже достигнет значения 2 или немного больше. Еще несколько подобных
манипуляций и значение счетчика станет равно 5 или 8, или вообще двухзначному числу. При этом у картинки по-прежнему ничего не изменится, так как
свойство opacity воспринимает все значения выше единицы как полную непрозрачность. Если теперь один раз провести мышью по картинке в обратном
направлении, мы с удивлением обнаружим, что изображение не исчезает. А все
потому, что число, хранимое счетчиком, хотя и уменьшились на единицу, но
стало, допустим, 4 вместо накрученных 5. Инструкция
else
i=1;
избавляет нас от такого неприятного эффекта.
Кстати, похожую проверку выполняет и вторая часть функции, не допуская уменьшения значения счетчика ниже отметки 0.
Теперь разберемся, что будет происходить во время движения указателя
мыши по картинке в обратном направлении. Как раз вторая часть функции и
предназначена для обработки таких действий посетителя:
if(d-h>3)
{
if(i>=0)
{
i-=0.01;
document.getElementById("car").style.opacity=i;
d=h;
}
else
{
i=0;
d=0;
}
}
В данном случае проверяется обратное условие:
if(d-h>3)
То есть, если предыдущая координата мыши больше текущей, значит указатель
двигается в обратном направлении и показатель непрозрачности уменьшается
на 0.01:
i-=0.01;
document.getElementById("car").style.opacity=i;
d=h;
242
Эти инструкции выполняются до тех пор, пока уровень непрозрачности
больше или равен 0:
if(i>=0)
По достижении нулевой «отметки» рисунок полностью исчезает, скручивание
счетчика прекращается и переменным i и d присваиваются исходные значения:
else
{
i=0;
d=0;
}
Открывать и прятать снимок можно сколько угодно ⸻ программа составлена так, что допускает неограниченное число однотипных действий.
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Проявляем картинку</title>
<style>
#basis {position: relative; margin: auto;
border: 1px solid #000000; width: 600px;
height: 400px;}
#ocean {opacity: 0;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("ocean").
addEventListener("mousemove", opa);
});
let d=0;
let i=0;
function opa()
{
let h=event.pageX;
if(h-d>3)
{
if(i<=1)
{
i+=0.01;
document.getElementById("ocean").style.
opacity=i;
d=h;
}
else
i=1;
243
}
if(d-h>3)
{
if(i>=0)
{
i-=0.01;
document.getElementById("ocean").style.
opacity=i;
d=h;
}
else
{
i=0;
d=0;
}
}
}
</script>
</head>
<body>
<div id="basis">
<img src="nat/im64.jpg" id="ocean" alt="Фото">
</div>
</body>
</html>
13.5. Фото за шторкой
Файл curt.html.
Продолжаем создавать оригинальные примеры. В новом сценарии большое
значение имеет позиционирование элементов. Поэтому в описании программы
мы особое внимание уделим настройкам стилей.
Щелкните на ссылке Фото за шторкой. Начальный вид документа очень
напоминает страницу из предыдущего примера (см. рис. 13.5.1). Опять есть
рамка. Внутри нее что-то скрывается? Нет, не внутри, а за ней. Рамка ⸻ это
границы белой шторки, за которой «спряталось» изображение.
Как и в предыдущем примере, медленно проведите курсором по шторке
слева направо. На ваших глазах шторка плавно сдвинется к правому краю, а за
ней обнаружится обещанная картинка (см. рис. 13.5.2 и 13.5.3). Если теперь
провести указателем мыши по шторке в обратном направлении, она вновь раздвинется и рисунок скроется за ней. Не торопитесь, ведите мышь плавно. Если
поспешить и сделать резкое движение, указатель «соскочит» со шторки и она
перестанет открываться. Правда, в этом нет ничего страшного. Достаточно вернуть курсор на место и продолжить плавное движение, чтобы шторка полностью открылась или закрылась.
244
Рис. 13.5.1. В исходном состоянии видна только шторка, закрывающая рисунок
Рис. 13.5.2. Начинаем смещать шторку
245
Рис. 13.5.3. Шторка полностью отодвинута в сторону
Совет: скройте боковую панель в вашем браузере (если она есть), чтобы
пример работал максимально точно.
В теле документа есть два слоя и снимок морского пейзажа:
<div id="basis">
<img src="nat/im64.jpg" id="ocean" alt="Фото">
<div id="lay"></div>
</div>
Внешний слой служит контейнером для остальных двух элементов. Свойства контейнера:
#basis {position: relative; margin: auto;
width: 1000px; height: 400px;}
Наиболее важное значение для правильной работы сценария имеет позиционирование слоя по центру страницы:
#basis {position: relative; margin: auto; ...}
Свойства фотографии:
#ocean {position: absolute; top: 35px; right: 250px;
width: 500px; z-index: 10;}
246
Поверх снимка располагается слой lay, который выполняет роль шторки.
Его настройки:
#lay {position: absolute; top: 20px; right: 220px;
width: 550px; height: 360px;
border: 1px solid #000000;
background: #FFFFFF; z-index: 20;}
Обратите внимание ⸻ позиционирование рисунка и шторки отсчитываются от
правого края слоя-контейнера:
#ocean {... right: 250px; ...}
#lay {... right: 220px; ...}
Это тоже важно для правильной работы программы.
Сам код сценария довольно короткий. Регистрируем обработчик события
mousemove:
addEventListener("load", function()
{
document.getElementById("lay").
addEventListener("mousemove", wid);
});
Объявляем переменную w. Она необходима при определении размеров
сжатия шторки. Эту переменную мы не просто задаем, а рассчитываем в зависимости от разрешения монитора:
let w=screen.width/2+296;
Для этого выясняем ширину экрана компьютера:
screen.width
делим ее на 2 и получаем координату середины страницы, а значит и координату середины шторки. К полученному результату прибавляем число 296. Вообще-то, ширина шторки 550 пикселей, а значит, вроде бы, чтобы полностью
убрать ее, нужно в эти расчеты добавлять число 275 (то есть половину ширины
слоя lay). Но если мы полностью уберем шторку, то после этого уже не сможем
раздвинуть ее обратно. Поэтому мы взяли значение с запасом, чтобы после
остановки скрипта у нас еще оставался 21 пиксель несвернутой шторки, от которого программа и будет «плясать» во время обратного движения мыши (значение 21 пиксель выбрано экспериментальным путем).
Подозреваю, что эти объяснения пока выглядят довольно туманно. Но вы
поймете их, разбирая принцип работы функции wid.
247
Вот ее код:
function wid()
{
let h=event.pageX;
let p=w-h;
if(p<553)
document.getElementById("lay").style.width=p+"px";
}
Первым делом определяется горизонтальная координата мыши:
let h=event.pageX;
а затем вычисляется ширина шторки в данный момент:
let p=w-h;
Если значение переменной p меньше 553 (это чуть больше максимальной ширины шторки), то выполняется инструкция
document.getElementById("lay").style.width=p+"px";
Пусть указатель двигается слева. В это время размеры шторки уменьшаются, так как w ⸻ постоянная величина, а значение переменной h все время возрастает. Поскольку позиционирование слоя со шторкой отсчитывается от правого края контейнера, то при движении мыши слева слой lay будет «сворачиваться» вправо, вслед за курсором. При обратном движении мыши значение переменной p будет увеличиваться и шторка станет разворачиваться.
Теперь необходимые пояснения к переменной w. По сути она представляет
собой сумму двух слагаемых: координаты правого края слоя lay относительно
полностью развернутого окна браузера и 21 пиксель «запаса», на величину которого шторка останется не полностью свернутой. Запись w=screen.width/2+296
аналогична записи w=screen.width/2+275+21. А это, в свою очередь, означает,
что левый край шторки следует за курсором с отставанием в 21 пиксель. В результате, когда курсор пересечет правый край шторки и выполнение функции
прекратится, левый край будет отстоять от правого на 21 пиксель, что вы и видите на рисунке 13.5.3.
Кстати, «подхватывание» шторки в тот момент, когда курсор начнет движение в обратном направлении, произойдет практически сразу. В этом легко
убедиться в результате соответствующего эксперимента на странице с примером. И естественно, что шторка полностью закроется при обратном движении
мыши «раньше», чем указатель покинет слой lay.
Осталось добавить, что условие if(p<553) ограничивает движение шторки
в обратном направлении.
Вот такой у нас получился сценарий: короткий, но с довольно сложной логикой.
248
Полный код страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Фото за шторкой</title>
<style>
#basis {position: relative; margin: auto;
width: 1000px; height: 400px;}
#ocean {position: absolute; top: 35px; right: 250px;
width: 500px; z-index: 10;}
#lay {position: absolute; top: 20px; right: 220px;
width: 550px; height: 360px;
border: 1px solid #000000;
background: #FFFFFF; z-index: 20;}
</style>
<script>
addEventListener("load", function()
{
document.getElementById("lay").
addEventListener("mousemove", wid);
});
let w=screen.width/2+296;
function wid()
{
let h=event.pageX;
let p=w-h;
if(p<553)
document.getElementById("lay").style.width=p+"px";
}
</script>
</head>
<body>
<div id="basis">
<img src="nat/im64.jpg" id="ocean" alt="Фото">
<div id="lay"></div>
</div>
</body>
</html>
249
14. Заключение
Итак, мы рассмотрели и протестировали 36 программ для управления различными режимами просмотра изображений. Принципы работы этих программ
описаны настолько подробно, что читателю, думаю, не составило труда разобраться в нюансах кода.
Замечу, что материал книги многократно проверен и часто использовался
автором в проектах, сделанных для заказчиков.
Хочу также обратить ваше внимание, что в каждом из сценариев сделан
упор на получение только какого-то одного результата. Если вы пожелаете использовать в своих разработках галереи или слайдеры с набором из нескольких
эффектов, вам не составит труда скомпоновать отдельные сценарии в один более сложный. Все необходимое у вас под рукой.
Ну а мне остается пожелать вам творческих успехов!
250
Валерий Викторович ЯНЦЕВ
JAVASCRIPT. КАРТИНКИ, ГАЛЕРЕИ, СЛАЙДЕРЫ
Учебное пособие
Зав. редакцией литературы
по информационным технологиям
и системам связи О. Е. Гайнутдинова
Ответственный редактор Н. С. Захарова
Корректор О. В. Федорова
Выпускающий В. А. Плотникова
ЛР № 065466 от 21.10.97
Гигиенический сертификат 78.01.10.953.П.1028
от 14.04.2016 г., выдан ЦГСЭН в СПб
Издательство «ЛАНЬ»
lan@lanbook.ru; www.lanbook.com
196105, СанктПетербург, пр. Юрия Гагарина, д.1, лит. А.
Тел.: (812) 3362509, 4129272.
Бесплатный звонок по России: 88007004071
Подписано в печать 09.06.22
Бумага офсетная. Гарнитура Школьная. Формат 70×100 1/16.
Печать офсетная/цифровая. Усл. п. л. 20,48. Тираж 30 экз.
Заказ № 91722.
Отпечатано в полном соответствии
с качеством предоставленного оригиналмакета
в АО «Т8 Издательские технологии»
109316, г. Москва, Волгоградский пр., д. 42, к. 5.