JQuery OLMADAN ana mutlak div öğesinin alt öğe üzerinde gezinirken aşırıya kaçmayı önleyin


169

Ben onmouseoutmutlak bir positon div div fonksiyonu ile sorun yaşıyorum . Fare div öğesinde bir alt öğeye çarptığında, fareyle ilgili olay tetiklenir, ancak fare ana öğeden, mutlak div'ın dışına çıkıncaya kadar ateş etmesini istemiyorum.

mouseoutEtkinliğin jquery OLMADAN bir alt öğeye çarptığında tetiklenmesini nasıl önleyebilirim .

Bunun olay köpürme ile bir ilgisi olduğunu biliyorum, ama bunu nasıl çözeceğimi bulmakta hiç şansım yok.

Burada benzer bir yazı buldum: Alt öğeler tarafından tetiklenen fare olayları nasıl devre dışı bırakılır?

Ancak bu çözüm jQuery kullanır.


Sorunu bir zaman aşımı kullanarak çözdüm ve alt öğelerin üzerine geldiğinde temizledim
John

Merhaba, demonuza baktım ama sağ alt paneldeki öğelerin üzerinden geçtiğimde hiçbir şey olmuyor mu?
John

1
Bir alt öğeyi fareyle üzerine getirdiğinizde üst etkinlikte bir fare kapanını önlemek istiyorsanız bu yanıtı buldunuz: javascript fare ile fare kapama / fare ile kapma .
user823527

Yanıtlar:


94
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);

Hızlı bir JsFiddle demosu yaptım, tüm CSS ve HTML gerekli, kontrol edin ...

Tarayıcılar arası destek için SABİT DÜZENLEME bağlantısı http://jsfiddle.net/RH3tA/9/

NOT üst div sonra çocukları iç içe olsaydı bu sadece kontroller hemen ebeveyn, siz "Orginal elemanı" arayan elemanlar ebeveynler aracılığıyla nasılsa çapraz zorunda

Yuvalanmış çocuklar için EDIT örneği

EDIT Umarım çapraz tarayıcılar için düzeltilmiştir

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

Ve yeni bir JSFiddle , EDIT güncellenmiş bağlantısı


1
Kemanın test edilebilmesi için bir fare kapama olayı eklemelisiniz. Bir uyarı falan yapmalı.
John

Üzgünüz uyarı var gibi görünüyor ('MouseOut'), ancak benim için çalışmıyor? JS kütüphanesi seçeneği olmadan koştum
John

Safari ve krom üzerinde test edildi, ancak her şey üzerinde çalışmalı! tarayıcınız nedir
Amjad Masad

2
Ya büyük çocuklarınız varsa? ya da büyük büyük çocuklar? yani sadece acil çocuklar yerine özyinelemeli bir çözüm olabilir mi?
Roozbeh15

20
Bu işe yaramıyor. mouseleavecevap nedir
Code Whisperer

126

Kullanın onmouseleave.

Veya jQuery'de şunu kullanın: mouseleave()

Tam aradığınız şey bu. Misal:

<div class="outer" onmouseleave="yourFunction()">
    <div class="inner">
    </div>
</div>

veya jQuery'de:

$(".outer").mouseleave(function(){
    //your code here
});

bir örnek burada .


3
onMouseLeaveBen kadar kabarcık değil gibi kullanarak sona erdi ne olduğunu.
Alecz

Bana çok zaman kazandırdı. thnx
npo

mouseleaveiptal edilemez.
grecdev

@grecdev, daha fazlasını söyle!
Ben Wheeler

98

Daha basit, saf CSS çözüm için bazı durumlarda (işleri IE11 veya daha yeni ), bir çocuk kaldırmak olabilir pointer-eventsonları ayarlayaraknone

.parent * {
     pointer-events: none;
}

4
Parlak! Tamamen sorunumu düzelttim!
Anna_MediaGirl

4
Bu birinci ya da en azından ikinci cevap olmalı, olay dinleyicilerinin güçlüğü ile başlamaya hazırdım ve bu da sorunumu tamamen düzeltti. Çok basit !
Mickael V.

