当容器有选择框时,jQuery mouseleave触发的问题

时间:2011-06-02 08:46:54

标签: javascript jquery

我有两个容器 - 一个嵌套在另一个容器内。当我将鼠标悬停在父级上方时,我希望显示子容器。当我使用mouseout时,我想让子容器淡出。我遇到的问题是子容器有一个包含“选择框”的表单。当用户选择选择框时 - 意外触发了mouseleave事件。

如何阻止选择框跳过mouseleave事件?

您可以在此处查看我的工作代码:http://jsfiddle.net/rsturim/9TZyh/3/

以下是我的脚本摘要:

$('#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();              
});

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

9 个答案:

答案 0 :(得分:12)

在大多数情况下,您应该只是能够检查事件目标是否是一个select元素,并且只有在它不是的情况下才能继续。似乎比公认的解决方案更清洁,并且在我的案例中运作良好。

我修改了小提琴: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();
    }
});

答案 1 :(得分:8)

$('#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();              
});

答案 2 :(得分:3)

由于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();   
    }
});

答案 3 :(得分:2)

我在一个我正在贡献的项目中遇到了同样的问题,而其他答案对我来说并不合适。我棘手的解决方案是检查事件对象内的鼠标位置是否在父容器内。效果还不错!

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();              
});

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

答案 4 :(得分:1)

这部分解决了这个问题。 当选择框获得焦点时取消绑定mouseleave事件,并在失去焦点时再次绑定。

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();
}

答案 5 :(得分:0)

那些家伙给你一个工作替代品,但它也有一些错误。例如,如果在组合框仍然打开时退出外框,它将不会淡出。我建议你一个更容易的替代方案,也将修复该bug。

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

显然,为了这个目的,内盒不应该是外盒的孩子,即使在视觉上看起来如此(可以用css定位来实现它)

答案 6 :(得分:0)

如果您不介意在某些旧浏览器中使用淡入淡出功能,您可以快速使用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;
}

答案 7 :(得分:0)

所以我遇到了一个类似的问题,其中<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');
                                    }

                            });
                    });

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

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

希望有所帮助。

答案 8 :(得分:0)

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

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

请参阅:jquery descendant

示例:

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