...

пятница, 13 марта 2015 г.

[Из песочницы] Создаем свое Amazon-like навигационное меню

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

image



Как же это сделать?




Предполагается, что у вас на сайте подключен jQuery. Если нет — можете переработать скрипт под чистый JS. На Github уже есть готовый плагин для этого, написанный Бен Кэменсом. Но мне он показался слишком громоздким и не слишком подходящим для текущего меню. Поэтому было принято решение писать свой скрипт.

Сразу могу сказать, что это не изобретение велосипеда, а скорее краткое руководство по созданию амазон-меню. Далее более подробная информация о поставленной задаче и ее решении:


Итак, имеется меню с фиксированной шириной:


image


Это существенно упрощает задачу. Для каждого положения курсора вычисляется треугольник с вершинами в верхнем и нижних углах списка и курсоре. Если курсор попадает на область другого элемента в голубом треугольнике, уже открытое подменю сменится, но с задержкой, которая даст пользователю возможность протащить курсор в область подменю. Далее используем известные координаты. А именно: нижние вершины. Все, что нам нужно вычислить — это текущее положение курсора. Кроме того, нужно запомнить предыдущее значение положения курсора. На этом хватит теории, дальше — больше практики.


Как было раньше




Верстка меню:

<div class="menu-all">
<ul>
<li><a>Caption</a>
<div class="dropdown-menu-main">some content</div>
</li>
<li><a>Caption 2</a>
<div class="dropdown-menu-main">some content 2</div>
</li>
</ul>
</div>


Обработчик для меню:



$(".menu-all > ul > li").hover(function(){
$(this).addClass("active").find("div.dropdown-menu-main").show();
$("#over-hidden").addClass("over");
}, function(){
$(this).removeClass("active").find("div.dropdown-menu-main").hide();
$("#over-hidden").removeClass("over");
});




В итоге получается:

image


Ок, исправляем ситуацию.


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



// Присваиваем координаты для предыдущей позиции курсора
var x2 = 0;
var y2 = 0;

// Известные координаты нижних углов треугольника
var x1 = 0;
var y1 = 70;
var x3 = 900;
var y3 = 70;

// Присваиваем зничение вспомогательной переменной
var in_delta = false;

// При наведении на меню так же присваиваем ей false
$('.dropdown-menu-main').mouseenter(function() {
in_delta = false;
});

// Ну и теперь самое главное событие
$('.menu-all > ul > li').mousemove(function(e) {
var parentOffset = $(this).parent().offset();

// Берем текущие координаты курсора
var x0 = e.pageX - parentOffset.left;
var y0 = e.pageY - parentOffset.top;

// Ну и теперь простая формула для определения находится ли курсор в треугольнике
var z1 = (x1 - x0) * (y2 - y1) - (x2 - x1) * (y1 - y0);
var z2 = (x2 - x0) * (y3 - y2) - (x3 - x2) * (y2 - y0);
var z3 = (x3 - x0) * (y1 - y3) - (x1 - x3) * (y3 - y0);
if ((z1 > 0 && z2 > 0 && z3 > 0) || (z1 < 0 && z2 < 0 && z3 < 0)) {
in_delta = true;
} else {
// Здесь непосредственно нужный нам код для показа меню
$('.menu-all > ul > li.active').removeClass('active').find("div.dropdown-menu-main").hide();
$(this).addClass("active").find("div.dropdown-menu-main").show();
$("#over-hidden").addClass("over");

// И сразу же присваиваем значение нашей переменной
in_delta = false;
}

// Ну и обязательно присваиваем значения координатам для "предыдущего значения положения" для следущего события
x2 = e.pageX - parentOffset.left;
y2 = e.pageY - parentOffset.top;
}).mouseleave(function() {
if (!in_delta) {
// Здесь код для скрытия меню
$(this).removeClass("active").find("div.dropdown-menu-main").hide();
$("#over-hidden").removeClass("over");
}
});


Вот и все.


Удачи при воспроизведении!


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий