Чертёж десятый, половина первая: Знакомство с JavaScript

До сих пор средствами HTML мы не могли обеспечить интерактивность, не могли и «оживить» страничку движущимися или изменяющимися элементами. Но, оказывается, это можно сделать, если использовать язык программирования JavaScript.

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

В качестве испытательного полигона возьмём страничку Дуси, точнее, её копию.

  • Создай копию странички dusja.htm, назвав её, например, dusja-proba.htm.
  • Создадим на Дусиной страничке интерактивный фотоальбом, в котором при выборе названия фотографии она отображается на специальной панели. Названия фотографий тоже разместим на выпуклых панелях, поэтому есть смысл создать класс panelka.
    • в стилевом файле my_style.css объявляем класс:
    • .panelka{	border-style:outset;
       		text-align:center;
      }
    • там же зададим стиль для заголовка третьего уровня <H3>:
    • H3{	color:#ff0088;
      	font-size:130%;
      	text-align:center;
      }
    • не забудь подключить стилевой файл к файлу dusja-proba.htm;
    • кроме того, подготовь «Дусины фотографии» одинакового размера (в нашем примере 200×250), помести их в папку images и назови dusja1.jpg, dusja2.jpg, dusja3.jpg и dusja4.jpg. Там же помести файл dusja0.jpg, в котором нарисуй обложку фотоальбома.
  • Формируем страничку:
    • запиши в файл dusja-proba.htm следующий текст:
    • <BODY bgcolor="#ffddff" text="#880088">
      	<H2 class="panelka">Наша любимица Дуся</H2>
      	<P>Однажды осенним дождливым вечером в дверь кто-то
      		постучал, а точнее, &laquo;поцарапался&raquo;…</P>
      	<DIV class="panelka"><H3>Дусин фотоальбом</H3></DIV>
      	<P>
      	<DIV class="panelka" style="position:absolute; right:10;
      		width:300; height:350; padding:50;">
      		<IMG id="foto" src="images/dusja0.jpg" width="200"
      			height="250">
      	</DIV>
      	<DIV class="panelka" id="kn1" onmouseover="sm_foto(1)">
      		Дуся знакомится с Погромычем</DIV>
      	<DIV class="panelka" id="kn2" onmouseover="sm_foto(2)">
      		Когда Дуся была маленькой</DIV>
      	<DIV class="panelka" id="kn3" onmouseover="sm_foto(3)">
      		Как Дуся училась охотиться</DIV>
      	<DIV class="panelka" id="kn4" onmouseover="sm_foto(4)">
      		Уроки танцев</DIV>
      </BODY>

На этот раз полужирным выделено не то, что надо добавить (как это было обычно), а то, что тебе ещё незнакомо.

Прежде всего, это &laquo; и &raquo;. Подобные последовательности (их иногда называют escape-последовательностями) служат для отображения зарезервированных символов, таких, как <, >, &, кавычки, апострофы… Таких последовательностей очень много, поэтому отметим только некоторые:

&laquo; и &raquo; — левая и правая кавычки-ёлочки;

&quot; — прямые кавычки-лапки;

&lt; и &gt; — знаки < и >;

&nbsp; — неразрывный пробел.

Но это всё не относится непосредственно к JavaScript. А вот что относится, так это новое назначение атрибута id. Теперь с его помощью мы именуем блок. Для чего? Мы собираемся изменять значения некоторых атрибутов фотографии и панелек с названиями фотографий и, чтобы иметь возможность к ним обращаться, объявляем для них идентификаторы.

Кроме того, атрибутом onMouseOver мы сообщили, какую JS-функцию надо запустить при возникновении указанного события onMouseOver (то есть при наведении указателя мыши на объект).

Понятие события является ключевым в объектно-ориентированных языках.

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

В приложении 4 приведён список основных событий, который тебе может понадобиться.

    • загрузи страничку в браузер и убедись, что она выглядит примерно так:



    • в разделе <HEAD> создадим функцию JavaScript, которая будет изменять фотографию:
    • <HEAD>
      	<TITLE>Наша любимица Дуся</TITLE>
      	<LINK rel="stylesheet" type="text/css" href="my_style.css">
      	<SCRIPT type="text/javascript">
      <!--
      	function sm_foto(num)
      	{
      		foto.src="images/dusja"+num+".jpg";
      	}
      //-->
      	</SCRIPT>
      </HEAD>
    • обнови страничку в браузере и наведи указатель мышки на название второй фотографии. Если всё сделано правильно, фотография изменится.

А теперь разберёмся, что же мы натворили. Тег <SCRIPT> содержит описание функций — скриптов. Его атрибут type сообщает, что функции написаны на языке JavaScript. Иногда вместо атрибута type записывают практически равноценный атрибут language="JavaScript".

Внутри тега <SCRIPT> располагаются одна или несколько собственно функций по следующему правилу: после слова function записывается её имя (в нашем случае sm_foto) со списком параметров в круглых скобках (мы передаём нашей функции один параметр num — номер выбранной фотографии). Затем в фигурных скобках следуют операторы. Оператор foto.src="images/dusja"+num+".jpg"; указывает, что у объекта с именем foto атрибуту src надо задать значение, записанное справа от знака =, то есть для первой фотографии получится images/dusja1.jpg, для второй — images/dusja2.jpg, и так далее.

И ещё один момент требует пояснения. Весь код JS взят в скобки комментариев HTML <!-- и -->. Зачем? Дело в том, что некоторые браузеры не распознают JS или у них просто отключена функция обработки скриптов. Если не закомментарить описание функций, такой браузер просто отобразит их текст, что вряд ли доставит удовольствие посетителю странички.

  • Теперь обратим внимание на дизайн странички. Вряд ли тебе понравилось, что панельки с названиями фото растянулись на всю ширину экрана. Напрямую изменить их ширину нельзя, потребуется задать для каждой панельки стиль. Но мы поступим иначе — поместим все панельки внутрь контейнера <FIELDSET>, который просто охватывает своё содержимое в рамку:
  • <FIELDSET style="width:350;">
    	<LEGEND><H3>Выбери фотографию</H3></LEGEND>
    	<DIV class="panelka" id="kn1" onmouseover="sm_foto(1)">
    		Дуся знакомится с Погромычем</DIV>
    	<DIV class="panelka" id="kn2" onmouseover="sm_foto(2)">
    		Когда Дуся была маленькой</DIV>
    	<DIV class="panelka" id="kn3" onmouseover="sm_foto(3)">
    		Как Дуся училась охотиться</DIV>
    	<DIV class="panelka" id="kn4" onmouseover="sm_foto(4)">
    		Уроки танцев</DIV>
    </FIELDSET>

Тегом <LEGEND> задаётся надпись в рамке. У него есть атрибут align, который тебе хорошо знаком.

  • Страничка выглядит довольно привлекательно, но, всё-таки, мы на этом не остановимся. Сделаем так, чтобы при выборе какой-либо фотографии её панелька вдавливалась, создавая впечатление нажатой кнопки. Для этого добавим в функцию sm_foto несколько строк:
  • function sm_foto(num)
    {
    	foto.src="images/dusja"+num+".jpg";
    	if (num==1) {kn1.style.borderStyle="inset"}
    		else {kn1.style.borderStyle="outset"}
    	if (num==2) {kn2.style.borderStyle="inset"}
    		else {kn2.style.borderStyle="outset"}
    	if (num==3) {kn3.style.borderStyle="inset"}
    		else {kn3.style.borderStyle="outset"}
    	if (num==4) {kn4.style.borderStyle="inset"}
    		else {kn4.style.borderStyle="outset"}
    }

Здесь мы использовали условный оператор JS:

if (условие) {команды «то»}

    else{команды «иначе»}

и работает он так: если условие истинно, то выполняются команды «то», в противном случае выполняются команды «иначе».

Отметим, что операция сравнения записывается двумя знаками =, то есть запись if (num==1) означает если num равна 1.

Разберёмся подробнее с точечной нотацией, которая сейчас получила большое распространение. Что означает запись kn1.style.borderStyle="outset"?

kn1 — объект с идентификатором kn1, то есть первая панелька с названием фотографии;

kn1.style — атрибут style объекта kn1;

