Глаза страшат, а руки делают

ЧАСТЬ ПЕРВАЯ


10. Ещё о массивах

  • многомерные массивы;
  • встроенные массивы;
  • усовершенствованный фотоальбом;
  • оператор-помощник with

Многомерные массивы

Многомерные массивы в JavaScript — это массивы, содержащие внутри себя другие массивы.

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

Сначала объявим массив:

list = new Array()

Теперь объявим его первый элемент как массив из трёх элементов — наших основных пунктов меню.

list[0] = newArray("Меню 1", "Меню 2", "Меню 3")

В этом «массиве в массиве» у нас три элемента, которые можно вызвать как 0, 1 и 2 (помним, что отсчёт ведётся с нуля).

Теперь, вызывая list[0][0], мы получим «Меню 1», вызывая list[0][1] — «Меню 2», и т.д.

Следующие элементы главного массива заготавливаем как массивы пунктов подменю:

list[1] = newArray("Меню 1.1", "Меню 1.2", "Меню 1.3")
list[2] = newArray("Меню 2.1", "Меню 2.2")
list[3] = newArray("Меню 3.1", "Меню 3.2", "Меню 3.3", "Меню 3.4")

Вызываются аналогично: например, list[1][2] («Меню 1.3») или list[2][0] («Меню 2.1»).

Теперь формируем список:

/*Первый уровень, первый пункт*/
document.writeln("<ul><li>" + list[0][0] + "</li>")
/*Второй уровень*/
document.writeln("<ul><li>" + list[1][0] + "</li>")
document.writeln("<li>" + list[1][1] + "</li>")
document.writeln("<li>" + list[1][2] + "</li></ul>")
/*Первый уровень, второй пункт*/
document.writeln("<li>" + list[0][1] + "</li>")
/*Второй уровень*/
document.writeln("<ul><li>" + list[2][0] + "</li>")
document.writeln("<li>" + list[2][1] + "</li></ul>")
/*Первый уровень, третий пункт*/
document.writeln("<li>" + list[0][2] + "</li>")
/*Второй уровень*/
document.writeln("<ul><li>" + list[3][0] + "</li>")
document.writeln("<li>" + list[3][1] + "</li>")
document.writeln("<li>" + list[3][2] + "</li>")
document.writeln("<li>" + list[3][3] + "</li></ul></ul>")

Результат:

Для чего это нужно?

Чтобы для настройки и «оживления» меню можно было программно обращаться к его пунктам как к элементам массива.

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

О методах сортировки элементов массива я расскажу, когда мы будем говорить о методах JavaScript.

Встроенные массивы

Поскольку JavaScript предназначен прежде всего для web-страниц, некоторые элементы HTML встроены в него как массивы (иногда их называют коллекциями).

К таким массивам-коллекциям относятся формы — forms() и изображения — images().

Допустим, на нашей web-странице несколько раз встречается тэг <img>. Первый <img> будет автоматически определяться как images[0], и т.д. по порядку появления в коде. То же и с формами.

Иногда это бывает удобно, но не всегда.

В Ассоциации «Русская Традиция» при Петербургском Союзе композиторов, в которой я состою, двое из музыкантов являются также и одарёнными художниками. И я сделал на сайте Ассоциации маленькую галерею (можете посмотреть). И использовал эту встроенную коллекцию. А потом решил резко поменять дизайн всего сайта. А поскольку в элементах дизайна тоже есть графика, то нумерация сбилась, и я двое суток сидел и правил цифры. А на третьи сутки до меня дошло, что лучше это сделать, например, через getElementById() — помните? — присваиваем тэгу id и обращаемся к нему этим методом.

Но есть от встроенных массивов и настоящая польза. У элементов этих массивов есть свойства, присущие их объектам-прототипам. Так, элементы коллекции forms() имеют свойства method, action, name, а элементы images() — свойства src, width, height. Таким образом, мы можем создавать некие «абстрактные» элементы массива, а потом определять для них конкретный тэг. Это хорошо работает в слайд-шоу, когда в одном тэге программно заменяются картинки, определённые в скрипте.

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

