Ngăn chặn onmouseout khi di chuột vào phần tử con của div cha tuyệt đối KHÔNG CÓ jQuery


169

Tôi đang gặp rắc rối với onmouseoutchức năng trong một div được tích cực tuyệt đối. Khi chuột chạm vào một phần tử con trong div, sự kiện mouseout sẽ kích hoạt, nhưng tôi không muốn nó kích hoạt cho đến khi chuột hết cha mẹ, div tuyệt đối.

Làm cách nào tôi có thể ngăn mouseoutsự kiện này phát sinh khi nó đánh vào một phần tử con KHÔNG CÓ jquery.

Tôi biết điều này có liên quan đến bong bóng sự kiện, nhưng tôi không gặp may mắn trong việc tìm ra cách giải quyết vấn đề này.

Tôi tìm thấy một bài tương tự ở đây: Làm thế nào để vô hiệu hóa các sự kiện mouseout được kích hoạt bởi các phần tử con?

Tuy nhiên, giải pháp đó sử dụng jQuery.


Cuối cùng tôi đã giải quyết vấn đề bằng cách sử dụng thời gian chờ và xóa nó khi di chuột qua các phần tử con
John

Xin chào, tôi đã xem bản demo của bạn nhưng khi tôi xem qua các yếu tố ở bảng dưới cùng bên phải thì không có gì xảy ra?
Giăng

1
Đã tìm thấy câu trả lời này nếu bạn đang tìm cách ngăn chặn việc di chuột vào sự kiện chính khi bạn di chuột qua một phần tử con: rê chuột / chuột javascript .
user823527

1
Kiểm tra câu trả lời
@Zach

Câu trả lời:


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

Tôi đã thực hiện bản demo JsFiddle nhanh chóng, với tất cả CSS và HTML cần thiết, hãy xem thử ...

Liên kết EDIT FIXED để hỗ trợ nhiều trình duyệt http://jsfiddle.net/RH3tA/9/

LƯU Ý rằng điều này chỉ kiểm tra cha mẹ ngay lập tức, nếu div cha mẹ đã có con cái lồng nhau thì bạn phải bằng cách nào đó đi qua các yếu tố mà cha mẹ đang tìm kiếm "phần tử Orginal"

Ví dụ EDIT cho trẻ lồng nhau

EDIT Đã sửa lỗi với hy vọng trình duyệt chéo

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

Và một liên kết cập nhật EDFiddle , EDIT mới


1
Bạn nên thêm một sự kiện mouseout vào fiddle để nó có thể được kiểm tra. Một cảnh báo hoặc một cái gì đó nên làm.
John

Xin lỗi có vẻ như bạn đã cảnh giác ('MouseOut'), tuy nhiên nó không hoạt động với tôi? Tôi đã nhấn run mà không có tùy chọn thư viện JS
John

Đã thử nghiệm trên safari và chrome, nhưng nên hoạt động trên mọi thứ! trình duyệt của bạn là gì
Amjad Masad

2
Nếu bạn có con lớn thì sao? hay cháu lớn? tức là bạn có thể có một giải pháp đệ quy thay vì chỉ đắm đuối trẻ em?
Roozbeh15

20
Điều này không hoạt động. mouseleavelà câu trả lời đúng
Code Whisperer

126

Sử dụng onmouseleave .

Hoặc, trong jQuery, sử dụng mouseleave()

Đây là điều chính xác mà bạn đang tìm kiếm. Thí dụ:

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

hoặc, trong jQuery:

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

một ví dụ là ở đây .


3
onMouseLeavelà những gì tôi đã kết thúc bằng cách sử dụng vì nó không nổi bong bóng.
Alecz

Tiết kiệm cho tôi rất nhiều thời gian. thnx
npo

mouseleavekhông thể hủy bỏ.
grecdev

@grecdev, nói thêm!
Ben Wheeler

97

