Предотвращение onmouseout при наведении на дочерний элемент родительского абсолютного div без jQuery
у меня проблемы с onmouseout
функция в абсолютном позиционном div. Когда мышь попадает в дочерний элемент в div, событие mouseout срабатывает, но я не хочу, чтобы он срабатывал, пока мышь не выйдет из родительского, абсолютного div.
Как я могу запретить mouseout
событие от запуска, когда оно попадает в дочерний элемент без jquery.
Я знаю, что это имеет какое-то отношение к пузырящемуся событию, но мне не повезло узнать, как это сделать.
Я нашел аналогичный пост здесь:Как отключить события mouseout, вызванные дочерними элементами?
однако это решение использует jQuery.
17 ответов
function onMouseOut(event) {
//this is the original element the event handler was assigned to
var e = event.toElement || event.relatedTarget;
if (e.parentNode == this || e == this) {
return;
}
alert('MouseOut');
// handle mouse event here!
}
document.getElementById('parent').addEventListener('mouseout',onMouseOut,true);
Я сделал быструю демонстрацию jsfiddle, со всеми необходимыми CSS и HTML, проверьте это...
редактировать исправлена ссылка для поддержки кросс-браузераhttp://jsfiddle.net/RH3tA/9/
Примечание что это проверяет только непосредственный родитель, если родительский div имел вложенных детей, то вы должны каким-то образом пройти через элементы родителей, ищущих "исходный элемент"
редактировать пример вложенных дети!--3-->
редактировать исправлено для кросс-браузера
function makeMouseOutFn(elem){
var list = traverseChildren(elem);
return function onMouseOut(event) {
var e = event.toElement || event.relatedTarget;
if (!!~list.indexOf(e)) {
return;
}
alert('MouseOut');
// handle mouse event here!
};
}
//using closure to cache all child elements
var parent = document.getElementById("parent");
parent.addEventListener('mouseout',makeMouseOutFn(parent),true);
//quick and dirty DFS children traversal,
function traverseChildren(elem){
var children = [];
var q = [];
q.push(elem);
while (q.length > 0) {
var elem = q.pop();
children.push(elem);
pushAll(elem.children);
}
function pushAll(elemArray){
for(var i=0; i < elemArray.length; i++) {
q.push(elemArray[i]);
}
}
return children;
}
и новая JSFiddle, редактировать обновили ссылку
для более простого чистого решения CSS это работает в некоторых случаях (IE11 или новее), можно удалить детей pointer-events
установив их в none
.parent * {
pointer-events: none;
}
использовать onmouseleave
.
или, в jQuery, используйте mouseleave()
это именно то, что вы ищете. Пример:
<div class="outer" onmouseleave="yourFunction()">
<div class="inner">
</div>
</div>
или, в jQuery:
$(".outer").mouseleave(function(){
//your code here
});
пример здесь.
вот более элегантное решение, основанное на том, что было ниже. это объясняет событие, пузырящееся из более чем одного уровня детей. Это также кросс-браузер вопросы.
function onMouseOut(this, event) {
//this is the original element the event handler was assigned to
var e = event.toElement || event.relatedTarget;
//check for all children levels (checking from bottom up)
while(e && e.parentNode && e.parentNode != window) {
if (e.parentNode == this|| e == this) {
if(e.preventDefault) e.preventDefault();
return false;
}
e = e.parentNode;
}
//Do something u need here
}
document.getElementById('parent').addEventListener('mouseout',onMouseOut,true);
Если вы используете jQuery, вы также можете использовать функцию "mouseleave", которая занимается всем этим для вас.
$('#thetargetdiv').mouseenter(do_something);
$('#thetargetdiv').mouseleave(do_something_else);
do_something будет срабатывать, когда мышь входит в thetargetdiv или любой из его детей, do_something_else будет срабатывать только тогда, когда мышь покидает thetargetdiv и любой из его детей.
благодаря Амджаду Масаду, который вдохновил меня.
У меня есть следующее решение, которое, кажется, работает в IE9, FF и Chrome, и код довольно короткий (без сложного закрытия и поперечных дочерних вещей):
DIV.onmouseout=function(e){
// check and loop relatedTarget.parentNode
// ignore event triggered mouse overing any child element or leaving itself
var obj=e.relatedTarget;
while(obj!=null){
if(obj==this){
return;
}
obj=obj.parentNode;
}
// now perform the actual action you want to do only when mouse is leaving the DIV
}
Я думаю Quirksmode имеет все ответы, которые вам нужны (различные браузеры пузырящееся поведение и mouseenter / mouseleave события), но я думаю, что самый распространенный вывод к этому событию пузырящийся беспорядок is использование фреймворка, такого как JQuery или Mootools (который имеет события мыши: mouseenter и mouseleave события, которые именно то, что вы интуитивно произойдет).
посмотрите, как они это делают, если хотите, сделайте он сам
или вы можете создать свой собственный "lean mean" версия Mootools только с частью события (и его зависимостями).
попробовать mouseleave()
пример :
<div id="parent" mouseleave="function">
<div id="child">
</div>
</div>
;)
Я нашел очень простое решение,
просто используйте событие onmouseleave= " myfunc ()", чем событие onmousout=" myfunc ()"
в моем коде это сработало!!
пример:
<html>
<head>
<script type="text/javascript">
function myFunc(){
document.getElementById('hide_div').style.display = 'none';
}
function ShowFunc(){
document.getElementById('hide_div').style.display = 'block';
}
</script>
</head>
<body>
<div onmouseleave="myFunc()" style='border:double;width:50%;height:50%;position:absolute;top:25%;left:25%;'>
Hover mouse here
<div id='child_div' style='border:solid;width:25%;height:25%;position:absolute;top:10%;left:10%;'>
CHILD <br/> It doesn't fires if you hover mouse over this child_div
</div>
</div>
<div id="hide_div" >TEXT</div>
<a href='#' onclick="ShowFunc()">Show "TEXT"</a>
</body>
</html>
тот же пример с функцией mouseout:
<html>
<head>
<script type="text/javascript">
function myFunc(){
document.getElementById('hide_div').style.display = 'none';
}
function ShowFunc(){
document.getElementById('hide_div').style.display = 'block';
}
</script>
</head>
<body>
<div onmouseout="myFunc()" style='border:double;width:50%;height:50%;position:absolute;top:25%;left:25%;'>
Hover mouse here
<div id='child_div' style='border:solid;width:25%;height:25%;position:absolute;top:10%;left:10%;'>
CHILD <br/> It fires if you hover mouse over this child_div
</div>
</div>
<div id="hide_div">TEXT</div>
<a href='#' onclick="ShowFunc()">Show "TEXT"</a>
</body>
</html>
надеюсь, что это помогает :)
есть два способа справиться с этим.
1) Проверьте событие.целевой результат в обратном вызове, чтобы увидеть, соответствует ли он вашему родительскому div
var g_ParentDiv;
function OnMouseOut(event) {
if (event.target != g_ParentDiv) {
return;
}
// handle mouse event here!
};
window.onload = function() {
g_ParentDiv = document.getElementById("parentdiv");
g_ParentDiv.onmouseout = OnMouseOut;
};
<div id="parentdiv">
<img src="childimage.jpg" id="childimg" />
</div>
2)или используйте захват события и вызов события.это происходит в функции обратного вызова
var g_ParentDiv;
function OnMouseOut(event) {
event.stopPropagation(); // don't let the event recurse into children
// handle mouse event here!
};
window.onload = function() {
g_ParentDiv = document.getElementById("parentdiv");
g_ParentDiv.addEventListener("mouseout", OnMouseOut, true); // pass true to enable event capturing so parent gets event callback before children
};
<div id="parentdiv">
<img src="childimage.jpg" id="childimg" />
</div>
Я заставляю его работать как шарм с этим:
function HideLayer(theEvent){
var MyDiv=document.getElementById('MyDiv');
if(MyDiv==(!theEvent?window.event:theEvent.target)){
MyDiv.style.display='none';
}
}
а, а MyDiv
тег выглядит так:
<div id="MyDiv" onmouseout="JavaScript: HideLayer(event);">
<!-- Here whatever divs, inputs, links, images, anything you want... -->
<div>
таким образом, при onmouseout идет к ребенку, внуку и т. д... the style.display='none'
не выполняется; но когда onmouseout выходит из MyDiv, он запускается.
поэтому нет необходимости останавливать распространение, использовать таймеры и т. д...
Спасибо за примеры, я могу сделать этот код из них.
надеюсь, это кому-то поможет.
также можно улучшить вот так:
function HideLayer(theLayer,theEvent){
if(theLayer==(!theEvent?window.event:theEvent.target)){
theLayer.style.display='none';
}
}
а затем DIVs теги, как это:
<div onmouseout="JavaScript: HideLayer(this,event);">
<!-- Here whatever divs, inputs, links, images, anything you want... -->
<div>
так что более общий, не только для одного div и не нужно добавлять id="..."
на каждый слой.
Я проверяю смещение исходного элемента, чтобы получить координаты страницы границ элемента, затем убедитесь, что действие mouseout запускается только тогда, когда mouseout выходит за эти границы. Грязно, но работает.
$(el).live('mouseout', function(event){
while(checkPosition(this, event)){
console.log("mouseovering including children")
}
console.log("moused out of the whole")
})
var checkPosition = function(el, event){
var position = $(el).offset()
var height = $(el).height()
var width = $(el).width()
if (event.pageY > position.top
|| event.pageY < (position.top + height)
|| event.pageX > position.left
|| event.pageX < (position.left + width)){
return true
}
}
var elem = $('#some-id');
elem.mouseover(function () {
// Some code here
}).mouseout(function (event) {
var e = event.toElement || event.relatedTarget;
if (elem.has(e).length > 0) return;
// Some code here
});
Если вы добавили (или имеете) класс CSS или id к родительскому элементу, то вы можете сделать что-то вроде этого:
<div id="parent">
<div>
</div>
</div>
JavaScript:
document.getElementById("parent").onmouseout = function(e) {
e = e ? e : window.event //For IE
if(e.target.id == "parent") {
//Do your stuff
}
}
поэтому материал выполняется только тогда, когда событие находится на родительском div.
Я просто хотел поделиться с тобой кое-чем.
Я получил некоторые трудные времена с ng-mouseenter
и ng-mouseleave
событий.
примеры:
Я создал плавающее меню навигации, которое переключается, когда курсор находится над значком.
Это меню было вверху каждой страницы.
- чтобы обработать Показать / Скрыть в меню, я переключаю класс.
ng-class="{down: vm.isHover}"
- для переключения vm.isHover, я использую ng событие мыши.
ng-mouseenter="vm.isHover = true"
ng-mouseleave="vm.isHover = false"
пока все было хорошо и работало, как ожидалось.
Решение чисто и просто.
входящие проблемы:
в определенном представлении у меня есть список элементов.
Я добавлена панель действий, когда курсор находится над элементом списка.
Я использовал тот же код, что и выше, для обработки поведения.
в проблема:
Я понял, когда мой курсор находится в плавающем меню навигации, а также в верхней части элемента, существует конфликт между собой.
Появилась панель действий, и плавающая навигация была скрыта.
дело в том, что даже если курсор находится над плавающим меню навигации, элемент списка ng-mouseenter запускается.
Для меня это не имеет смысла, потому что я ожидал бы автоматического разрыва распространения мыши события.
Должен сказать, что я был разочарован и потратил некоторое время, чтобы выяснить эту проблему.
первые мысли:
Я попытался использовать эти:
$event.stopPropagation()
$event.stopImmediatePropagation()
Я объединил много событий указателя ng (mousemove, mouveover,... но никто мне не поможет.
решение CSS:
Я нашел решение с простым свойством css, которое я использовать все больше и больше:
pointer-events: none;
в основном, я использую его так (в моих элементах списка):
ng-style="{'pointer-events': vm.isHover ? 'none' : ''}"
С помощью этого хитрого события ng-mouse больше не будут запускаться, и мое плавающее меню навигации больше не будет закрываться, когда курсор находится над ним и над элементом из списка.
пойти дальше:
как вы можете ожидать, это решение работает, но мне это не нравится.
Мы не контролируем наши события и это плохо.
Кроме того, у вас должен быть доступ к vm.isHover
область для достижения этого, и это может быть невозможно или возможно, но грязно так или иначе.
Я могу сделать скрипку, если кто-то захочет посмотреть.
тем не менее, у меня нет другого решения...
Это долгая история, и я не могу дать вам картошку, поэтому, пожалуйста, простите меня, мой друг.
Во всяком случае,pointer-events: none
это жизнь, так что запомните это.
если у вас есть доступ к элементу, к которому прикреплено событие внутри mouseout
метод, вы можете использовать contains()
чтобы увидеть, если event.relatedTarget
является дочерним элементом или нет.
As event.relatedTarget
- это элемент, в который перешла мышь, если это не дочерний элемент, вы вышли из элемента.
div.onmouseout = function (event) {
if (!div.contains(event.relatedTarget)) {
// moused out of div
}
}
хотя решение вы ссылались на использование jquery, события мыши: mouseenter и mouseleave являются родными событиями dom, поэтому вы можете использовать без jquery.