javascript 容器具有选择框时 jQuery mouseleave 触发的问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6212309/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 19:53:03  来源:igfitidea点击:

Problem with jQuery mouseleave firing when container has select box

javascriptjquery

提问by rsturim

I have a two containers -- one is nested inside of another. When I hover over the parent, I want the child container to appear. When I mouseout, I want the child container to fadeout. The problem I'm having is the child container has a form that contains a "select box". When the user selects the select box -- the mouseleave event is accidentally fired.

我有两个容器——一个嵌套在另一个容器中。当我将鼠标悬停在父容器上时,我希望出现子容器。当我鼠标移出时,我希望子容器淡出。我遇到的问题是子容器有一个包含“选择框”的表单。当用户选择选择框时—— mouseleave 事件被意外触发。

How can I stop the select box from tripping the mouseleave event?

如何阻止选择框触发 mouseleave 事件?

You can see my working code here: http://jsfiddle.net/rsturim/9TZyh/3/

你可以在这里看到我的工作代码:http: //jsfiddle.net/rsturim/9TZyh/3/

Here's a summary of my script:

这是我的脚本的摘要:

$('#parent-container').live("mouseenter", function () {
    var $this = $(this),
    $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave", function (e) {
    var $this = $(this),
    $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().hide();              
});

edit: appears fine in WebKit-based browsers. Fails in Firefox and IE7-IE9.

编辑:在基于 WebKit 的浏览器中显示正常。在 Firefox 和 IE7-IE9 中失败。

采纳答案by bjornd

Since mouseleave and mouseenter events are non-standard you can get such lags here and there. The only method I can suggest to fix that is using some hacks. Here is http://jsfiddle.net/mPDcu/1/improved version of you code.

由于 mouseleave 和 mouseenter 事件是非标准的,因此您可能会到处出现这种滞后。我可以建议修复的唯一方法是使用一些技巧。这是您代码的http://jsfiddle.net/mPDcu/1/改进版本。

var selectOpened = false;
$('#select-grind-type').click(function(e){
    selectOpened = !selectOpened;
    e.stopPropagation();
});
$('body').click(function(){
    if (selectOpened) {
        selectOpened = false;
    }
})
$('#parent-container').on("mouseenter", function() {
    var $this = $(this),
        $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave", function(e) {
    if (!selectOpened) {
        var $this = $(this),
            $selectOptionsContainer = $this.find('#child-container');
        $selectOptionsContainer.stop().hide();   
    }
});

回答by Dygerati

In most cases you should simply be able to check to see if the event target was a select element, and only continue in the case that it wasn't. Seems much cleaner than the accepted solution, and worked well in my case.

在大多数情况下,您应该能够简单地检查事件目标是否是 select 元素,并且只有在不是的情况下才继续。似乎比公认的解决方案更干净,并且在我的情况下效果很好。

I've modified the fiddle: http://jsfiddle.net/Dygerati/uj3ZC/5/

我修改了小提琴:http: //jsfiddle.net/Dygerati/uj3ZC/5/

$('#parent-container').live("mouseenter", function() {
    var $this = $(this),
        $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave", function(e) {
    if(e.target.tagName.toLowerCase() != "select") {
        var $this = $(this),
            $selectOptionsContainer = $this.find('#child-container');
        $selectOptionsContainer.stop().hide();
    }
});

回答by Paulo Alexandre Borges Miranda

$('#parent-container').live("mouseenter", function () {
    var $this = $(this),
    $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave", function (e) {

    /* Solution */
    if(e.relatedTarget == null) return;
    /************/

    var $this = $(this),
    $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().hide();              
});

回答by juallom

I had the same problem in a project in which I am contributing, and the other answers didn't work fine for me. My tricky solution was to check if the mouse position inside the event object is inside the parent container. Works pretty good!

我在我参与的一个项目中遇到了同样的问题,其他答案对我来说不起作用。我的棘手解决方案是检查事件对象内的鼠标位置是否在父容器内。效果很好!

var layer = $('#parent-container'),
    layerPos = {};
$(layer).mouseenter(function () {
    var $this = $(this),
    $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().fadeTo('slow', 1.0, function(){
        layerPos.x = {
            min: $(layer).offset().left,
            max: $(layer).offset().left + $(layer).width()
        };
        layerPos.y = {
            min: $(layer).offset().top,
            max: $(layer).offset().top + $(layer).height()
        };
    });
})
$(layer).mouseleave(function(e) {
    // check if event mouse position is inside parent container
    var x_con = e.pageX >= layerPos.x.min && e.pageX <= layerPos.x.max;
    var y_con = e.pageY >= layerPos.y.min && e.pageY <= layerPos.y.max;
    if ( x_con && y_con ) {
        return false;
    }

    var $this = $(this),
    $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().hide();              
});

You can also check the navigator version to avoid this code to execute in browsers that support this functionality like Chrome.

您还可以检查导航器版本,以避免在支持此功能的浏览器(如 Chrome)中执行此代码。

回答by Jishnu A P

This partly solves the problem. Unbind the mouseleaveevent when the select box gains focus and bind again when it loses focus.

这部分解决了问题。mouseleave选择框获得焦点时解除绑定事件,失去焦点时再次绑定。

http://jsfiddle.net/9TZyh/5/

http://jsfiddle.net/9TZyh/5/

$('#parent-container').live("mouseenter", function() {
    var $this = $(this);
    $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().fadeTo('slow', 1.0);
}).live("mouseleave",focusOut);
$("#select-grind-type").live("focus",function(){
    $('#parent-container').die("mouseleave");
});
$("#select-grind-type").live("focusout change",function(){
    $('#parent-container').live("mouseleave",focusOut);
});
function focusOut(e) {
    var $this = $(this),
        $selectOptionsContainer = $this.find('#child-container');
    $selectOptionsContainer.stop().hide();
}

回答by ChangePictureWeekly

Those guys give you a working alternative, but it also has some bugs. For example, if you quit the outer box while the combobox is still opened, it won't fade out. I recommend you a much easier alternative that will also fix that bug.

这些家伙为您提供了一个可行的替代方案,但它也有一些错误。例如,如果在组合框仍处于打开状态时退出外框,则它不会淡出。我向您推荐一个更简单的替代方案,它也将修复该错误。

Instead of thinking in the mouseleave event of the inner box, why don't you swap your mind to think in the other way around? I mean, leaving the inner box, also means entering in another container. So you can do outerContainer.mouseenter(function(){ hideInnerBox() });:-)

与其考虑内盒的 mouseleave 事件,为什么不换个思路换个思路呢?我的意思是,离开内盒,也意味着进入另一个容器。所以你可以这样做outerContainer.mouseenter(function(){ hideInnerBox() });:-)

Obviously for that purpose innerbox should not be a child of outerbox, even if visually it seems so (css positioning can be used to achieve it)

显然为此目的,innerbox 不应该是outerbox 的孩子,即使在视觉上看起来是这样(css 定位可以用来实现它)

回答by Roberto

If you don't mind having the fade not working in some old browsers, you could do it with CSS quickly:

如果您不介意淡入淡出在某些旧浏览器中不起作用,您可以使用 CSS 快速实现:

#parent-container {  }
#child-container {
    opacity:0;
    -webkit-transition:opacity 1s ease-in;
       -moz-transition:opacity 1s ease-in;
}
#parent-container:hover #child-container {{
    opacity:1;
    -webkit-transition:opacity 1s ease-out;
       -moz-transition:opacity 1s ease-out;
}

回答by a.m.

So I just ran into a similar issue with a <select>nested in a container and came across this question. Here's what I ended up doing.

所以我刚刚遇到了一个类似的问题,<select>嵌套在容器中并遇到了这个问题。这就是我最终要做的。

               $("#container").mouseover(function(e){
                            var t = $(this);
                            t.addClass('active');
                            var offset = t.offset();
                            var xMin = offset.left;
                            var yMin = offset.top;
                            var xMax = xMin + t.innerWidth();
                            var yMax = yMin + t.innerHeight();

                            t.parent().mousemove(function(e){
                                    if(e.pageX < xMin || e.pageX > xMax-2 || e.pageY < yMin || e.pageY > yMax ){
                                            t.removeClass('active');
                                            // unbind this event
                                            $(this).unbind('mousemove');
                                    }

                            });
                    });

Basically, when you mouseover the container, we collect its bounds and start checking whether or not the mouse is over the element. When we know the mouse is gone, we unbind the mousemovelistener.

基本上,当您将鼠标悬停在容器上时,我们会收集其边界并开始检查鼠标是否位于元素上方。当我们知道鼠标消失了,我们就解除了mousemove监听器的绑定。

I'd make a jsfiddle for you but its running so slow today!

我会为你制作一个 jsfiddle,但它今天的运行速度太慢了!

Hope that helps.

希望有帮助。

回答by Heinz Georg Spengler

You should only check if the current Element is a descendant of your container.

您应该只检查当前 Element 是否是您的容器的后代。

If so abort the handler.

如果是这样,则中止处理程序。

See: jquery descendant

见:jquery后代

Example:

例子:

ContainerElement.mouseleave(function (e) {
if (ContainerElement.has(e.fromElement).length > 0) return;
// Do your Stuff
});