imgslide = new Array()
imgslide[0] = new Image()
imgslide[1] = new Image()

Обратите внимание: элементы называются в единственном числе — Image(), а не images(), как вся коллекция. И с большой буквы (тогда как коллекция — с маленькой).

Усложняем слайд-шоу № 9

В «Диких уроках HTML» урок № 9 посвящён созданию слайд-шоу на JavaScript. Мы немного усложним этот скрипт.

Там фотоальбом посвящён кошкам. Я тоже люблю и кошек (у самого два кота), и собак (увы, на них у меня аллергия), но ещё больше — друзей. Есть у меня друг Гена Змитрович, талантливый скульптор и художник. И в нашем уроке я хочу представить несколько его работ. А поскольку он выступает в двух ипостасях, как художник и как скульптор, у нас будет два слайд-шоу, с картинами и скульптурами, но управляться они будут одним скриптом.

Этот скрипт — своего рода контрольное задание. Кроме массивов, в нём используется ряд операторов, которые мы изучили, а также он продемонстрирует, как можно использовать логический (булев) тип данных.

Если Вы сможете сами соорудить подобный скрипт, значит, уже перешли из категории «чайников» в категорию «кофейников»:)

Объявим две переменных счётчика и два массива — для картин и для скульптур. Элементы массивов сразу объявим как images.

(В первоначальном варианте я для простоты дал один счётчик, но с ним функция работала не совсем корректно. Так что пусть будет немного сложнее, но без халтуры.).

var i = 0, j = 0;

imgslide = new Array()
imgslide[0] = new Image()
imgslide[1] = new Image()
imgslide[2] = new Image()
imgslide[3] = new Image()
imgslide[4] = new Image()

imgslide2 = new Array()
imgslide2[0] = new Image()
imgslide2[1] = new Image()
imgslide2[2] = new Image()
imgslide2[3] = new Image()
imgslide2[4] = new Image()

Высота у всех изображений одинаковая — 300 px. А вот ширина немножко разная. Воспользуемся свойствами элементов встроенного массива. Кроме ширины width укажем имена и пути файлов src.

imgslide[0].src = "lsn_js10.files/plakha.jpg"
imgslide[0].width = "225"

Что, так и будем по два раза каждый элемент прописывать?

Для сокращения кода существует вспомогательный оператор with. Сейчас научу, как им пользоваться.

Один раз упомянув в круглых скобках объект, в фигурных можно выписать все его свойства и методы через точку с запятой:

with (объект) {свойство_или_метод; свойство_или_метод}

Теперь наш код приобретёт более компактный вид:

with (imgslide[0]) {src = "lsn_js10.files/plakha.jpg"; width = "225"}
with (imgslide[1]) {src = "lsn_js10.files/grav.jpg"; width = "224"}
with (imgslide[2]) {src = "lsn_js10.files/history.jpg"; width = "200"}
with (imgslide[3]) {src = "lsn_js10.files/porog.jpg"; width = "202"}
with (imgslide[4]) {src = "lsn_js10.files/dedal.jpg"; width = "232"}

with (imgslide2[0]) {src = "lsn_js10.files/applegir.jpg"; width = "178"}
with (imgslide2[1]) {src = "lsn_js10.files/atlant.jpg"; width = "181"}
with (imgslide2[2]) {src = "lsn_js10.files/afrodita.jpg"; width = "193"}
with (imgslide2[3]) {src = "lsn_js10.files/turgenev.jpg"; width = "199"}
with (imgslide2[4]) {src = "lsn_js10.files/obelisk.jpg"; width = "222"}

Все картины и скульптуры как-то называются. Картины у Змитровича философские. А среди скульптур есть и памятник, и кубок, и просто миниатюры. С названиями легче. Давайте сделаем, чтобы и названия выпрыгивали.

Для этого заготовим ещё два массива — тоже для картин и для скульптур.

