Роботландский Университет © А.А.Дуванов

НА КУХНЕ У СИДОРОВА

i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ?
урок 11 | меню 3 | меню 4 | меню 5 | меню 6 | меню 7 | урок 13

Искре-1256 посвящается...

Мы снова на программистской кухне Ивана Сидорова.

Он товарищ открытый, секретов не держит и всегда готов поделиться своими находками за чашкой крепкого чая. Так было и встарь в славном городе Благовещенске, где сиживал он с друзьями в ЛПМ БГПИ (лаборатория прикладной математики Благовещенского пединститута).

Ах, что тогда вытворялось там, на технике, которая теперешним школьникам и не снилась! Взять хотя бы такого отечественного монстра персонального компьютеростроения как Искра-1256. Оперативной памяти — аж 4 КБ! Вместо дисководов — один накопитель на кассете от обычного бытового магнитофона.

Язык программирования тоже отечественный, без названия. Иван с друзьями окрестили его Дуб, за жесткую непоколебимую сущность. Представьте, имена переменных нельзя было выбирать произвольно, все они были предопределены заранее конструкторами языка. Какая-то гремучая смесь из Алгола и Ассемблера. Внешний вид программ — не для слабонервных. Иван точно не помнит, но, кажется, в языке не было даже комментариев.

Тем не менее, было бы вдохновение, да интерес, да мускулистые руки — посадим картофель и лопатой! А уж этого добра (интереса и вдохновения) было в ЛПМ сколько угодно. И лились рекой крепкие чаи (иногда с ложкой спирта для протирки клавиатуры), и рождались на 4 КБ удивительные вещи. Например, среда исполнителя Кукарача. В среде и сам исполнитель, и редактор программ для него, и, конечно, транслятор.

Техника теперь изменилась, Сидоров уехал из Благовещенска. Пьет он теперь чай один на своей “кухне” для компьютера с 256 МБ памятью и увлечен HTML, JavaScript, CSS.

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

Заметки посвящены теме меню, которая была затронута на предыдущем уроке.

— Меню нужны разные! — так подумал Иван и налил первый стакан чаю.

урок 12: меню

Список примеров Ивана Сидорова:

меню ссылок на UL

Стандартный список HTML — чем не меню? Вот вам и пример этого:

Код этого меню — проще не бывает:

До того просто, что не интересно. Никакого JavaScript, CSS. Так не пойдет. Давайте создадим функцию, которая будет сама строить это меню там, где нам надо.

Пусть интерфейс функции будет таким:

menu1(
      "Раздел1", "item1.htm",
      "Раздел2", "item2.htm",
      "Раздел3", "item3.htm"
    );

В аргументах функции записываются название разделов и ссылки, им соответствующие, а функция строит на экране список.

Построить список динамически можно при помощи метода write объекта document. Есть только одна особенность: число аргументов функции menu1 заранее неизвестно. Но и это не беда: JavaScript для каждой нашей функции строит одноименный объект. Аргументы функции записываются в специальный массив этого объекта:

имя_функции.arguments

Внутри самой функции можно писать короче:

arguments

Длина массива, а значит, число аргументов функции, как обычно, содержится в свойстве arguments.length. Учитывая вышесказанное, кодируем функцию так:

// Построение списка ссылок.
// Обращение к функции:
// menu1(
//          "имя раздела меню", "ссылка",
//          ...
//          "имя раздела меню", "ссылка",
//      );
function menu1()
{
  var alen = arguments.length; // Число аргументов функции.
  if(alen < 1) // Функция работает,
  {            // если число аргументов больше одного.
    // Если число аргументов нечетно,
    //  последний аргумент игнорируем.
    if(alen%2) alen--;
    // Строим начальный тег списка.
    document.write("<UL type=disc>");
    // Построение списка.
    for(var i=0; i<alen; i+=2)
      document.write("<LI><A href="+arguments[i+1]+">"+
                     arguments[i]+"</A>");
    document.write("</UL>"); // Строим конечный тег списка.
  }
}