9
Bu, farenin ateş etmesini önler, ancak benim için gerçek çocuğun menünün noktası olan menüde bir seçim olarak tıklanmasını da önler.
johnbakers

@hellofunk Bu nedenle tıklama etkinliğini üst öğeye uygularsınız. Gereken tam kod uygulamaya bağlı olarak değişir, bu cevap sadece pointer-eventsözelliği kullanmanızı önerir
Zach Saucier

1
yalnızca alanın içinde başka denetleyici öğeleriniz (düzenleme, silme) yoksa çalışır, çünkü bu çözüm onları da engeller.
Zoltán Süle

28

İşte aşağıda verilenlere dayanan daha zarif bir çözüm. birden fazla çocuk seviyesinden köpüren olayı açıklar. Ayrıca tarayıcılar arası sorunları da açıklar.

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

Sam Elie, bu IE, Safari veya Opera üzerinde çalışmıyor gibi görünüyor. Bu komut dosyasının çapraz tarayıcı sürümüne sahip misiniz? Firefox ve Chrome'da bir cazibe gibi çalışır. Teşekkürler.

1
Yukarıdaki işlevi komut dosyama yapıştırdığımda, Dreamweaver ve FF ilk satıra bir hata atar, "function onMouseOut (this, event) {". "This" i parametre olarak koymanıza izin verilmiyor gibi görünüyor. Giriş paramlarından "this" i bıraktığımda biraz işe yarıyor ama emin değilim, çünkü "Ne bilmediğimi bilmiyorum".
TARKUS

1
Aynı sorunu Chrome'da aynı thissatırda da açtım, @GregoryLewis işlev tanımı satırı hariç sorunu düzeltti. Ayrıca daha fazla tarayıcı desteği için şunu deneyin: if (window.addEventListener) {document.getElementById ('parent'). AddEventListener ('mouseout', onMouseOut, true); } else if (window.attachEvent) {document.getElementById ('parent'). attachEvent ("onmouseout", onMouseOut); }
DWils

Çok yakışıklı! Eski tarayıcılar için destek gerekiyorsa en iyi yanıt.
BurninLeo

13

Bana ilham veren Amjad Masad sayesinde.

IE9, FF ve Chrome'da çalışıyor gibi görünen aşağıdaki çözümü yaşadım ve kod oldukça kısadır (karmaşık kapatma ve enine alt öğeler olmadan):

    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
    }

13

aşırı kullanmak yerine aşırı kullanmak.

Bize özel kodunuzu göstermediniz, bu nedenle size nasıl yapılacağına ilişkin özel örneğinizi gösteremem.

Ama bu çok basit: sadece aşırıya kaçmak yerine onmouseleave değiştirin.

Hepsi bu kadar :) Çok basit :)

Nasıl yapılacağından emin değilseniz, aşağıdaki açıklamaya bakın:

https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onmousemove_leave_out

Pasta Barış :) Keyfini çıkarın :)


Bu harika bir bağırış, benzer bir durumunuz varsa kontrol etmeye değer
Chris

12

JQuery kullanıyorsanız, tüm bunlarla ilgilenen "mouseleave" işlevini de kullanabilirsiniz.

$('#thetargetdiv').mouseenter(do_something);
$('#thetargetdiv').mouseleave(do_something_else);

do_something fare fare thetargetdiv veya çocuklarından herhangi birine girdiğinde, do_something_else sadece fare thetargetdiv ve çocuklarından herhangi birini terk ettiğinde ateşlenir.


8

Bence Quirksmode tüm gerekmez cevapları (farklı tarayıcılar köpüren davranışı ve sahip MouseEnter / mouseLeave olaylar), ama bu olay fokurdayan karmaşa en yaygın sonuç, düşünmek olduğunu JQuery veya Mootools (var gibi bir çerçevenin kullanılması mouseenter ve mouseleave olayları, tam olarak sezdiğiniz şey olurdu).

Bunu yapmak, kendinizi İstersen onlar, bunu nasıl göz at
ya yapabilecekleriniz özel oluşturmak sadece olay parçası (ve bağımlılıkları) ile Mootools ait "yalın ortalama" versiyonunu.


7

Deneyin mouseleave()

Misal :

<div id="parent" mouseleave="function">
   <div id="child">

   </div>
</div>

;)


5

Çok basit bir çözüm buldum,

onmousout = "myfunc ()" olayından daha onmouseleave = "myfunc ()" olayını kullanmanız yeterlidir

Kodumda çalıştı !!

Misal:

<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>

Fare fonksiyonu ile aynı örnek:

<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>

Umarım yardımcı olur :)



2

Bunu ele almanın iki yolu vardır.

1) üst divinizle eşleşip eşleşmediğini görmek için geri aramadaki event.target sonucunu kontrol edin

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) Veya olay yakalama işlevini kullanın ve event.stop Callback işlevinde çağrı yapın

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>

Bu işi, aşırıya kaçmak yerine aşırıya kaçma için nasıl yapabilirim?
John

Hata. Benim hatam. Sadece yukarıdaki kodda "fare imleci" tüm "fare imleci" referansları değiştirmek. Bunu senin için yapmalı.
selbie

İlk yöntem için, event.target, fare alt öğenin üzerine geldiğinde her zaman üst öğeyle eşleşir, bu nedenle çalışmaz
John

Aynı şey ikinci yöntem için de geçerlidir. Fare bir alt öğeye girdiğinde olayı hala tetikler
John

1

Bu bir cazibe gibi çalışmasını sağlamak:

function HideLayer(theEvent){
 var MyDiv=document.getElementById('MyDiv');
 if(MyDiv==(!theEvent?window.event:theEvent.target)){
  MyDiv.style.display='none';
 }
}

Ah, ve MyDivetiket şöyle:

<div id="MyDiv" onmouseout="JavaScript: HideLayer(event);">
 <!-- Here whatever divs, inputs, links, images, anything you want... -->
<div>

Bu şekilde, muazzam bir çocuğa, büyük çocuğa vb. Gittiğinde ... style.display='none'idam edilmez; ama onmouseout MyDiv'den çıktığında çalışır.

Bu nedenle, yayılmayı durdurmaya, zamanlayıcıları kullanmaya vb.

Örnekler için teşekkürler, onlardan bu kodu yapabilir.

Umarım bu birine yardımcı olur.

Ayrıca şu şekilde geliştirilebilir:

function HideLayer(theLayer,theEvent){
 if(theLayer==(!theEvent?window.event:theEvent.target)){
  theLayer.style.display='none';
 }
}

Ve sonra DIV etiketleri şöyle:

<div onmouseout="JavaScript: HideLayer(this,event);">
 <!-- Here whatever divs, inputs, links, images, anything you want... -->
<div>

Çok daha genel, sadece bir div için değil id="...", her katmana eklemeye gerek yok .


1

Etkinliğin mouseoutyöntemin içine iliştirildiği öğeye erişiminiz contains()varsa, event.relatedTargetöğesinin alt öğe olup olmadığını görmek için kullanabilirsiniz .

Gibi event.relatedTargetbir alt öğe değilse fare, içine geçti hangi unsurdur, sen elemanın dışına moused var.

div.onmouseout = function (event) {
    if (!div.contains(event.relatedTarget)) {
        // moused out of div
    }
}

1

Açısal 5, 6 ve 7'de

<div (mouseout)="onMouseOut($event)"
     (mouseenter)="onMouseEnter($event)"></div>

Sonra

