Через два часа поисков я понял, что изобретать придётся. Варианты делились на две большие группы: кустарные (то есть ограниченно работоспособные) и маниакально-величественные (требовавшие установки библиотек, инициализации приложений и танцев с бубнами).
В моём распоряжении была библиотека Prototype, успевшая обновиться до версии 1.6.
Стратегия решения: каждый пункт меню являет собой div с атрибутом float: left. Открываемое подменю — тоже div, но абсолютно позиционированный так, чтобы возникнуть под своим родительским пунктом.
Дополнительные условия: 1) меню описано как массив в PHP для простоты работы; 2) позиционирование подменю не задаётся во время дизайна, а определяется при загрузке страницы. Иначе нельзя избежать мелких косяков из-за особенностей рендеринга в разных браузерах, а изменение строки меню вообще выльется в хаос.
Среди новых методов Element в этой версии Prototype обнаружил два просто замечательных:
absolutize 1.6
Turns element
into an absolutely-positioned element without changing its position in the page layout.
Turns
element
into an absolutely-positioned element without changing its position in the page layout.clonePosition 1.6
Clones the position and/or dimensions of source
onto element
as defined by the optional argument options
.
Clones the position and/or dimensions of
source
onto element
as defined by the optional argument options
. Создание HTML-кода меню в PHP:
$x=1;
foreach ($MENU as $d=>$m) {
if (is_array($m)) {
echo "<div id='item$x' class='menuItem' onClick='menuExpand($x);'>$d</div>";
echo "<div id='submenu$x' class='subMenu' style='display: none;'>";
foreach ($m as $item=>$href) {
echo "<nobr><a href='$href' class='menuItemHref'>$item</a></nobr><br />";
}
echo "</div>";
?>
<script type='text/javascript'>
Menu[Menu.length]=<?php echo $x; ?>
</script>
<?php
}
else {
echo "<div id='item$x' class='menuItem'><a href='$m' class='menuItemHref'>$d</a></div>";
}
++$x;
}
Понятно, что, если какое-то значение в массиве $MENU — тоже массив, то это описание подменю; иначе пункт меню — сам по себе ссылка, без наворотов.
Яваскрипт, добавляющий текущий индекс родительских пунктов меню в глобальный явскрипт-массив Menu, нужен будет для инициализации подменюшек.
Сперва я сделал просто: сразу после создания div для подменю инициализировал его позицию. Это работало в Firefox, но в IE не прошло из-за чудной манеры последнего создавать DOM лишь по окончании загрузки страницы, то есть когда я пытался получить свойства div#item1, его ещё не существовало в IE.
Пришлось просто заносить в массив Menu те пункты, у которых есть подменю, чтобы инициализировать их позже, по событию onLoad:
function menuInit() {
var menuHeight=$('item1').getHeight();
Menu.each(function(expandThis) {
$('submenu'+expandThis).absolutize();
$('submenu'+expandThis).clonePosition('item'+expandThis, { setHeight: false, offsetTop: menuHeight });
});
}
Мы берём высоту меню в переменную menuHeight, затем проходимся по всем подменю, делая их позицию абсолютной и помещая их относительно родительского пункта, смещая вниз на высоту оного.
Теперь прикручиваем обработчик нажатия на родительское меню:
function menuExpand(n) {
Menu.each(function(i) {
// Закрыть возможные открытые подменю, тупо пряча их все
if (i!=n) { $('submenu'+i).hide(); }
});
$('submenu'+n).toggle();
}
Метод toggle здесь вместо ожидаемого show для того, чтобы повторное нажатие на родительский пункт закрывало подменю.
Описываем меню в CSS:
.menuItem {
float : left;
padding-left: 7px;
padding-right: 20px;
font-family: sans-serif;
font-size: 10pt;
cursor: pointer;
}
.menuItemHref {
color: black;
text-decoration: none;
}
.subMenu {
display: table;
border: solid 1px black;
padding: 5px;
font-family: sans-serif;
font-size: 9pt;
background-color: #e98080;
line-height: 15pt;
}
Собираем в кучу, и... мама, мама, что делается, Люська с Манохиным прилетели...
Всё меню создано десятком строк на Яваскрипте, совместимо с тремя основными браузерами (возможно, и с остальными). Prototype — это страшная сила.
2 комментария:
Привет. Художник ты авторитетный, спору нет. А насчет РНР разреши дать небольшой совет: не выводи HTML в PHP коде. Есть шаблоны, это окупается сторицей.
Я вот когда соображаю, на сколько вещь надо делать правильно, а на сколько
— эффективно, вспоминаю пример, читанный в книге по Перлу. Там високосный год вычислялся регистровым сдвигом, то есть, несмотря на уровень языка — практически средствами ассемблера. В смысле перспектив рефакторинга этот код был чудовищен, конечно. Лично я 15 минут чёркал по листочку карандашом, чтобы понять, как он работает.
Но зато как он работал!
Правильно было бы, конечно, использовать подходящий модуль. Только что правильнее — решить задачу правильным способом или решить её оптимально? Правильного ответа нет, мне кажется. Надо балансировать.
Отправить комментарий