鼠标悬停时保持滑动菜单打开

发布于 2024-10-16 06:45:55 字数 1469 浏览 6 评论 0原文

我正在尝试将加载有内联 Javascript 的现有菜单系统转换为仅使用 jQuery 的新的、更高效的代码。

我有一个带有翻转图像的单杠。我在页面中有一个包含整数值的隐藏字段。加载页面时,相应的菜单会加载图像的“粘性”版本,并且所有其他菜单项会在鼠标输入时交换图像。离开。它加载了大量的内联 Javascript 和一个巨大的 Javascript 文件,每次我创建一个新网站时,转换这些文件都很繁琐。

我成功地将这一切转换为 jQuery,在那里我还能够禁用粘性菜单项上的单击。现在,我可以简单地设置一些变量,并根据每个站点的设计轻松自定义它。

工作得很好...

现在出现了一个新问题。一种设计在每个菜单图像下包含一堆滑动抽屉。滑动动画由外部 JS 文件处理,菜单抽屉本身只是一个包含嵌套在容器 DIV 内的内容的 DIV。

然后我为 jQuery 编写了一些简单的东西,为 DIV 制作动画,并在鼠标悬停时将其滑入和滑出菜单图像。

问题是,我似乎无法解决鼠标从菜单图像移开并向下移动到菜单抽屉而不关闭抽屉的问题。我明白“为什么?”...我要留下触发动画以关闭抽屉的图像,然后才能进入抽屉。如果我将悬停动画应用到抽屉容器,它只会在菜单下创建一个区域,该区域也会触发动画,我也不希望这样。对于 jQuery,这似乎变成了一个更复杂的问题。所有这些都在内联 Javascript 中正常工作...您只需将鼠标从图像移动到相邻打开的抽屉中,而无需触发关闭它的功能...就好像抽屉的内联“鼠标输入”取消了图像的“鼠标离开”。

有什么建议吗?

谢谢你!


编辑:

我相信我在从图像传递到抽屉时通过使用 .stop(true, false) 解决了这个问题。这会在动画开始之前停止动画。然后,在启动正常动画之前输入图像时也是如此...这具有停止因离开抽屉并进入图像而触发的动画的效果,但在正常进入图像时也不会执行任何操作。更多测试,然后我将发布一些示例代码。


编辑#2:

我让它与“stop()”和“delay()”一起工作来控制动画,但如果你能让鼠标进入抽屉的速度比打开抽屉的速度快,就可以冻结抽屉的打开。安装时间为 150 毫秒。但现在设置为 300 毫秒会夸大问题。

相关代码发布在这里...

jsfiddle.net/qPLVp/8/


编辑#3:

感谢尼尔,现在运行得很好。通过更快的动画速度,鼠标越过菜单图像并进入抽屉的情况将保持在最低限度。但如果发生这种情况,抽屉将不会关闭,这比从鼠标下方关闭要好得多。

http://jsfiddle.net/elusien/PayFw/8/


编辑#4:

再次感谢Neil,这是相同代码的更高效版本...

http://jsfiddle.net/PayFw/ 9/

I'm trying to convert an existing menu system which is loaded with inline Javascript into new, more efficient, code using only jQuery.

I have a horizontal bar with rollover images. I have a hidden field in the page containing an integer value. When a page is loaded, the corresponding menu is loaded with a "sticky" version of the image and all other menu items swap images on mouse enter & leave. It was loaded with tons of inline Javascript and a monster Javascript file that was tedious to convert every time I created a new site.

I successfully converted this all to jQuery where I was also able to disable the click on the sticky menu item. Now I can simply set some variables and easily customize it per each site's design.

Working great...

Now comes a new issue. One design contains a bunch of sliding drawers under each menu image. The sliding animations are handled by an external JS file and the menu drawers themselves are each just a DIV containing the content nested inside a container DIV.

So then I wrote some simple stuff for jQuery that animates the DIV and slides it in and out on mouse hover for the menu images.

The problem is that I cannot seem to solve the problem of the mouse moving away from the menu image and down into the menu drawer without the drawer closing. I understand the "why?"... I am leaving the image which triggers the animation to close the drawer before I can get inside. If I apply the hover animations to the drawer container it simply creates a zone under the menu which also triggers the animation, and I don't want that either. It seems to be turning into a more complex problem with jQuery. All this was working fine with the inline Javascript... you could just move your mouse from the image into the adjacent open drawer without triggering the function to close it... as if the inline "mouse enter" for the drawer cancelled out the image's "mouse leave".

Any suggestions?

Thank-you!


EDIT:

I believe I solved this by using .stop(true, false) when passing from the image and into the drawer. This stops the animation dead before it even starts. Then the same when entering the image BEFORE initiating the normal animation... this has the effect of stopping the animation triggered by leaving the drawer and entering the image but also does nothing when just entering the image normally. More testing and then I'll post some sample code.


EDIT #2:

I have it working with "stop()" and "delay()" to control the animation but it's possible to freeze the opening of the drawer if you can get your mouse into it faster than it takes to open it. Installed with 150 ms. but right now set to 300 ms to exaggerate the problem.

