Как добиться эффекта mouseleave с абсолютно позиционируемого не потомки?

одна проблема со стандартным mouseout событие заключается в том, что оно срабатывает не только тогда, когда курсор покидает область экрана, ограниченную внешним периметром элемента, но и когда курсор парит над каким-либо другим элементом, содержащимся в этом периметре.

обоснование для jQuery mouseleave событие-это сигнал только момент, когда курсор покидает область, ограниченную внешним периметром элемента.

к сожалению, это, кажется, работать только в том случае, если" препятствующий "элемент является потомком" препятствующего " элемента. Если" препятствующий " элемент находится там, где он находится через абсолютное позиционирование, то когда мышь парит над ним,mouseleave событие на" препятствуют " элемент получает уволен.

например, со следующим HTML-кодом:

<div id="b-div">
    <div id="d-div"><span>d</span></div>
</div>
<div id="c-div"><span>c</span></div>

...#d-div является истинным потомком #b-div, а #c-div нет, но, но мы можем стиль его так, что он "мешает"#b-div все то же самое. Это проиллюстрировано в этой jsFiddle.

если теперь определить следующие события на #b-div:

$( '#b-div' ).bind( {
    mouseenter: function () {
        $( this ).addClass( 'outlined' );
    },
    mouseleave: function () {
        $( this ).removeClass( 'outlined' );
    }
} );

...затем наведите курсор мыши внутри #b-divвнешний периметр заставляет синий контур появляться по этому периметру,если мышь находится над #c-div.

есть ли способ, чтобы получить тот же эффект с #b-div и #c-div as mouseleave достигает #b-div и #d-div?

EDIT: у меня исправлена пример в jsFiddle. Первоначальный вариант этого примера показал непредставительный частный случай, когда все препятствующие элементы перекрываются с препятствующими элементами. В этом частном случае желаемый эффект может быть имитация определяя одни и те же события как на препятствующих, так и на препятствующих элементах, таким образом, по сути, превращая препятствующий элемент в пятно препятствующего элемента. Это не будет работать, когда препятствующий элемент не полностью содержится в пределах внешнего периметра заблокированного элемента (как показано в измененном jsFiddle). В более общем плане, любое решение, основанное на использовании mouseover событие на препятствующем элементе обязательно завершится неудачей, так как реальные проблема в том, чтобы предотвратить (или сделать неэффективным) ложное mouseleave на заблокированном элементе.

2 ответов


это делает это, основываясь на вашем первоначальном посте, в котором #c-div полностью содержался в #b-div:

$('#b-div, #c-div').on( {
  mouseenter: function (ev) {
    $('#b-div').addClass('outlined');
  },
  mouseleave: function (ev) {
    $('#b-div').removeClass('outlined');
  }
});

Скрипка 1


С #c-div не всегда может содержаться полностью в #b-div, вы можете использовать существующий код, если вы добавите этот стиль:
#c-div {
  pointer-events: none;
}

но это сделает невозможным взаимодействие с #c-div С помощью мыши.

Скрипка 2


если вы do необходимо взаимодействовать с #c-div, и это не полностью в #b-div, вы можете использовать элемент.getBoundingClientRect такой:

$('#b-div, #c-div').on('mousemove mouseleave',
  function(ev) {
    var br= $('#b-div')[0].getBoundingClientRect();
    $('#b-div').toggleClass(
      'outlined',
      ev.pageX > br.left && ev.pageX < br.left+br.width &&
      ev.pageY > br.top  && ev.pageY < br.top +br.height
    )
  }
);

Скрипка 3


если вы не можете использовать предложения Рича pointer-events: none (возможно, вам нужно поддержка IE 10 или вам нужно взаимодействовать с абсолютно позиционированных div-элемент), вы можете вручную проверить, что событие не будет #c-div используя relatedTarget.

однако, вы также должны проверить, что mouseleave от #c-div не будет #b-div.

$( '#b-div' ).bind( {
    mouseenter: function () {
        $( this ).addClass( 'outlined' );
    },
    mouseleave: function (e) {
        if (e.relatedTarget.id == 'c-div' ||  $.contains(document.getElementById('c-div'), e.relatedTarget)) {
            return;
        }
        $( this ).removeClass( 'outlined' );
    }
} );

$( '#c-div' ).bind( {
    mouseleave: function (e) {
        if (e.relatedTarget.id == 'b-div' ||  $.contains(document.getElementById('b-div'), e.relatedTarget)) {
            return;
        }
        $( '#b-div' ).removeClass( 'outlined' );
    }
});
#a-div {
    position: relative;
    margin: 20px;
}
#b-div {
    height: 100px;
    width: 100px;
    background-color: #555;
    padding: 50px;
}
#c-div {
    position: absolute;
    height: 50px;
    width: 200px;
    top: 100px;
    left: 100px;
    background-color: #999;
}
#d-div {
    height: 50px;
    width: 50px;
    background-color: #ddd;
    text-align: center;
}
#c-div span {
    margin: 21.5px;
    line-height: 50px;
}
#d-div span {
    margin: auto;
    line-height: 50px;
}
.outlined {
    outline: 10px solid steelblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a-div">
    <div id="b-div"><div id="d-div"><span>d</span></div></div>
    <div id="c-div"><span>c</span></div>
</div>