ฉันจะตรวจจับได้อย่างไรเมื่อเมาส์ออกจากหน้าต่าง


103

ฉันต้องการตรวจจับเมื่อเมาส์ออกจากหน้าต่างเพื่อที่ฉันจะได้หยุดเหตุการณ์ต่างๆไม่ให้เริ่มทำงานในขณะที่เมาส์ของผู้ใช้อยู่ที่อื่น

มีความคิดอย่างไรในการทำสิ่งนี้?


1
ลองดูห้องสมุด github ของ beeker exit-Intent มันยอดเยี่ยมมาก github.com/beeker1121/exit-intent-popup
raksheetbhat

ใช้mouseleaveเพื่อป้องกันการยิงในทุกองค์ประกอบตามที่mouseoutทำ: คำอธิบายและการสนับสนุนที่ดีมาก: developer.mozilla.org/en-US/docs/Web/API/Element/…

ตั้งค่าเหตุการณ์บนเอกสาร - ไม่ใช่ document.body เพื่อป้องกันแถบเลื่อนไฟ abowe แถบเลื่อนของ Windows ดูเหมือนจะหดตัว

คำตอบ:


100

โปรดทราบว่าคำตอบของฉันมีอายุมากแล้ว

โดยปกติแล้วพฤติกรรมประเภทนี้เป็นที่ต้องการในขณะที่ใช้ลักษณะการลากวางบนหน้า html โซลูชันด้านล่างได้รับการทดสอบบน IE 8.0.6, FireFox 3.6.6, Opera 10.53 และ Safari 4 บนเครื่อง MS Windows XP
ฟังก์ชั่นเล็ก ๆ น้อย ๆ จาก Peter-Paul Koch ก่อน; ตัวจัดการเหตุการณ์ข้ามเบราว์เซอร์:

function addEvent(obj, evt, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(evt, fn, false);
    }
    else if (obj.attachEvent) {
        obj.attachEvent("on" + evt, fn);
    }
}

จากนั้นใช้วิธีนี้เพื่อแนบตัวจัดการเหตุการณ์กับเหตุการณ์ mouseout วัตถุเอกสาร:

addEvent(document, "mouseout", function(e) {
    e = e ? e : window.event;
    var from = e.relatedTarget || e.toElement;
    if (!from || from.nodeName == "HTML") {
        // stop your drag event here
        // for now we can just use an alert
        alert("left window");
    }
});

สุดท้ายนี่คือหน้า html ที่มีสคริปต์ฝังอยู่สำหรับการดีบัก:

<html>
<head>
<script type="text/javascript">
function addEvent(obj, evt, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(evt, fn, false);
    }
    else if (obj.attachEvent) {
        obj.attachEvent("on" + evt, fn);
    }
}
addEvent(window,"load",function(e) {
    addEvent(document, "mouseout", function(e) {
        e = e ? e : window.event;
        var from = e.relatedTarget || e.toElement;
        if (!from || from.nodeName == "HTML") {
            // stop your drag event here
            // for now we can just use an alert
            alert("left window");
        }
    });
});
</script>
</head>
<body></body>
</html>

การใช้ window.event แก้ไขปัญหาของฉันในการรับเหตุการณ์นี้ ขอบคุณ!
Jay

ดูเหมือนว่าจะไม่ทำงานเมื่อไม่ได้กดเมาส์ใน chrome มันจะเริ่มทำงานเมื่อกดเมาส์ในโครเมี่ยม ดูเหมือนพฤติกรรมที่ไม่สอดคล้องกัน
antony.trupe

5
จะไม่ได้ผลหากองค์ประกอบ HTML อื่น ๆ เต็มหน้าต่าง
Emmanuel

ปัญหาในการแก้ปัญหานี้คือมันจะแจ้งเตือนหน้าต่างด้านซ้ายแม้ว่าผู้ใช้จะพยายามใช้ scroller ก็ตาม ฉันเผยแพร่วิธีแก้ปัญหานี้ที่นี่แล้ว แต่ยังมีปัญหาหนึ่งที่ต้องแก้ไข (ดูลิงค์)
JohnyFree