Relevant code posted here...

jsfiddle.net/qPLVp/8/


EDIT #3:

Thanks to Neil, this is functioning very well now. With a quicker animation speed, the condition of a mouse overshooting the menu image and entering the drawer will be kept to a minimum. But if it happens to occur, the drawer will not close which is much better than it closing from under your mouse.

http://jsfiddle.net/elusien/PayFw/8/


EDIT #4:

Again thanks to Neil, this is a more efficient version of the same code...

http://jsfiddle.net/PayFw/9/

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

紅太極 2024-10-23 06:45:56

看起来您正在寻找 .delegate() 函数,它将一个处理程序附加到现在或将来的 DOM 事件:

$(".menuItem").delegate(".subMenu","hover", function(){ $(this).show(); });

您可以在此处阅读有关 .delegate() 函数及其伙伴 .live() 的更多信息:< a href="http://api.jquery.com/delegate/" rel="nofollow">http://api.jquery.com/delegate/

It seems like you're looking for the .delegate() function, which attaches a handler to a DOM event now or in the future:

$(".menuItem").delegate(".subMenu","hover", function(){ $(this).show(); });

You can read more about the .delegate() function and its buddy .live() here: http://api.jquery.com/delegate/

梦回旧景 2024-10-23 06:45:56

如果不看代码,很难知道以下代码是否有效:

hover() 将 2 个函数作为其参数,第一个函数在您输入图像时执行,第二个函数在您输入图像时执行。当你离开图像时。

您可能已设置第二个功能来隐藏(关闭)抽屉。我会在 hide() 之前添加一个小的延迟(例如 delay(100)),并在抽屉本身上设置一个悬停事件(在第一个函数参数中)停止动画队列 stop(true, true) - 这将停止抽屉被关闭,并在第二个函数中 - 退出抽屉时关闭抽屉。

Without seeing the code it is difficult to know if the following would work:

hover() takes as its arguments 2 functions, the first is executed when you enter the image, the second; when you leave the image.

You have presumably set the second function to hide (close) the drawer. I would add a small delay (e.g. delay(100)) before the hide() and set a hover event on the drawer itself to (in the first function argument) stop the animation queue stop(true, true) - this will stop the drawer being closed, and in the second function - close the drawer when you exit it.

清晨说晚安 2024-10-23 06:45:56

嘿,我在尝试完成同样的事情时偶然发现了这篇文章。我想我可能会放弃我的解决方案,因为现在已经是 2017 年了,.delegate 已被弃用,并且使用数据来跟踪转换是否仍然有效似乎很混乱。

关键是使用传递到 mouseleave 回调中的元素来获取 element.latedTarget

$('.myMouseoverElements').on('mouseover', function() {        

  activeElements = $('.elements.to.open')
  activeElements.addClass('open')

  activeElements.on('mouseleave', function(element) {

    var sustainElements = $('.elements.to.sustain.mouseover')
    var drawerShouldClose = !$(element.relatedTarget).is(sustainElements)

    if (drawerShouldClose) {
      activeElements.removeClass("open")
      activeElements.off("mouseleave")
    }
  })
})

感谢您的帮助!

Hey I stumbled on this post while trying to accomplish the same thing. Thought I might leave my solution because it's now 2017, .delegate was deprecated, and using data to keep track of whether or not a transition was still in effect seemed messy.

The key was using the element passed into the mouseleave callback to get the element.relatedTarget.

$('.myMouseoverElements').on('mouseover', function() {        

  activeElements = $('.elements.to.open')
  activeElements.addClass('open')

  activeElements.on('mouseleave', function(element) {

    var sustainElements = $('.elements.to.sustain.mouseover')
    var drawerShouldClose = !$(element.relatedTarget).is(sustainElements)

    if (drawerShouldClose) {
      activeElements.removeClass("open")
      activeElements.off("mouseleave")
    }
  })
})

Thanks for the help!

风渺 2024-10-23 06:45:55

我已经修改了您的 jsFiddle 代码以使其正常工作。基本上,我已将一个数据对象附加到您的 #menu 元素。当您打开此抽屉时,对象为{opening: true}。当抽屉完全打开(动画完成)时,该对象为{opening: false}。当你进入抽屉时我会检查这个,如果它是假的,我会停止动画。如果这是真的,我不会停止动画。

代码是:

    function enter(event) { // mouseenter IMG
        // removed image rollover code

        $('#menu').data({opening: true}).stop(true, false).animate({
            top: '0',
            opacity: 1
        },{
            duration: 300  // slow the opening of the drawer
        },
        function(){$(this).data({opening: false});}
        );
    };
    function leave(event) { // mouseout IMG
        // removed image rollover code

        $('#menu').delay(400).animate({
            top: '-'+$ht+'px',
            opacity: 0
        },{
            duration: 600
        });
    };

    $('#menu').hover(
        function (){ // mouseenter Menu drawer
            if (!$(this).data('opening')) {
                $(this).stop(true, false);
            }
        },
        function (){ // mouseout Menu drawer
            $(this).delay(400).animate({
                top: '-'+$ht+'px',
                opacity: 0
            },{
                duration: 600    
            });

       }
   );