Đối với một giải pháp CSS thuần túy đơn giản hơn , hoạt động trong một số trường hợp ( IE11 hoặc mới hơn ), người ta có thể loại bỏ trẻ em pointer-eventsbằng cách đặt chúng thànhnone

.parent * {
     pointer-events: none;
}

4
Xuất sắc! Hoàn toàn chỉ sửa vấn đề của tôi!
Anna_MediaGirl

4
Đây phải là câu trả lời đầu tiên hoặc ít nhất là thứ hai, tôi đã sẵn sàng gặp rắc rối với người nghe sự kiện và điều này cũng hoàn toàn khắc phục vấn đề của tôi. Quá đơn giản !
Mickael V.

9
Điều này ngăn không cho chuột bắn ra, nhưng đối với tôi nó cũng ngăn đứa trẻ thực sự được nhấp vào như một lựa chọn trong menu, đó là điểm của menu.
johnbakers 17/05/2015

@hellofunk Đó là lý do tại sao bạn áp dụng sự kiện nhấp chuột cho phụ huynh. Mã chính xác cần thiết khác nhau tùy thuộc vào việc triển khai, câu trả lời này chỉ gợi ý sử dụng thuộc pointer-eventstính
Zach Saucier

1
nó chỉ hoạt động nếu bạn không có các thành phần điều khiển khác (chỉnh sửa, xóa) trong khu vực, bởi vì giải pháp này cũng chặn chúng ..
Zoltán Süle

28

Đây là một giải pháp thanh lịch hơn dựa trên những gì dưới đây. nó chiếm sự kiện nổi lên từ hơn một cấp độ của trẻ em. Nó cũng chiếm các vấn đề trên nhiều trình duyệt.

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, điều này dường như không hoạt động trên IE, Safari hoặc Opera. Bạn có phiên bản trình duyệt chéo của tập lệnh này không? Nó hoạt động như một nét quyến rũ trong Firefox và Chrome. Cảm ơn.

1
Khi tôi dán chức năng trên vào tập lệnh của mình, Dreamweaver và FF sẽ xuất hiện lỗi trên dòng đầu tiên, "function onMouseOut (this, event) {". Có vẻ như bạn không được phép đặt "cái này" làm tham số. Tôi đoán nó là loại công việc khi tôi bỏ "cái này" khỏi các thông số đầu vào, nhưng tôi không biết chắc chắn, vì "Tôi không biết những gì tôi không biết".
TARKUS

1
Tôi cũng gặp vấn đề tương tự trong Chrome trên cùng một dòng, ngoại trừ thisdòng định nghĩa chức năng @GregoryLewis đã đề cập đã khắc phục sự cố. Ngoài ra để có thêm hỗ trợ trình duyệt chéo, hãy thử điều này: if (window.addEventListener) {document.getEuityById ('Parent'). AddEventListener ('mouseout', onMouseOut, true); } if if (window.attachEvent) {document.getEuityById ('Parent'). AttachEvent ("onmouseout", onMouseOut); }
DWils

Rất đẹp trai! Câu trả lời tốt nhất nếu cần hỗ trợ cho các trình duyệt cũ hơn.
BurninLeo

13

Cảm ơn Amjad Masad đã truyền cảm hứng cho tôi.

Tôi đã có giải pháp sau đây dường như hoạt động trong IE9, FF và Chrome và mã này khá ngắn (không có sự đóng cửa phức tạp và những thứ con ngang):

    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

thay vì onmouseout sử dụng onmouseleave.

Bạn đã không chỉ cho chúng tôi mã cụ thể của bạn để tôi không thể chỉ cho bạn về ví dụ cụ thể của bạn về cách thực hiện.

Nhưng nó rất đơn giản: chỉ cần thay thế onmouseout bằng onmouseleave.

Đó là tất cả :) Vì vậy, đơn giản :)

Nếu không chắc chắn cách thực hiện, hãy xem giải thích về:

https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onmousemove_leave thừng

Yên tâm của bánh :) Thưởng thức nó :)


Đây là một tiếng hét tuyệt vời, rất đáng để kiểm tra nếu bạn có một tình huống tương tự
Chris

12

Nếu bạn đang sử dụng jQuery, bạn cũng có thể sử dụng hàm "mouseleave", giải quyết tất cả những điều này cho bạn.

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

do_s Something sẽ kích hoạt khi chuột vào thetargetdiv hoặc bất kỳ con nào của nó, do_s Something_else sẽ chỉ bắn khi chuột rời thetargetdiv và bất kỳ con nào của nó.


8

Tôi nghĩ Quirksmode có tất cả các câu trả lời bạn cần (hành vi sủi bọt của các trình duyệt khác nhau và các sự kiện mouseenter / mouseleave ), nhưng tôi nghĩ rằng kết luận phổ biến nhất cho sự lộn xộn bong bóng sự kiện đó sử dụng một khung như JQuery hoặc Mootools (có mouseenter và sự kiện mouseleave , đó chính xác là những gì bạn trực giác sẽ xảy ra).

Hãy xem cách họ làm điều đó, nếu bạn muốn, tự làm
hoặc bạn có thể tạo phiên bản Mootools tùy chỉnh "nạc" chỉ với phần sự kiện (và phần phụ thuộc của nó).


7

Thử mouseleave()

Thí dụ :

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

   </div>
</div>

;)


5

Tôi đã tìm thấy một giải pháp rất đơn giản,

chỉ sử dụng sự kiện onmouseleave = "myfunc ()" hơn sự kiện onmousout = "myfunc ()"

Trong mã của tôi, nó hoạt động !!

Thí dụ:

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

Ví dụ tương tự với chức năng 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>

Hy vọng nó giúp :)



2

Có hai cách để xử lý việc này.

1) Kiểm tra kết quả event.target trong cuộc gọi lại của bạn để xem liệu nó có khớp với div cha của bạn không

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) Hoặc sử dụng ghi sự kiện và gọi event.stopPropagation trong chức năng gọi lại

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>

Làm thế nào tôi có thể thực hiện công việc này cho onmouseout thay vì onmouseover?
John

Giáo sư. Lỗi của tôi. Tôi chỉ thay đổi tất cả các tham chiếu "mouseover" thành "mouseout" trong đoạn mã trên. Chuyện đó nên làm vì bạn.
selbie

Đối với phương thức đầu tiên, event.target luôn khớp với phần tử cha khi chuột đi qua phần tử con, vì vậy nó không hoạt động
John

Điều tương tự xảy ra cho phương pháp thứ hai. Khi chuột vào một phần tử con, nó vẫn kích hoạt sự kiện
John

1

Tôi làm cho nó hoạt động như một cơ duyên với điều này:

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

À, và MyDivthẻ là như thế này:

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

Theo cách này, khi onmouseout đi đến một đứa trẻ, một đứa trẻ, v.v ... style.display='none' thì không được thực thi; nhưng khi onmouseout đi ra khỏi MyDiv thì nó chạy.

Vì vậy, không cần phải ngừng nhân giống, sử dụng bộ hẹn giờ, v.v ...

Cảm ơn ví dụ, tôi có thể tạo mã này từ họ.

Hy vọng điều này sẽ giúp được ai đó.

Cũng có thể được cải thiện như thế này:

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

Và sau đó các thẻ DIV như thế này:

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

Vì vậy, tổng quát hơn, không chỉ cho một div và không cần thêm id="..."vào mỗi lớp.


1

Nếu bạn có quyền truy cập vào phần tử mà sự kiện được gắn vào bên trong mouseoutphương thức, bạn có thể sử dụng contains()để xem event.relatedTargetphần tử đó có phải là phần tử con hay không.

event.relatedTargetphần tử mà chuột truyền vào, nếu đó không phải là phần tử con, bạn đã loại bỏ phần tử đó.

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

1

Trên góc 5, 6 và 7

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

Sau đó

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

