强制CSS的解决方法:转换后悬停以更新(打开菜单)

时间:2015-05-24 18:48:03

标签: javascript html css events

解决此问题已有几个问题。我包括我有两个原因:

  • 它建议了一种可能的替代解决方案
  • 演示代码可能对想要模拟菜单
  • 的其他人有用

:hover之后,用户必须先移动鼠标,然后鼠标下方的元素才会注意到它处于li:hover状态。我创建了一个菜单式功能,可以打开以显示不同的选项。打开过渡结束时鼠标下的选项与过渡开始时鼠标下的选项不同。因此,我必须找到一种解决方法。

您可以在下面找到jsFiddle here和演示来源。寻找替代方法(在三个地方)看看我做了什么。

要查看此问题,请将鼠标移到菜单上,然后将其保留在原位,而不移动它。浏览器认为的列表项li.ignoreHover将以蓝色显示。我的解决方法使用:hover类取代了#menu规则。为了使变通方法不可见,我可以简单地使用标准背景颜色。相反,我使用蓝色来显示问题。

我的问题:我注意到按下其中一个修饰键( Caps Caps Lock Ctrl Option / Alt 在Mac上,...)也会强制<!DOCTYPE html> <html> <head> <style> #menu { position: relative; background: #ccc; display: inline-block; } #wrapper { margin: 5px; } #logo { width: 150px; height: 50px; border: 1px solid #000; margin: 0px auto; z-index: 10; } nav { width: 100%; overflow: hidden; text-align:center; height: 2em; } ul { position: relative; display:inline-block; margin: 0 auto; padding: 0; list-style-type: none; text-align:left; } li { display: block; margin: 0; padding:0.25em 0; line-height: 1.5em; } ul.animated, nav { transition: all 500ms linear 1s; } #menu.hover ul, #menu.hover nav { transition-delay: 0s; } li:hover, li.hover { background-color: #999; } li.ignoreHover { background-color: #ccf; /* a touch of blue, so you can see it */ } .selected { color: #fff; } </style> <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> </head> <body> <div id="menu"> <div id="wrapper"> <div id="logo"></div> </div> <nav> <ul> <li>Note one</li> <li>Note two</li> <li>Note three</li> <li>Not four much longer</li> <li>Note five</li> <li>Note six</li> </ul> </nav> </div> <script> var test = {} ;(function createMenu() { var item = 3; var minPadding = 5; var hover = "hover" // class var $li = $("li"); var $ul = $("ul"); var $menu = $("#menu"); var $nav = $("nav"); var itemHeight = parseInt($li.outerHeight(), 10); var itemCount = $ul.children().length; var menuWidth = $menu.outerWidth(true); var padding = (menuWidth - $ul.width()) / 2; var transitionDone = false; var mouseOver = false; var top; // Pad the list items to fill the width of the menu if (padding < minPadding) { // Widen the menu to allow for the minimum padding menuWidth += (minPadding - padding) * 2; $menu.width(menuWidth); padding = minPadding; } $li.css({ paddingLeft: padding, paddingRight: padding }); // Scroll to the current selected item selectItem(true); function selectItem(scroll) { $ul.children().removeClass("selected"); $ul.children().eq(item).addClass("selected"); if (scroll) { top = -(itemHeight * item); $ul.css({ top: top }); } } // Wait until the initial settings are applied // before animating the transitions setTimeout(function () { $ul.addClass("animated"); }, 1); // Handle interaction with the menu $menu.on("mouseover", openMenu); $menu.on("mouseleave", closeMenu); $menu.on("transitionend", menuIsOpen); $ul.on("click", treatClickOnItem); // <WORKAROUND... var x var y // ... WORKAROUND> function openMenu(event) { if (mouseOver) { // This method may be called multiple times as the menu is // transitioning to its open state return } // <WORKAROUND... $menu.on("mousemove", function updateXY(event) { x = event.pageX y = event.pageY }) // ... WORKAROUND> $menu.addClass(hover); transitionDone = false; mouseOver = true; $nav.css({ height: (itemHeight * itemCount) }); $ul.css({ top: 0 }); } function menuIsOpen() { transitionDone = true; // <WORKAROUND... var $hover = $("li:hover").addClass("ignoreHover") var $item = $(document.elementFromPoint(x, y)) if (mouseOver) { $item.addClass(hover) } $menu.on("mousemove", function () { $item.removeClass(hover) $hover.removeClass("ignoreHover") $menu.off("mousemove") }) //... WORKAROUND> if (!mouseOver) { closeMenu() } } function closeMenu() { mouseOver = false; if (transitionDone) { $menu.removeClass(hover) $nav.css({ height: itemHeight }); $ul.css({ top: top }); } } function treatClickOnItem(event) { item = $(event.target).index(); top = -(itemHeight * item); selectItem(); // DO MORE STUFF WITH THE SELECTION } })() </script> </body> </html> 状态更新。有没有办法将这样的事件发送到$("#header-wrapper").removeClassName("container"); 元素?

(我的尝试没有成功,所以我更倾向于给你我的工作解决方案,而不是那些可能无效的工作方法。)

$("#header-wrapper").removeClass("container");

1 个答案:

答案 0 :(得分:3)

<强> jsBin demo

Seems like it's almost impossible获取元素的:hover状态,同时制作动画。

从CSS中删除:hover和 使用所需的样式创建 .hover。使用jQuery切换.hover

$links.hover(function(){
  $(this).toggleClass("hover");
});

现在回到您的问题:

为了在菜单打开后获得正确的元素突出显示 我们需要始终知道鼠标Y的位置:

var mouseY = 0; // Needed to know the mouse position when menu is opening
$(document).on("mousemove", function( e ){
    mouseY = e.clientY; // Update the Y value
});

现在,在折叠菜单悬停时,使用jQuery为您的菜单添加动画,
animate step callback内,通过定位与鼠标位置匹配的位置来获取每个链接位置的每一帧,.filter()。 最后将.hover仅应用于那个:

function openMenu() {
  $navUl.stop().animate({top: 0});
  $nav.stop().animate({height: linkH*nLinks}, {
    duration: 600,
    step: function( menuHeight ){
        // keeps removing and adding class during the animation time.
        // (it's an overkill but no other solution to that issue so far)
        $links.removeClass("hover").filter(function(i, e){
          var t = e.getBoundingClientRect().top;
          return mouseY > t  &&  mouseY < t+linkH;
        }).addClass("hover"); // only to the link returned by `.filter()` condition
    }
  });
}

<强>!重要说明:上述过滤将与您拥有的许多项目一样昂贵,因为它会在每个动画帧中尝试获取位置。如果你发现缓慢 - 改善上述。

回顾
在每一帧检查鼠标clientX/Y坐标是否在元素element.getBoundingClientRect()坐标/值