imgname = new Array()
imgname[0] = "Плаха"
imgname[1] = "И сказал Бог: «Да будет свет!»"
imgname[2] = "История"
imgname[3] = "Порог"
imgname[4] = "Дедал"

imgname2 = new Array()
imgname2[0] = "Девочка с яблоком"
imgname2[1] = "Почетный приз «Атлант»"
imgname2[2] = "Пеннорожденная Афродита"
imgname2[3] = "И.С.Тургенев"
imgname2[4] = "Памятник Л.Богданову"

Принцип работы будет такой: в левой половине — слайд с картинами и под ним две кнопки: «вперёд» и «назад». Под кнопками — меняющееся название. Справа — аналогичная конструкция для скульптур (всё это можно поместить в таблицу с двумя <td> по 50%). Кнопки мы возьмём из стандартного элемента form.

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

Сначала сформулируем задачи:

Кнопка «вперёд» должна «бесконечно» прокручивать картинки вперёд, то есть, дойдя до конца, возвращаться к началу.

Кнопка «назад» должна делать то же самое, но в обратном направлении.

Пары кнопок должны работать автономно, прокручивая только свой слайд.

Вот сейчас и пора вспомнить гениального Джорджа Буля, который утверждал, что самые сложные проблемы можно решить через последовательность цепочек «да» и «нет».

Нам нужны всего две таких цепочки:

вперёд-назад — да-нет;

картины-скульптуры — да-нет.

Эти два булевых выражения и станут аргументами нашей функции. Поскольку это «родная дочь» функции dem(n) из Дикого урока № 9, назовём её dem_plus(n,k). Приведу её всю, а дальше будем разбираться, что к чему.

function dem_plus(n, k)
{
var
dlina;
switch (k)
{
  case true:

  // определяем размерность первого массива
  // и подставляем значение в код для кнопок

  dlina = imgslide.length
    if (n == true)
    { i++;
      if (i == dlina)
      i = 0;
    }
    else
    {
i--;
      if (i == -1)
      i = (dlina - 1);
    }
    with
(document.images("pic"))
    {src = imgslide[i].src;
    width=imgslide[i].width}
    document.getElementById("picname").innerHTML = imgname[i]
  break
  case false:

  // определяем размерность второго массива
  // и снова подставляем, используя новый счётчик

  dlina = imgslide2.length
    if (n == true)
    { j++;
      if (j == dlina)
      j = 0;
    }
    else
    {
j--;
      if (j == -1)
      j = (dlina - 1);
    }
    with
(document.images("sculp"))
    {src = imgslide2[j].src;
    width = imgslide2[j].width}
    document.getElementById("sculpname").innerHTML = imgname2[j]
  }
}

Количество картин и скульптур в нашем примере одинаково. Но оно может быть и разным. Для этого нам и нужны два счётчика. Но это ещё не всё. Для правильной работы функция должна «знать» фактическую длину каждого массива. Поэтому объявим в ней переменную dlina, чтобы, воспользовавшись свойством массива length, динамически определить «потолок» для каждой группы слайдов.

(Вспомните, что переменная, объявленная внутри функции, «живёт» только в теле этой функции. Но здесь нам этого вполне достаточно.)

Сначала разнесём разные слайды. С этим управится второй аргумент — k. Тут никаких особых действий — просто «да» и «нет». Не будем конструировать «если бы да кабы», а используем простой переключатель switch. И в случае true (картины) будем использовать счётчик i, а в случае false (скульптуры) — j.

Аргумент n отвечает за «вперёд-назад». Если он true, то вперёд. Счётчик (i или j) будет считать картинки по возрастающей.

Теперь внимание: пошла арифметика, в которой можно и запутаться.

Какова размерность массива картин (скульптур)? Как мы помним, это составит их реальное количество + 1 (см. прошлый урок). Значит, dlina даст нам на 1 номер больше, чем их количество.