1
ใช้mouseleaveแทนการวางเมาส์เพื่อป้องกันไม่ให้ไฟไหม้องค์ประกอบในเอกสาร คำอธิบายดีมากและใช้งานได้บน IE5.5 ... developer.mozilla.org/en-US/docs/Web/API/Element/…

43

ถ้าคุณใช้ jQuery แล้วโค้ดสั้น ๆ น่ารัก ๆ -

$(document).mouseleave(function () {
    console.log('out');
});

เหตุการณ์นี้จะเริ่มทำงานเมื่อใดก็ตามที่เมาส์ไม่อยู่ในหน้าของคุณตามที่คุณต้องการ เพียงแค่เปลี่ยนฟังก์ชั่นเพื่อทำอะไรก็ได้ที่คุณต้องการ

และคุณยังสามารถใช้:

$(document).mouseenter(function () {
    console.log('in');
});

เพื่อทริกเกอร์เมื่อเมาส์กลับเข้าสู่หน้าอีกครั้ง

ที่มา: https://stackoverflow.com/a/16029966/895724


mouseleave ใช้งานได้ แต่จะเริ่มทำงานเช่นกันหากเปิดองค์ประกอบการตรวจสอบจะป้องกันได้อย่างไร ไอเดีย?
Pankaj Verma

เทคนิคนี้ไม่เสถียรใน Chrome 15 ถึง 56 (เวอร์ชันปัจจุบันของฉัน) แต่มันทำงานได้ดีมากใน Firefox ดู: stackoverflow.com/questions/7448468/…
Tremours

mouseleave ดูเหมือนจะยิงได้มากกว่าที่ควรจะเป็น
Alexander

นอกจากนี้ยังจะเริ่มทำงานหากหน้าต่างอยู่ในพื้นหลัง (เบราว์เซอร์ไม่เน้น) และเมาส์เข้าสู่หน้าต่าง (Chrome 61 / macOS10.11)
CodeBrauer

1
@Skeets (และผู้อ่านในอนาคต) ปัญหานี้ได้รับการแก้ไขแล้วเมื่อ 14 ก.พ. 2019
Xandor

27

สิ่งนี้ใช้ได้กับฉัน:

addEvent(document, 'mouseout', function(evt) {
  if (evt.toElement == null && evt.relatedTarget == null) {
    alert("left window");
  }
});

9
คืออะไรaddEvent?
Yi Jiang

5
เป็นฟังก์ชันที่กำหนดไว้ในคำตอบของ Joshua Mills
superjos