现在可以正常工作了。鉴于此,您可能想重做一些“延迟”。

I've modified your jsFiddle code to make it work. Basically I have attached a data object to your #menu element. When you are opening this drawer the object is {opening: true}. When the drawer is fully open (animation completed) the object is {opening: false}. I check this when you enter the drawer and if it is false, I stop the animation. If it is true I do NOT stop the animation.

The code is:

    function enter(event) { // mouseenter IMG
        // removed image rollover code

        $('#menu').data({opening: true}).stop(true, false).animate({
            top: '0',
            opacity: 1
        },{
            duration: 300  // slow the opening of the drawer
        },
        function(){$(this).data({opening: false});}
        );
    };
    function leave(event) { // mouseout IMG
        // removed image rollover code

        $('#menu').delay(400).animate({
            top: '-'+$ht+'px',
            opacity: 0
        },{
            duration: 600
        });
    };

    $('#menu').hover(
        function (){ // mouseenter Menu drawer
            if (!$(this).data('opening')) {
                $(this).stop(true, false);
            }
        },
        function (){ // mouseout Menu drawer
            $(this).delay(400).animate({
                top: '-'+$ht+'px',
                opacity: 0
            },{
                duration: 600    
            });

       }
   );

This now works fine. You might want to redo some of your "delay"s in light of this.

放低过去 2024-10-23 06:45:55

Sparky,

我想出了一种不同的做事方式。基本上在“按钮”和“描述”上放置一个透明蒙版,并在其上使用“mouseleave”事件。

HTML:

<body>
<div id="Container" class="menuContainer" style="position: relative">
<div id="menumask"> </div>
<!-- this simulates the menu rollover image -->
<div id="menuitem" style="position:absolute; background-color:#ff00ff; top:10px; width:200px; height:50px; text-align:center;">
    <b>MENU ITEM</b>
</div>

<!-- this is the drawer -->
    <div id="menu" class="menuContent">
        <br/>
        <p>Content of the menu drawer.</p>
        <br/>
        <p>Bla bla bla </p>
        <br/>
        <p>Bla bla bla Bla.</p>
        <br/>
        <p>Bla bla bla Bla bla.</p>
        <br/>
        <p>Bla bla bla Bla bla bla Bla bla.</p>
    </div>

Javascript:

$(document).ready(function() {
    $('#menuitem').bind('mouseenter', enter);
    $('#menumask').bind('mouseleave', leave);

    $('#menu').css({
        height: '500px',
        position: 'absolute',
        paddingTop: '50px',
        width: '200px',
        backgroundColor: '#080',
        zIndex: -1
    }).hide();
    $('#menumask').css({
        height: '550px',
        width: '200px',
        opacity: 0.99,
        position: 'absolute',
        fontSize: '20000px',
        overflow: 'hidden',
        zIndex: 2
    }).hide();

    function enter(){
        $('#menumask').show();
        $('#menu').stop(true,true).animate({height: 500}, 'slow');
    };
    function leave(){
        $('#menumask').hide();
        $('#menu').stop(true,true).slideUp({height:   0}, 'slow');};  
});

您可以使用它作为菜单系统的基础。

问候
尼尔

Sparky,

I've come up with a different way of doing things. Basically putting a transparent mask over the "button" and "description" and using a "mouseleave" event on this.

HTML:

<body>
<div id="Container" class="menuContainer" style="position: relative">
<div id="menumask"> </div>
<!-- this simulates the menu rollover image -->
<div id="menuitem" style="position:absolute; background-color:#ff00ff; top:10px; width:200px; height:50px; text-align:center;">
    <b>MENU ITEM</b>
</div>

<!-- this is the drawer -->
    <div id="menu" class="menuContent">
        <br/>
        <p>Content of the menu drawer.</p>
        <br/>
        <p>Bla bla bla </p>
        <br/>
        <p>Bla bla bla Bla.</p>
        <br/>
        <p>Bla bla bla Bla bla.</p>
        <br/>
        <p>Bla bla bla Bla bla bla Bla bla.</p>
    </div>

Javascript:

$(document).ready(function() {
    $('#menuitem').bind('mouseenter', enter);
    $('#menumask').bind('mouseleave', leave);

    $('#menu').css({
        height: '500px',
        position: 'absolute',
        paddingTop: '50px',
        width: '200px',
        backgroundColor: '#080',
        zIndex: -1
    }).hide();
    $('#menumask').css({
        height: '550px',
        width: '200px',
        opacity: 0.99,
        position: 'absolute',
        fontSize: '20000px',
        overflow: 'hidden',
        zIndex: 2
    }).hide();

    function enter(){
        $('#menumask').show();
        $('#menu').stop(true,true).animate({height: 500}, 'slow');
    };
    function leave(){
        $('#menumask').hide();
        $('#menu').stop(true,true).slideUp({height:   0}, 'slow');};  
});

You could use this as the basis for your menu system.

Regards
Neil

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文