Tôi kiểm tra phần bù của phần tử ban đầu để lấy tọa độ trang của giới hạn của phần tử, sau đó đảm bảo rằng hành động rê chuột chỉ được kích hoạt khi rớt chuột ra khỏi giới hạn đó. Bẩn nhưng nó hoạt động.

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

Xin vui lòng cho một số lời giải thích với anwser của bạn.
Sabass van Boxel

0

Nếu bạn đã thêm (hoặc có) một lớp CSS hoặc id vào phần tử cha, thì bạn có thể làm một cái gì đó như thế này:

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

Vì vậy, công cụ chỉ được thực hiện khi sự kiện nằm trên div cha.


0

Tôi chỉ muốn chia sẻ một cái gì đó với bạn.
Tôi có một số thời gian khó khăn với ng-mouseenterng-mouseleavecác sự kiện.

Nghiên cứu trường hợp:

Tôi đã tạo một menu điều hướng nổi, chuyển đổi khi con trỏ ở trên một biểu tượng.
Menu này ở trên cùng của mỗi trang.

  • Để xử lý chương trình / ẩn trên menu, tôi chuyển một lớp.
    ng-class="{down: vm.isHover}"
  • Để chuyển đổi vm.isHover , tôi sử dụng các sự kiện chuột ng.
    ng-mouseenter="vm.isHover = true"
    ng-mouseleave="vm.isHover = false"

Hiện tại, mọi thứ đều ổn và hoạt động như mong đợi.
Giải pháp là sạch sẽ và đơn giản.

Vấn đề đến:

Trong một cái nhìn cụ thể, tôi có một danh sách các yếu tố.
Tôi đã thêm một bảng điều khiển hành động khi con trỏ ở trên một phần tử của danh sách.
Tôi đã sử dụng mã giống như trên để xử lý hành vi.

Vấn đề:

Tôi đã tìm ra khi con trỏ của tôi ở trên menu điều hướng nổi và cũng ở trên cùng của một phần tử, có một xung đột giữa nhau.
Bảng điều khiển hành động xuất hiện và điều hướng nổi được ẩn.

Vấn đề là ngay cả khi con trỏ ở trên menu điều hướng nổi, phần tử danh sách ng-mouseenter được kích hoạt.
Nó không có ý nghĩa với tôi, bởi vì tôi sẽ mong đợi một sự phá vỡ tự động của các sự kiện lan truyền chuột.
Tôi phải nói rằng tôi đã thất vọng và tôi dành thời gian để tìm hiểu vấn đề đó.

Suy nghĩ đầu tiên:

Tôi đã thử sử dụng những thứ này:

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

Tôi đã kết hợp rất nhiều sự kiện con trỏ ng (mousemove, mouveover, ...) nhưng không có gì giúp tôi.

Giải pháp CSS:

Tôi tìm thấy giải pháp với một thuộc tính css đơn giản mà tôi sử dụng ngày càng nhiều:

pointer-events: none;

Về cơ bản, tôi sử dụng nó như thế (trên các yếu tố danh sách của tôi):

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

Với thủ thuật phức tạp này, các sự kiện ng-mouse sẽ không còn được kích hoạt và menu điều hướng nổi của tôi sẽ không còn tự đóng khi con trỏ ở trên nó và trên một phần tử trong danh sách.

Để đi xa hơn:

Như bạn có thể mong đợi, giải pháp này hoạt động nhưng tôi không thích nó.
Chúng tôi không kiểm soát các sự kiện của mình và điều đó thật tệ.
Thêm vào đó, bạn phải có quyền truy cập vào vm.isHoverphạm vi để đạt được điều đó và nó có thể không thể hoặc có thể nhưng bẩn theo cách này hay cách khác.
Tôi có thể làm cho một fiddle nếu ai đó muốn nhìn.

Tuy nhiên, tôi không có giải pháp nào khác ...
Đó là một câu chuyện dài và tôi không thể cho bạn một củ khoai tây vì vậy xin hãy tha thứ cho tôi, bạn của tôi.
Dù sao, pointer-events: nonelà cuộc sống, vì vậy hãy nhớ nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.