4
บน ie8, relatedTarget ไม่ได้กำหนดใน ie9 + และ firefox, toElement ไม่ได้กำหนด เนื่องจากการประเมินที่ถูกต้องคือ: if ((evt.relatedTarget === null) || (evt.toElement === null)) {
carlos

1
คำกริยาอาจจะกระชับมากขึ้นเช่นif (!evt.toElement && !evt.relatedTarget)
Pavel Ye

20

ในการตรวจจับการปล่อยเมาส์โดยไม่คำนึงถึงแถบเลื่อนและฟิลด์เติมข้อความอัตโนมัติหรือตรวจสอบ:

document.addEventListener("mouseleave", function(event){

  if(event.clientY <= 0 || event.clientX <= 0 || (event.clientX >= window.innerWidth || event.clientY >= window.innerHeight))
  {

     console.log("I'm out");

  }
});

คำอธิบายเงื่อนไข:

event.clientY <= 0  is when the mouse leave from the top
event.clientX <= 0  is when the mouse leave from the left
event.clientX >= window.innerWidth is when the mouse leave from the right
event.clientY >= window.innerHeight is when the mouse leave from the bottom

======================== แก้ไข ========================= ======

document.addEventListener ("mouseleave") ดูเหมือนว่าจะไม่ทำงานใน Firefox เวอร์ชันใหม่จำเป็นต้องแนบ mouseleave เข้ากับองค์ประกอบเช่น body หรือองค์ประกอบย่อย

ผมแนะนำให้ใช้แทน

document.body.addEventListener("mouseleave")

หรือ

window.addEventListener("mouseout")

ไม่ยิงเป็นครั้งคราว ตะเข็บเหมือนจะล้มเหลวเมื่อสตรีมจุดจุดหนึ่งถูกกระตุ้นโดยเคอร์เซอร์ย้ายเส้นจุดมุ่งหมายและเคอร์เซอร์จะปรับขนาด
Ivan Borshchov

@ user3479125 คุณช่วยลองใช้กับข้อมูลโค้ดของฉันด้วยและดูว่าปัญหายังคงอยู่หรือไม่เมื่อไม่ได้เพิ่ม if-statement มันคำนึงถึงแถบเลื่อน แต่ฉันไม่ได้ทดสอบด้วยการเติมข้อความอัตโนมัติหรือตรวจสอบ stackoverflow.com/a/56678357/985399

7

การใช้เหตุการณ์ onMouseLeave ช่วยป้องกันการเกิดฟองและช่วยให้คุณตรวจจับได้ง่ายเมื่อเมาส์ออกจากหน้าต่างเบราว์เซอร์

<html onmouseleave="alert('You left!')"></html>

http://www.w3schools.com/jsref/event_onmouseleave.asp


สุดยอด! การสนับสนุนคือ IE5.5 + ... ใช้งานได้ด้วย: document.onmouseleave = function() { alert('You left!') };ใช้ไม่ใช่ document.body ที่ยิงแถบเลื่อน abowe ที่หดตัว! ไม่จำเป็นต้องใช้รหัสป้องกันไฟในองค์ประกอบ คำอธิบายดีๆ: developer.mozilla.org/en-US/docs/Web/API/Element/…

6

คำตอบเหล่านี้ไม่ได้ผลสำหรับฉัน ตอนนี้ฉันใช้:

document.addEventListener('dragleave', function(e){

    var top = e.pageY;
    var right = document.body.clientWidth - e.pageX;
    var bottom = document.body.clientHeight - e.pageY;
    var left = e.pageX;

    if(top < 10 || right < 20 || bottom < 10 || left < 10){
        console.log('Mouse has moved out of window');
    }

});

ฉันใช้สิ่งนี้สำหรับวิดเจ็ตการอัปโหลดไฟล์แบบลากแล้ววาง มันไม่ถูกต้องอย่างแท้จริงโดยจะถูกเรียกใช้เมื่อเมาส์อยู่ในระยะที่กำหนดจากขอบหน้าต่าง


ฉันเชื่อว่าบางครั้งสิ่งนี้จะไม่เกิดขึ้นหากการเคลื่อนไหวของเมาส์ "เร็วพอ"
John Weisz

@JohnWeisz ใช่ฉันคิดว่าคุณพูดถูก ฉันใช้สคริปต์นี้มาระยะหนึ่งแล้วและมันก็ใช้ได้ดี
Emmanuel

6

ฉันได้ลองทำทุกอย่างข้างต้นแล้ว แต่ดูเหมือนจะไม่มีอะไรเป็นไปตามที่คาด หลังจากการวิจัยน้อยฉันพบว่าe.relatedTargetเป็นHTMLเพียงก่อนเมาส์ออกจากหน้าต่าง

ดังนั้น ... ฉันจบลงด้วยสิ่งนี้:


document.body.addEventListener('mouseout', function(e) {
    if (e.relatedTarget === document.querySelector('html')) {
        console.log('We\'re OUT !');
    }
});

โปรดแจ้งให้เราทราบหากคุณพบปัญหาหรือการปรับปรุงใด ๆ !

อัปเดต 2019

(ตามที่ user1084282 ค้นพบ)

document.body.addEventListener('mouseout', function(e) {
    if (!e.relatedTarget && !e.toElement) {
        console.log('We\'re OUT !');
    }
});

2
ไม่ทำงานสำหรับฉันใน Chrome relatedTargetเป็นโมฆะเมื่อเมาส์ออกจากหน้าต่าง แรงบันดาลใจจากคำตอบของ @ user1084282 เปลี่ยนเป็นสิ่งนี้if(!e.relatedTarget && !e.toElement) { ... }และใช้งานได้

ฉันยืนยันว่าสิ่งนี้ใช้งานได้ดีบน Chrome, Firefox และ IE Edge หากคุณใช้if(!e.relatedTarget && !e.toElement)แทนเงื่อนไขในคำตอบจริง ตรวจพบว่าเมาส์ออกจากเนื้อเอกสาร
Haijerome

ห้ามมีเหตุการณ์บน document.body เนื่องจากแถบเลื่อนของหน้าต่างอาจหดตัวและทำให้เลื่อนไปข้างหน้า แล้วทำไมคุณถึงมี 'mouseout' ที่จะยิงทุกองค์ประกอบที่เป็นฟองในเมื่อคุณมี 'mouseleave' ได้? developer.mozilla.org/en-US/docs/Web/API/Element/…

2

ฉันเอาสิ่งที่ฉันพูดกลับไป มันเป็นไปได้. ฉันเขียนโค้ดนี้ทำงานได้อย่างสมบูรณ์

window.onload = function() {

    $span = document.getElementById('text');

    window.onmouseout = function() {
        $span.innerHTML = "mouse out";  
    }

    window.onmousemove = function() {
        $span.innerHTML = "mouse in";   
    }

}

ทำงานใน chrome, firefox, opera ไม่ได้ทดสอบใน IE แต่คิดว่ามันใช้งานได้

แก้ไข. IE มักทำให้เกิดปัญหา เพื่อให้ทำงานใน IE ให้แทนที่เหตุการณ์จากหน้าต่างเป็นเอกสาร:

window.onload = function() {

    $span = document.getElementById('text');

    document.onmousemove = function() {
        $span.innerHTML = "mouse move";
    }

    document.onmouseout = function() {
        $span.innerHTML = "mouse out";
    }

}

รวมเข้าด้วยกันสำหรับ crossbrowser kick ass cursor detection o0: P


คุณได้ทดสอบว่าสิ่งนี้ทำงานร่วมกับองค์ประกอบบนหน้าได้ดีเพียงใด ฉันคิดว่าองค์ประกอบที่มีเหตุการณ์ 'onmouseover / out' ของตัวเองอาจยกเลิกการเป็นฟองและทำลายฟังก์ชันนี้ได้
Dan Herbert

1
Ozzy Dan พยายามอธิบายว่าองค์ประกอบที่หยุดการแพร่กระจายของเหตุการณ์จะป้องกันไม่ให้เหตุการณ์ไปถึงเอกสาร / หน้าต่างจึงทำให้โซลูชันของคุณไม่ได้ผล
James

ฉันเพิ่งทดสอบกับองค์ประกอบอื่น ๆ ด้วยเหตุการณ์ onmousemove และ onmouseout ของตัวเองและมันก็ยังใช้งานได้ดี
Ozzy

2
ใช่ตกลง แต่เรากำลังพูดถึงการเผยแพร่เหตุการณ์อีกครั้ง หากคุณตั้งใจหยุดการเผยแพร่เหตุการณ์ด้วย EVENT.stopPropagation () (สำหรับ IE, EVENT.cancelBubble = true) มันจะไม่เกิดขึ้นที่เอกสาร / หน้าต่าง ... ในการต่อต้านสิ่งนี้คุณสามารถใช้การบันทึกเหตุการณ์ในเบราว์เซอร์ที่รองรับ .
James

โปรดจำไว้ว่าใน JS เพื่อประกาศตัวแปรคุณต้องใช้ 'var' ตอนนี้ตัวแปร $ span เป็น global โดยนัยซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ นอกจากนี้ในกรณีที่ไม่ได้ตั้งใจคุณไม่จำเป็นต้องมี $ ในชื่อตัวแปร
Jani Hartikainen

2

ใช้ css นี้:

html
{
height:100%;
}

เพื่อให้แน่ใจว่าองค์ประกอบ html จะใช้ความสูงทั้งหมดของหน้าต่าง

ใช้ jquery นี้:

$("html").mouseleave(function(){
 alert('mouse out');
});

ปัญหาเกี่ยวกับการวางเมาส์เหนือและการวางเมาส์คือถ้าคุณวางเมาส์เหนือ / ออกจาก html ไปยังองค์ประกอบลูกก็จะปิดเหตุการณ์นั้น ฟังก์ชั่นที่ฉันให้จะไม่ถูกปิดเมื่อวางเมาส์ไว้ที่องค์ประกอบลูก จะถูกตั้งค่าไว้เมื่อคุณเลื่อนเมาส์ออก / ออกจากหน้าต่างเท่านั้น

เพียงเพื่อให้คุณรู้ว่าคุณสามารถทำได้เมื่อผู้ใช้ mouses ในหน้าต่าง:

$("html").mouseenter(function(){
  alert('mouse enter');
});

2
โดย "ฉันไม่เชื่อว่า javascript มีฟังก์ชันเทียบเท่า" คุณหมายความว่าคุณไม่รู้ว่า jQuery เป็นไลบรารีฟังก์ชันจาวาสคริปต์และ jQuery นั้นเขียนด้วยและสำหรับจาวาสคริปต์หรือไม่
Milche Patern

2
@MilchePatern ฉันเขียนคำตอบนี้เมื่อเกือบสองปีที่แล้ว ในตอนนั้นฉันไม่รู้มากกว่านี้และฉันไม่ได้ตระหนักถึงความจริงที่ว่าสิ่งที่ทำใน jQuery สามารถทำได้ใน JavaScript บริสุทธิ์ ฉันจะปรับปรุงคำตอบ ...
www139

2

ฉันลองทำทีละคำและพบคำตอบที่ดีที่สุดในเวลานั้น:

https://stackoverflow.com/a/3187524/985399

ฉันข้ามเบราว์เซอร์เก่าดังนั้นฉันจึงทำให้โค้ดสั้นลงเพื่อให้ทำงานบนเบราว์เซอร์สมัยใหม่ (IE9 +)

    document.addEventListener("mouseout", function(e) {
        let t = e.relatedTarget || e.toElement;
        if (!t || t.nodeName == "HTML") {
          console.log("left window");
        }
    });

document.write("<br><br>PROBLEM<br><br><div>Mouseout trigg on HTML elements</div>")

ที่นี่คุณจะเห็นการสนับสนุนเบราว์เซอร์

นั่นค่อนข้างสั้นที่ฉันคิด

แต่ปัญหายังคงอยู่เพราะ"mouseout" Trigg ในองค์ประกอบทั้งหมดในเอกสาร

เพื่อป้องกันไม่ให้เกิดขึ้นให้ใช้mouseleave (IE5.5 +) ดูคำอธิบายดีๆในลิงค์

โค้ดต่อไปนี้ใช้งานได้โดยไม่ต้องทริกเกอร์องค์ประกอบภายในองค์ประกอบให้อยู่ภายในหรือภายนอก ลองลากปล่อยนอกเอกสารด้วย

var x = 0

document.addEventListener("mouseleave", function(e) { console.log(x++) 
})

document.write("<br><br>SOLUTION<br><br><div>Mouseleave do not trigg on HTML elements</div>")

คุณสามารถตั้งค่าเหตุการณ์ในองค์ประกอบ HTML ใดก็ได้ อย่าเปิดเหตุการณ์ไว้document.bodyเนื่องจากแถบเลื่อนของหน้าต่างอาจหดตัวและเริ่มทำงานเมื่อตัวชี้เมาส์อยู่ชิดแถบเลื่อนเมื่อคุณต้องการเลื่อน แต่ไม่ต้องการเรียกใช้เมาส์ทิ้งเหตุการณ์ไว้เหนือมัน ตั้งค่าdocumentแทนดังในตัวอย่าง


1

บางทีถ้าคุณฟัง OnMouseOver ในแท็ก body อยู่ตลอดเวลาให้โทรกลับเมื่อเหตุการณ์ไม่เกิดขึ้น แต่ในขณะที่ Zack ระบุสิ่งนี้อาจน่าเกลียดมากเพราะไม่ใช่ทุกเบราว์เซอร์ที่จัดการเหตุการณ์ในลักษณะเดียวกันมีแม้แต่บางตัว ความเป็นไปได้ที่คุณจะสูญเสีย MouseOver แม้จะอยู่เหนือ div ในหน้าเดียวกัน


ไม่ใช่คำตอบ

1

บางทีนี่อาจจะช่วยบางคนที่มาที่นี่ในภายหลัง window.onblurและdocument.mouseout.

window.onblur ถูกทริกเกอร์เมื่อ:

  • คุณเปลี่ยนไปใช้หน้าต่างอื่นโดยใช้Ctrl+TabหรือCmd+Tabหรือ
  • คุณโฟกัส (ไม่ใช่แค่วางเมาส์เหนือ) บนตัวตรวจสอบเอกสาร
  • คุณสลับเดสก์ท็อป

โดยทั่วไปทุกเวลาที่แท็บเบราว์เซอร์สูญเสียโฟกัส

window.onblur = function(){
    console.log("Focus Out!")
}

document.mouseout ถูกทริกเกอร์เมื่อ:

  • คุณเลื่อนเคอร์เซอร์ไปที่แถบชื่อเรื่อง
  • คุณสลับไปยังหน้าต่างอื่นใช้หรือCtrl+TabCmd+Tab
  • คุณเปิดเลื่อนเคอร์เซอร์ไปที่ตัวตรวจสอบเอกสาร

โดยทั่วไปไม่ว่าในกรณีใด ๆ เมื่อเคอร์เซอร์ของคุณออกจากเอกสาร

document.onmouseleave = function(){
    console.log("Mouse Out!")
}

"ในทุกเวลาที่แท็บเบราว์เซอร์สูญเสียโฟกัส" .. ด้วย IE เวอร์ชันเก่าเหตุการณ์ 'เบลอ' จะถูกคอมไพล์โดย DOM เมื่อ / หลังจากที่องค์ประกอบอื่นได้รับโฟกัสสำหรับ gooChrome ก็คือเมื่อองค์ประกอบนั้นสูญเสียโฟกัส .. เพียงแค่พูดถึง
Milche Patern

ใช้สมาร์ทwindow.onblurเกินไป +1
โปรแกรม

1
$(window).mouseleave(function(event) {
  if (event.toElement == null) {
    //Do something
  }
})

อาจจะแฮ็คนิดหน่อย แต่จะเริ่มทำงานเมื่อเมาส์ออกจากหน้าต่างเท่านั้น ฉันจับเหตุการณ์เด็ก ๆ มาเรื่อย ๆ และสิ่งนี้ก็แก้ไขได้



1

สิ่งนี้ได้ผลสำหรับฉัน รวมคำตอบบางส่วนไว้ที่นี่ และฉันใส่รหัสที่แสดงโมเดลเพียงครั้งเดียว และโมเดลจะหายไปเมื่อคลิกที่อื่น

<script>
    var leave = 0
    //show modal when mouse off of page
    $("html").mouseleave(function() {
       //check for first time
       if (leave < 1) {
          modal.style.display = "block";
          leave = leave + 1;
       }
    });

    // Get the modal with id="id01"
       var modal = document.getElementById('id01');

    // When the user clicks anywhere outside of the modal, close it
       window.onclick = function(event) {
          if (event.target == modal) {
             modal.style.display = "none";
          }
       }
</script>

ไม่มีแท็ก jQuery ในคำถาม
mrReiha

jQuery เป็นโค้ดจำนวนมากเมื่อเทียบกับคำตอบของฉันที่ทำงานบนเบราว์เซอร์สมัยใหม่ IE9 + และส่วนที่เหลือ เป็นไปตามคำตอบนี้ แต่สั้นกว่ามาก: stackoverflow.com/a/3187524/985399

1

ดูและmouseovermouseout

var demo = document.getElementById('demo');
document.addEventListener("mouseout", function(e){demo.innerHTML="😞";});
document.addEventListener("mouseover", function(e){demo.innerHTML="😊";});
div { font-size:80vmin; position:absolute;
      left:50%; top:50%; transform:translate(-50%,-50%); }
<div id='demo'>😐</div>


0

ฉันยังไม่ได้ทดสอบ แต่สัญชาตญาณของฉันคือการเรียกใช้ฟังก์ชัน OnMouseOut บนแท็กร่างกาย


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.