Урок 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 = "album/plakha.jpg" imgslide[0].width = "225"

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

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

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

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

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

with (imgslide[0]) {src = "album/plakha.jpg"; width = "225"} with (imgslide[1]) {src = "album/grav.jpg"; width = "224"} with (imgslide[2]) {src = "album/history.jpg"; width = "200"} with (imgslide[3]) {src = "album/porog.jpg"; width = "202"} with (imgslide[4]) {src = "album/dedal.jpg"; width = "232"} with (imgslide2[0]) {src = "album/applegir.jpg"; width = "178"} with (imgslide2[1]) {src = "album/atlant.jpg"; width = "181"} with (imgslide2[2]) {src = "album/afrodita.jpg"; width = "193"} with (imgslide2[3]) {src = "album/turgenev.jpg"; width = "199"} with (imgslide2[4]) {src = "album/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="album/plakha.jpg" alt="" name="pic" id="pic" width="225" height="300" border="0"> </td> <td width="50%" align="center"> <h3>Скульптура</h3> <img src="album/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? Ну так полный вперёд!

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


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

...

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


Живопись

Скульптура

Плаха

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


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


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

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

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

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

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

К следующему уроку

К списку уроков JavaScript

(© А. Фролов)