kn1.style.borderStyle — значение параметра border-style атрибута style объекта kn1;

kn1.style.borderStyle="outset" — параметру border-style присваивается значение "outset".

Небольшое, но очень важное замечание: в отличие от HTML, JavaScript чувствителен к регистру. Это значит, что, например, имена kn1 и Kn1 — совершенно разные.

Обрати внимание, что свойства объекта записываются немного иначе, чем название соответствующего параметра: параметру border-style соответствует свойство borderStyle (но никак не BorderStyle, borderstyle или Borderstyle). Как пишутся свойства, можно узнать в справочниках. Но ты, скорее всего, не ошибёшься, если уберёшь дефис (-), а следующую букву запишешь в верхнем регистре. Например, z-index и zIndex, font-size и fontSize.


  • Ну и, раз уж наши панельки работают как кнопки, изменим вид указателя мыши, когда он находится над панелькой, на «лапку». Для этого к определению стиля panelka достаточно добавить строчку:
  • .panelka{	border-style:outset;
    		text-align:center;
    		cursor:hand;
    }
  • Но создавать такие псевдокнопки совсем необязательно. В HTML для этого существуют специальные объекты. Рассмотрим некоторые из них:
    • допиши в файл dusja-proba.htm строки:
    • <FIELDSET style="width:350;">
      	<LEGEND><H3>Выбери фотографию</H3></LEGEND>
      	<DIV class="panelka" id="kn1" onmouseover="sm_foto(1)">
      		Дуся знакомится с Погромычем</DIV>
      	<DIV class="panelka" id="kn2" onmouseover="sm_foto(2)">
      		Когда Дуся была маленькой</DIV>
      	<DIV class="panelka" id="kn3" onmouseover="sm_foto(3)">
      		Как Дуся училась охотиться</DIV>
      	<DIV class="panelka" id="kn4" onmouseover="sm_foto(4)">
      		Уроки танцев</DIV>
      	<FORM id="knop">
      	<INPUT type="button" value="Дуся знакомится с Погромычем"
      		onclick="sm_foto(1)">
      	<INPUT type="button" value="Когда Дуся была маленькой"
      		onclick="sm_foto(2)">
      	<INPUT type="button" value="Как Дуся училась охотиться"
      		onclick="sm_foto(3)">
      	<INPUT type="button" value="Уроки танцев"
      		onclick="sm_foto(4)">
      	</FORM>
      </FIELDSET>

Внутрь тега <FORM> помещаются теги <INPUT>, задающие управляющие элементы. Атрибут type указывает тип такого элемента. В нашем примере type="button" создаёт кнопку. Атрибут value — надпись на кнопке.

Для каждой кнопки указано событие onClick, которое возникает при щелчке по кнопке. А обработчиком этого события будет всё та же функция sm_foto.

К тегу <FORM> можно подключить стиль, например, panelka:

<FORM id="knop" class="panelka">

и все кнопки зрительно объединятся в группу. Попробуй.


    • добавь ещё несколько строк:
    • <FIELDSET style="width:350;">
      	<LEGEND><H3>Выбери фотографию</H3></LEGEND>
      	<DIV class="panelka" id="kn1" onmouseover="sm_foto(1)">
      		Дуся знакомится с Погромычем</DIV>
      …
      	<INPUT type="button" value="Уроки танцев"
      		onclick="sm_foto(4)">
      	<BR><INPUT type="radio" name="rb" onclick="sm_foto(1)">
       		Дуся знакомится с Погромычем
      	<BR><INPUT type="radio" name="rb" onclick="sm_foto(2)">
       		Когда Дуся была маленькой
      	<BR><INPUT type="radio" name="rb" onclick="sm_foto(3)">
       		Как Дуся училась охотиться
      	<BR><INPUT type="radio" name="rb" onclick="sm_foto(4)">
       		Уроки танцев
      	</FORM>
      </FIELDSET>