Значит, когда счётчик перейдёт на значение dlina (элемента с таким номером уже нет, понятно, почему?), нужно взмахнуть волшебной палочкой и превратить его в 0. Вот видите, можно и так циклы делать, не используя специальных операторов. Но здесь нам не нужен самодвижущийся цикл. «Движок» — это «юзер» с мышкой.

В противном случае (else) делаем «пач-пач-пач» (назад). За нулём — что там в школе проходили? Минус единичка. Её-то мы и превращаем в...

Будьте внимательны! В dlina - 1. Именно это и будет номером последней картинки, который нам нужен.

Кончилась абстракция, теперь мы имеем дело с конкретными объектами на web-странице. Давайте отвлечёмся от функции и подготовим плацдарм.

Вот наши окошки для слайдов. Можно воспользоваться и порядковыми номерами из коллекции. Но давайте дадим дизайнеру возможность оформить страницу, не заморачиваясь сохранностью её содержимого. Поэтому лучше дадим нашим окошкам имена собственные: pic и sculp.

Да, у нас же ещё и названия! Так что зададим имена и тем абзацам или заголовкам (у меня <h3>), в которых эти названия должны появляться.

Теперь вернёмся к функции. Зададим для подготовленных окошек имя файла и ширину картинки (можно опять через with), а также текст названия (из массивов imgname и imgname2). В качестве номера элемента указываем счётчик. Если счётчик будет работать правильно, он сам будет подставлять нужные номера.

Метод innerHTML возвращает то, что находится внутри указанного тэга HTML (в данном случае — текст). Подробнее об этих методах будем говорить позже.

Разбросаем всё по случаям true (картины) false (скульптуры).

Не забудем поставить break!

Нам нужно либо одно, либо другое, а не всё сразу!

Аккуратно закрываем все скобки. Функция готова.

Вызывать её будем из кнопок формы (из атрибута onClick) с нужными аргументами (true или false).

В реальные тэги HTML (по умолчанию) вставим параметры нулевых слайдов.

Вот примерно что должно быть в <body> (проанализируйте, как расподожены аргументы true и false в вызовах функции):

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td width=
"50%" align="center">
<h3>Живопись</h3>
<img src="lsn_js10.files/plakha.jpg" alt="" name="pic" id="pic" width="225" height="300" border="0"></td>
<td width=
"50%" align="center">
<h3>Скульптура</h3>
<img src="lsn_js10.files/applegir.jpg" alt="" name="sculp" id="sculp" width="178" height="300" border="0"></td>
</tr>
<tr>
<td align=
"center"><form name="form1">
<input type=
"button" value="Назад" onClick="dem_plus(false, true)">
<input type=
"button" value="Вперед" onClick="dem_plus(true, true)">
</form>

<h3 id="picname">Плаха</h3></td>
<td align=
"center"><form name="form2">
<input type=
"button" value="Назад" onClick="dem_plus(false, false)">
<input type=
"button" value="Вперед" onClick="dem_plus(true, false)">
</form>

<h3 id="sculpname">Девочка с яблоком</h3></td>
</tr>
</table>

А теперь смотрим, как это работает.

Не работает?..

Ага, значит, у Вас браузер Netscape, Mozilla или Firefox. Они не всегда понимают document.images (впрочем, иногда и понимают, но действуют непредсказуемо).

Как это исправить?

Так Вы уже знаете, как.

У наших тэгов <img> есть id? А знаем мы, что такое getElementById? Ну так полный вперёд!

Это будет Вашим самостоятельным домашним заданием. А чтобы проверить себя и заглянуть в ответ... у Вас есть мышка с двумя, по крайней мере, кнопками. Поняли, где лежит ответ?


Геннадий Змитрович

скульптор и художник


Живопись

Скульптура

Плаха

Девочка с яблоком


Подробнее с работами автора можно познакомиться на сайте Геннадия Змитровича


Конец первой части

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


Итак, мы узнали:

какие бывают массивы и как их можно использовать, а также как использовать вспомогательный оператор with.

А также научились:

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


Ко второй части >>


 007781