Функция menu1 не использует сложных данных и глобальных переменных, поэтому заменять ее объектом особого смысла не имеет. Меню можно отобразить следующим кодом (описание функции menu1 расположено в файле menu1.js):

Переход к этому документу.

Обязательно посмотрите исходный текст этого HTML-файла. Файл находится по адресу: ./sidorov/menu1.htm. Функция menu1 оформлена в качестве отдельного js-файла: ./sidorov/menu1.js.

Меню ссылок на SELECT

Второй стакан чая Иван поднял за тег SELECT.

Без JavaScript меню вроде того, что показано ниже, интересно, но бесполезно:

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

Функция menu2_go, которая обрабатывает щелчок на кнопке Пуск, может быть такой:

function menu2_go(sel)
{
  var link;
  if     (sel.selectedIndex==0) link="item1.htm";
  else if(sel.selectedIndex==1) link="item2.htm";
  else                          link="item3.htm";
  location.href=link;
}

Да, но мы поставили задачу написать функцию с универсальным интерфейсом:

menu2(
      "Раздел1", "item1.htm",
       ...
      "Разделn", "itemn.htm"
     );

Придется опять поработать с функцией write объекта document. Вот код, который сделает все, что задумано:

// Построение меню ссылок.
// Обращение к функции:
// menu2(
//          "имя раздела меню", "ссылка",
//          ...
//          "имя раздела меню", "ссылка"
//      );
//----------------------------------------
var links = new Array(); // В этот массив помещаются ссылки.
function menu2()
{
  var alen = arguments.length; // Число аргументов функции
  if(alen < 1) // Функция работает,
  {            // если число аргументов больше одного.
    // Если число аргументов нечетно,
    // последний аргумент игнорируем.
    if(alen%2) alen--;
    document.write("<FORM><SELECT name=select size= "+alen/2+">");
    // Построение позиций меню и заполнение массива ссылками.
   for(var i=0; i<alen; i+=2)
   {
     document.write("<OPTION>"+arguments[i]+"</OPTION>");
     links[i/2] = arguments[i+1];
   }
   document.write("</SELECT><INPUT type=button value=Пуск"+
                  " onclick='menu2_go(this.form.select)'></FORM>");
  }
}
// Обработка щелчка на кнопке "Пуск"
function menu2_go(sel)
{
  location.href= links[sel.selectedIndex];
}

Пример вызова функции menu2.

Файл документа находится по адресу: ./sidorov/menu2.htm. Функция menu2 оформлена а качестве отдельного js-файла: ./sidorov/menu2.js.

Построенным скриптом Иван остался недоволен. Функция menu2 использует глобальный массив links. Если на одной гипертекстовой странице построить несколько таких меню, неизбежно возникнут проблемы. Ведь массив links — один!

Выход прост: надо для меню построить объект, а массив links спрятать внутри. Тогда для каждого экземпляра будет создаваться своя копия этого массива.

Иван построил объект MenuSelect. Скрипт он разместил в файле menu3.js:

// Меню ссылок (объект MenuSelect).
// Использование.
// 1. Создать экземпляр объекта:
//  var имя_экземпляра=MenuSelect(имя_экземпляра,
//                                название1,
//                                ссылка1, ...);
//  Здесь:
//    имя_экземпляра - имя созданного экземпляра;
//    название1      - текст для первой строки меню;
//    ссылка1        - ссылка для первой строки меню.
// 2. Настроить внешний вид меню используя свойства объекта:
//  имя_экземпляра.allview = true  - видны все строки меню
//  имя_экземпляра.allview = false - видна одна строка меню
//                                   (по умолчанию)
//  имя_экземпляра.mark = 0 - отмеченная строка
//                            (по умолчанию первая)
//  имя_экземпляра.textgo - текст на кнопке "Пуск"
//                          (по умолчанию "Пуск").
// 3. Показать меню на экране:
//    имя_экземпляра.Show();
//------------------------------------------
// Описание одной строки меню (название, ccылка).
function item(name, link)
{
  this.name=name; // Текст в строке меню.
  this.link=link; // Ссылка, соответствующая тексту.
}
// Конструктор главного объекта.
function MenuSelect()
{
  // Свойства объекта для пользователя.
  this.allview = false;
  this.textgo  = "Пуск";
  this.mark    = 0;
  // Методы объекта для пользователя.
  this.Show = _Show;

  // Внутренние переменные.
  this.items = new Array();    // Массив строк меню.
  this.name  = arguments[0];   // Имя экземпляра объекта.

  // Внутренние функции.
  this.Make   = _Make;         // Щелчок на строке меню.

  var alen = arguments.length; // Число аргументов конструктора
  if(!alen%2) alen--;          // должно быть нечетным.
  // Заполним массив items (строки меню).
  var j = 0; // Это индекс по массиву items.
  for(var i=1; i<alen; i+=2)
    this.items[j++] = new item(arguments[i],arguments[i+1]);
}

// Обработка нажатия кнопки Пуск.
function _Make(sel)
{
  location.href = this.items[sel.selectedIndex].link;
}
// Генерация HTML-кода для построения меню на экране.
function _Show()
{
  var len = this.items.length;
  var str= "<FORM><SELECT name=select size="+
            (this.allview ? len:1)+">";
  for(var i=0; i<len; i++)
      str += "<OPTION" + (i==this.mark ? " selected>" : ">") +
             this.items[i].name+"</OPTION>";
  str += "</SELECT><INPUT type=button value='"+this.textgo+"'"+
         " onclick='"+this.name+".Make(this.form.select)'>"+
         "</FORM>";
  document.write(str);
}

Иллюстрирующий документ.

Скрипт размещается в файле ./sidorov/menu3.js, пример использования в файле ./sidorov/menu3.htm.

Меню на стандартных кнопках

— Обычные кнопки <INPUT type=button> тоже годятся для меню, — подумал Иван. Нажал такую кнопочку — и получил результат.

Недолго думая, Сидоров написал такую программу:

Переход к документу (./sidorov/menu4.htm).

Кнопочки работают хорошо, но длина у них получилась разная, что, конечно, портит дизайн.

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

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

Потом он вдруг вспомнил про CSS (каскадные таблицы стилей) о которых прочитал в умной книжке, и написал такое стилевое определение:

INPUT
{
  width:300px;
  font-size:10pt;
}

Теперь размеры всех кнопок стали одинаковыми.

Переход к документу (./sidorov/menu5.htm).

Меню на графических кнопках

Иван Сидоров сделал несколько меню на графических кнопках, которые нарисовал для него компьютерный художник Саша Мур. Саша нарисовал два экземпляра кнопок. Первый набор — основной:

Второй — вид кнопок, когда над ними находится курсор мыши:

Иван — большой любитель порядка. Он придумал для файлов с картинками следующие имена.

Имена файлов для первого набора кнопок:

key011.gif, key021.gif, key031.gif, key041.gif, key051.gif, key061.gif, key071.gif

Имена файлов для второго набора кнопок.

key012.gif, key022.gif, key032.gif, key042.gif, key052.gif,key062.gif, key072.gif

Меню на этих кнопках получилось таким:

Для вывода такого меню на экран Иван использовал объект MenuPic:

//-- Файл menupic.js
// Меню ссылок на графических кнопках.
// (работает в Internet Explorer и Netscape Navigator)
// Использование
// -------------
// Меню представляет собой объект MenuPic. Необходимо:
// 1. Подготовить картинки кнопки и дать им имена по правилу:
//    имя011.расширение  - первая кнопка, курсор не над кнопкой;
//    имя012.расширение - первая кнопка, курсор над кнопкой;
//    ...
//    Пример
//    key011.gif
//    key012.gif
//    ...
// 2. Создать экземпляр объекта.
//    var имя_экземпляра = MenuPic(
//           имя_экземпляра, основа, расширение, ширина, высота,
//           название1, ссылка1, ...);
//    Здесь:
//    имя_экземпляра - имя экземпляра объекта MenuPic
//                     (например, "mp");
//    основа         - основа имени картинок
//                     (например, "./pic/key");
//    расширение     - расширение имени картинок
//                     (например, "gif");
//    ширина         - ширина картинки (например, 43);
//    высота         - высота картинки (например, 43);
//    название1      - alt-текст для первой кнопки
//                     (например, "Урок 1");
//    ссылка1        - ссылка для первой кнопки
//                     (например, "../01.htm")
//    ...
// 3. Показать меню на экране.
//    имя_экземпляра.Show();
//------------------------------------------
// Описание одной строки меню.
// pic_over -ссылка на картинку под курсором.
// pic_out - ссылка на основную картинку.
// name - содержание alt-надписи кнопки.
// link - URL для перехода.
function item(pic_over, pic_out, name, link)
{
  // Создали два экземпляра объекта Image.
  this.pic_over = new Image();
  this.pic_out  = new Image();

  this.pic_over.src=pic_over;
  this.pic_out.src=pic_out;
  this.name = name;
  this.link = link;
}
// Конструктор главного объекта.
function MenuPic(name,base,ext,width,height)
{
  this.name   = name;        // Имя экземпляра объекта.
  this.width  = width;       // Ширина картинок.
  this.height = height;      // Высота картинок.
  this.items  = new Array(); // Массив позиций меню.
  this.Show   = _Show;       // Метод для показа меню на экране.
  this.ismenu = arguments.length > 6; // false, если
                                      // аргументов мало.
  // Заполнение массива данными
  if(this.ismenu)
  {
    var j=0;
    for(var i=5; i<arguments.length; i+=2)
    {
      var num = j < 9 ? "0"+eval(j+1):eval(j+1);
      this.items[j++] = new item(base+num+"2."+ext,
                                 base+num+"1."+ext,
                                 arguments[i],
                                 arguments[i+1]);
    }
  }
}
// Показать меню на экране
function _Show()
{
 if(this.ismenu)
 {
   document.write("<NOBR>");
   for(var i=0; i<this.items.length; i++)
    document.write(
      "<A href="+this.items[i].link+
      " onmouseover=\"document.images."+this.name+i+".src='"+
         this.items[i].pic_over.src+"'\""+
      " onmouseout=\"document.images."+this.name+i+".src='"+
         this.items[i].pic_out.src+"'\""+
      "><IMG name="+this.name+i+" border=0 src="+
      this.items[i].pic_out.src+
      " width="+this.width+" height="+this.height+
      " alt=\""+this.items[i].name+"\"></A>");
   document.write("</NOBR>");
 }
}

Функцию _Show можно упростить, если внести “мышиные” атрибуты внутрь тега IMG:

function _Show()
{
 if(this.ismenu)
 {
   document.write("<NOBR>");
   for(var i=0; i<this.len; i++)
    document.write(
      "<A href="+this.items[i].link+
      "><IMG border=0 src="+this.items[i].pic_out.src+
      " width="+this.width+" height="+this.height+
      " alt=\""+this.items[i].name+"\""+
      " onmouseover=\"this.src='"+this.items[i].pic_over.src+"'\""+
      " onmouseout=\"this.src='"+this.items[i].pic_out.src+"'\""+
      "></A>");
   document.write("</NOBR>");
 }
}

Замечание. Последний вариант не работает в браузерах NN ниже 6 версии. Первый вариант работает, начиная с NN3. Оба варианта нормально работают в IE, начиная с IE4.

Для показа меню можно написать такой HTML-код:

Переход к документу (./sidorov/menu6.htm).

Наконец, Сидоров решил добавить к картинкам третий набор: кнопки в момент щелчка по ним мышью. Пример использования этого меню показан здесь: ./sidorov/menu7.htm, а объект, строющий меню, расположен в файле ./sidorov/menu7.js.

 

содержание урок 11 урок 13 письмо автору об авторах