import {Component,Renderer2} from '@angular/core';
...
@Component({
 selector: 'app-test',
 templateUrl: './test.component.html',
 styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit, OnDestroy {
...
 public targetElement: HTMLElement;

 constructor(private _renderer: Renderer2) {
 }

 ngOnInit(): void {
 }

 ngOnDestroy(): void {
  //Maybe reset the targetElement
 }

 public onMouseEnter(event): void {
  this.targetElement = event.target || event.srcElement;
  console.log('Mouse Enter', this.targetElement);
 }

 public onMouseOut(event): void {
  const elementRelated = event.toElement || event.relatedTarget;
  if (this.targetElement.contains(elementRelated)) {
    return;
  }
  console.log('Mouse Out');
 }
}

0

Öğenin sınırlarının sayfa koordinatlarını almak için orijinal öğenin ofsetini kontrol ediyorum, ardından fare eyleminin yalnızca fare bu sınırların dışına çıktığında tetiklendiğinden emin olun. Kirli ama işe yarıyor.

$(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
}
}

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

Lütfen anwser'ınızla biraz açıklama yapın.
Sebass van Boxel

0

Üst öğeye bir CSS sınıfı veya kimliği eklediyseniz (veya eklediyseniz), bunun gibi bir şey yapabilirsiniz:

<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
  }
}

Bu nedenle, şeyler yalnızca etkinlik ana div üzerinde olduğunda yürütülür.


0

Sadece seninle bir şeyler paylaşmak istedim. Ve olaylarla
biraz zorlandım . ng-mouseenterng-mouseleave

Vaka çalışması:

İmleç bir simgenin üzerinde olduğunda geçiş yapan kayan bir gezinme menüsü oluşturdum.
Bu menü her sayfanın üstündeydi.

  • Menüde show / hide işlemek için bir sınıfı değiştiririm.
    ng-class="{down: vm.isHover}"
  • Vm.isHover öğesini değiştirmek için, ng fare olaylarını kullanıyorum.
    ng-mouseenter="vm.isHover = true"
    ng-mouseleave="vm.isHover = false"

Şimdilik, her şey iyiydi ve beklendiği gibi çalıştı.
Çözüm temiz ve basittir.

Gelen sorun:

Belirli bir görünümde, elemanların bir listesi var.
İmleç listenin bir öğesinin üzerindeyken bir eylem paneli ekledim.
Davranışı işlemek için yukarıdaki ile aynı kodu kullandım.

Sorun:

İmlecim kayan gezinme menüsünde ve ayrıca bir öğenin üstünde olduğunda, aralarında bir çakışma olduğunu anladım.
Eylem paneli belirdi ve kayan gezinme gizlendi.

Mesele imleç kayan gezinme menüsünün üzerinde olsa bile, ng-mouseenter liste öğesinin tetiklenmesidir.
Benim için hiçbir anlam ifade etmiyor, çünkü fare yayılma olaylarının otomatik olarak kesilmesini beklerdim.
Hayal kırıklığına uğradım ve bu sorunu bulmak için biraz zaman harcadığımı söylemeliyim.

İlk düşünceler:

Bunları kullanmaya çalıştım:

  • $event.stopPropagation()
  • $event.stopImmediatePropagation()

İşaretçi olaylarının birçoğunu birleştirdim (fareyle üzerine gelme, mouveover, ...) ama hiçbiri bana yardım etmedi.

CSS çözümü:

Çözümü daha fazla kullandığım basit bir css özelliği ile buldum:

pointer-events: none;

Temel olarak, (liste öğelerimde) şöyle kullanıyorum:

ng-style="{'pointer-events': vm.isHover ? 'none' : ''}"

Bu aldatıcı olayla, ng-fare olayları artık tetiklenmeyecek ve imleç üzerinde olduğunda ve listedeki bir öğenin üzerinde olduğunda kayan gezinme menüm artık kendini kapatmayacak.

Daha ileri gitmek için:

Tahmin edebileceğiniz gibi, bu çözüm işe yarıyor ama hoşuma gitmiyor.
Olaylarımızı kontrol etmiyoruz ve bu kötü.
Ayrıca, bunu vm.isHoverbaşarmak için kapsama erişiminiz olmalıdır ve bu mümkün veya mümkün olmayabilir, ancak bir şekilde kirli olabilir.
Birisi bakmak isterse keman yapabilirim.

Yine de, başka bir çözümüm yok ...
Uzun bir hikaye ve sana patates veremem bu yüzden lütfen beni affet arkadaşım.
Her neyse, pointer-events: nonehayat bu yüzden hatırla.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.