JavaScript скрипты


Многоуровневое "раздвижное" JavaScript меню

Размещена 29 августа, 2008 года


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

Хэш с исходными данными

Задачу будем решать последовательно. Сначала определимся с форматом входных данных, а имеено: каким должен быть хэш?
Наиболее простой и понятный синтаксис такой (JSON - JavaScript Objecj Notation):
• Код JavaScript
// ******************
// Многоуровнеый хэш c информацией о меню
// ******************
var menuArray = {
      '1.html' : ["Мониторы", {
            '5.html' : ["15 дюймов"],
            '6.html' : ["17 дюймов"],
            '7.html' : ["19 дюймов"],
            '8.html' : ["21 и более дюймов"]
      }],
      '2.html' : ["Жесткие диски", {
            '9.html' : ["40-80 Гб"],
            '10.html' : ["120-160 Гб"],
            '11.html' : ["180-250 Гб"],
            '12.html' : ["300-500 Гб"],
            '13.html' : ["более 500 Гб"]
      }],
      '3.html' : ["Процессоры", {
            'proc=amd' : ["AMD", {
                  '14.html' : ["Athlon"],
                  '15.html' : ["Barton"],
                  '16.html' : ["Sempron"]
            }],
            'proc=intel' : ["Intel", {
                  '17.html' : ["Pentium"],
                  '18.html' : ["Celeron"]
            }]
      }],
      '4.html' : ["Бонус-карта"]
}

Ключи хэша одновренно являются частью URL пунктов меню, что необычайно удобно. В качестве значений всегда выступает массив, первый элемент которого является строкой с именем пункта меню. Второй элемент в массиве присутствует только в случае, если есть вложение и представляет собой аналогичный хеш.

Такой объект очень легко сформировать на сервере, обработав результаты выборки из БД.

Функции и переменные для формирования меню

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

Функция drawJSMenu формирует HTML-код меню и передает его в элемент-контейнер. В качетсве аргументов принимаются id контейнера, вышерассмотренный хэш и путь для ссылок. Для задания имен классов, а также таймаута ожидания существуют константы в начале функции.
Функция hideJSMenu используется для скрытия выпадушек по таймауту.
• Код JavaScript
// ******************
// Глобальные переменные для работы функций
// ******************
var menuWaitTimer = {};
var menuOpenedCount = 0;

// ******************
// Функция формирования HTML-кода меню и вывода на страницу
// ******************
function drawJSMenu(containerId, hash, path) {
      // ----------- Константы ------------
      var commonClassName = "common";
      var parentClassName = "parent";
      var levelClassPrefix = "level_";
      var menuWaitInterval = 500; // ms
      // ----------- Переменные ------------
      var container = document.getElementById(containerId);
      var html = _class = mouseOverOut = id = "";
      var i;
      var idArray = []
      // ----------- Функции ------------
      // Рекурсивная функция для прохождения по многоуровневому 
      // хэшу и формированию HTML-кода меню
      var cicleFunc = function(code, hash, level, parentId) {
            if (typeof level != "undefined" && level != 1) code += "<span id='b" + parentId + "' style='display:none;'>\n";
            for (i in hash) {
                  var randId = parseInt(Math.random() * 1e10).toString() + parseInt(Math.random() * 1e10);
                  _class = 
                        ((typeof hash[i][1] != "undefined") ? parentClassName : commonClassName) + 
                        " " + levelClassPrefix + level;
                  if (typeof hash[i][1] != "undefined") {
                        id = " id='a" + randId + "'";
                        idArray.push(randId);
                  } else id = 0;
                  code += "<a" + (id ? id : "") + " class='" + _class + "' href='" + path + i + "'>" + hash[i][0] + "</a>\n";
                  if (typeof hash[i][1] != "undefined") code += cicleFunc(html, hash[i][1], level+1, randId);
            }
            if (typeof level != "undefined" && level != 1) code += "</span>\n";
            return code;
      }
      // ----------- Добавление HTML-кода меню на страницу ------------
      html = cicleFunc(html, hash, 1);
      container.innerHTML = html;
      // ----------- Добавление обработчиков событий ------------
      for (i = 0; i < idArray.length; i++) {
            document.getElementById("a" + idArray[i]).onmouseover = function() {
                  menuOpenedCount++;
                  var absId = this.id.substring(1, this.id.length);
                  document.getElementById("b" + absId).style.display = "";
            }
            document.getElementById("a" + idArray[i]).onmouseout = function() {
                  menuOpenedCount--;
                  var absId = this.id.substring(1, this.id.length);
                  if (typeof menuWaitTimer[absId] == "undefined" || menuWaitTimer[absId] == null) {
                        menuWaitTimer[absId] = setInterval("hideJSMenu('" + absId + "')", menuWaitInterval);
                  }
            }
            document.getElementById("b" + idArray[i]).onmouseover = function() {
                  menuOpenedCount++;
                  var absId = this.id.substring(1, this.id.length);
                  if (typeof menuWaitTimer[absId] != "undefined") {
                        clearInterval(menuWaitTimer[absId]);
                        menuWaitTimer[absId] = null;
                  }
            }
            document.getElementById("b" + idArray[i]).onmouseout = function() {
                  menuOpenedCount--;
                  var absId = this.id.substring(1, this.id.length);
                  if (typeof menuWaitTimer[absId] == "undefined" || menuWaitTimer[absId] == null) {
                        menuWaitTimer[absId] = setInterval("hideJSMenu('" + absId + "')", menuWaitInterval);
                  }
            }
      }
}

// ******************
// Функция для убирания выпадушек, запускается по таймауту
// ******************
function hideJSMenu(id) {
      if (menuOpenedCount <= 0) {
            menuOpenedCount = 0;
            if (typeof menuWaitTimer[id] != "undefined") {
                  clearInterval(menuWaitTimer[id]);
                  menuWaitTimer[id] = null;
            }
            if (document.getElementById("b" + id)) {
                  document.getElementById("b" + id).style.display = "none";
            }
      }
}

Совместимость


Работоспособность скрипта проверена в:
- IE 6;
- Mozilla Fifefox 1.5;
- Opera 9.2;

Пример использования



Все права на статью принадлежат сайту fastcoder.org
SAPE все усложнил?

MainLink - простая и прибыльная продажа ссылок!

Последние поступления:

Стишки пирожки про Олега⁠⁠

Размещена 20 июня 2024 года

Олег купил презервативы
Проник в семидесятый год
И подарил их папе с мамой
Такой нелепый суицид

читать далее…

Размещена 10 августа 2020 года

Я по ТВ видел, что через 10 лет мы будем жить лучше, чем в Германии...
Я не понял, что это они с Германией сделать хотят?!

читать далее…

ТехЗадание на Землю

Размещена 14 марта 2018 года

Пpоект Genesis (из коpпоpативной пеpеписки)

читать далее…

Шпаргалка по работе с Vim

Размещена 05 декабря 2017 года

Vim довольно мощный редактор, но работа с ним не всегда наглядна.
Например если нужно отредактировать какой-то файл например при помощи crontab, без знания специфики работы с viv никак.

читать далее…

Ошибка: Error: Cannot find a valid baseurl for repo

Размещена 13 сентабря 2017 года

Если возникает ошибка на centos 5 вида
YumRepo Error: All mirror URLs are not using ftp, http[s] or file.
Eg. Invalid release/

читать далее…