Тип radio — это переключатель. Переключатели всегда объединены в группы. Все переключатели, образующие группу, имеют одинаковое значение атрибута name. Обратиться к конкретному переключателю можно по его номеру, например, rb[1] — это второй переключатель (только лишь потому, что первый имеет номер 0).

    • обнови страничку и убедись, что переключатели работают правильно:
    • исправим один недостаток — при выборе фотографии не с помощью переключателей на них это никак не отражается. Для этого добавим в описание функции sm_foto строчку:
    • function sm_foto(num)
      {
      	foto.src="images/dusja"+num+".jpg";
      	if (num==1) {kn1.style.borderStyle="inset"}
      		else {kn1.style.borderStyle="outset"}
      	if (num==2) {kn2.style.borderStyle="inset"}
      		else {kn2.style.borderStyle="outset"}
      	if (num==3) {kn3.style.borderStyle="inset"}
      		else {kn3.style.borderStyle="outset"}
      	if (num==4) {kn4.style.borderStyle="inset"}
      		else {kn4.style.borderStyle="outset"}
      	knop.rb[num-1].checked=true;
      }

«Включенность» переключателя определяется его свойством checked (true — включен, false — выключен). В этой команде мы присваиваем свойству checked переключателя под номером num-1 группы rb, находящейся в форме knop, значение true, то есть включаем его.

  • Ну и под конец снабдим навигационный фрейм кнопками Назад и Вперёд. Почему мы это делаем сейчас? Да просто раньше обычными средствами HTML этого сделать было нельзя. Представь, что мы «прибыли» на Дусину страничку и жмём кнопку Назад. Какая ссылка должна прятаться в этой кнопке?..
    • к файлу navig.htm подключаем стилевой файл и добавляем несколько строк:
    • <HTML>
      <HEAD>
      	<SCRIPT src="my_script.js"></SCRIPT>
      	<LINK rel="stylesheet" type="text/css" href="my_style.css">
      </HEAD>
      <BODY bgcolor="#ffddff" text="#880088">
      	<BR><img src="images/home.jpg" class="panelka"
      		onclick="load_frames('zagol.htm','glav.htm')">
      	<BR><img src="images/pogrom.jpg" class="panelka"
      		onclick="load_frames('zagol-p.htm','pogrom.htm')">
      	<BR><img src="images/dusja.jpg" class="panelka"
      		onclick="load_frames('zagol-d.htm','dusja.htm')">
      	<BR><img src="images/klava.jpg" class="panelka"
      		onclick="load_frames('zagol-k.htm','klava.htm')">
      	<BR><SPAN onclick="history.back()"
      		class="panelka">&nbsp;Назад&nbsp;</SPAN>
      	<BR><SPAN onclick="history.forward()"
      		class="panelka">Вперёд</SPAN>
      </BODY>
      </HTML>
      

Здесь мы всего лишь используем методы back() и forward() объекта history, который хранит всю историю перемещений пользователя по страничкам. Обрати внимание, что мы не стали создавать функцию, вызывающую эти методы. Зачем? Ведь команда в этой функции будет всего одна. В общем-то, в кавычках после события можно записывать сколь угодно длинный код вместо того, чтобы помещать его в специальную функцию. Но в этом случае мы лишаемся возможности повторно, в другом месте, использовать этот же код. Да и исправлять что-либо в коде удобно в одном файле, а не выискивая его по всем файлам сайта.

    • проверь работу кнопок Назад и Вперёд.

Если ты всё сделал правильно, то работать эти кнопки будут довольно странно — сначала вернётся содержимое главного фрейма, а уж потом, после повторного нажатия кнопки Назад, покажется заголовок. Но, если вдуматься, так и должно быть, ведь, например, кнопка Дуся загружает по очереди две странички. Чтобы исправить такое положение, можно дважды вызвать метод back() или forward(). А можно использовать метод go(), указав в качестве параметра количество шагов: положительное — вперёд, отрицательное — назад.

    • исправь обработчики событий:
    • <BR><SPAN onclick="history.go(-2);"
      	class="panelka">&nbsp;Назад&nbsp;</SPAN>
  • На этом мы пока остановимся. А ты реши, какой из способов задания меню тебе больше по душе, и оформи Дусину страничку по своему вкусу (надеюсь, ты ещё не забыл, что мы «обрабатывали» копию этой странички).

Следующий урок