JavaScript скрипты
Многоуровневое "раздвижное" JavaScript меню
Задача: написать как можно более универсальную функцию, которая, принимая многоуровневый хэш, смогла бы построить раздвижное меню любой вложенности
Хэш с исходными данными
Задачу будем решать последовательно. Сначала определимся с форматом входных данных, а имеено: каким должен быть хэш?Наиболее простой и понятный синтаксис такой (JSON - JavaScript Objecj Notation):
// ******************
// Многоуровнеый хэш 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 используется для скрытия выпадушек по таймауту.
// ****************** // Глобальные переменные для работы функций // ****************** 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;