簡體   English   中英

DOM-同步事件的計時與setTimeout

[英]DOM - timing of simultaneous events vs setTimeout

假設我有一個包含多個子元素的元素,並且想在鼠標進入或離開容器時運行一些代碼。 如果我天真地寫:

var onHover = function (el, f) {
    el.addEventListener('mouseover', function () {
        f(true);
    });
    el.addEventListener('mouseout', function () {
        f(false);
    });
};

然后,在某些情況下,我將獲得所需的行為-取決於回調f的性質。 但是,當鼠標容器中從一個子對象移到另一個子對象時, f(false)立即運行,后跟f(true) 我不希望發生這種情況-我只希望f在鼠標整體進入或離開容器時運行,而不是稱為機槍風格,因為用戶將鼠標拖動到容器內部的元素上。

這是我想出的解決方案:

var onHover = function (el, f) {
    var previousMouseover = false;
    var receivedMouseover = false;
    var pushing = false;
    var pushEv = function () {
        if (pushing) { return; }
        pushing = true;
        setTimeout(function () {
            pushing = false;
            if (previousMouseover !== receivedMouseover) {
                f(receivedMouseover);
                previousMouseover = receivedMouseover;
            }
        });
    };
    el.addEventListener('mouseover', function () {
        receivedMouseover = true;
        pushEv();
    });
    el.addEventListener('mouseout', function () {
        receivedMouseover = false;
        pushEv();
    });
};

與第一個解決方案一樣,該解決方案通過在mouseover事件發生之前發送mouseout事件來假定並起作用。 我也想知道是否是正式通過任何W3C文件規定,但不是這個問題的話題,甚至如果不是的話,它會很容易通過設置寫功能的算法,盡管該兩個獨立的變量,說receivedMouseoverreceivedMouseout所述的內部mouseovermouseout回調,這兩者都是則的內部檢查setTimeout回調。

問題是:是否需要在運行由任何一個事件注冊的任何setTimeout回調之前都處理mouseovermouseout事件?

使用mouseentermouseleave事件,而不是mouseovermouseout事件。

由於您已將事件偵聽器附加到父元素,因此可以在執行操作之前將事件來源( event.target )與父元素( thisevent.currentTarget )進行比較。 您可以執行以下操作;

var onHover = function (el, f) {
    el.addEventListener('mouseover', function (evt) {
        this === evt.target && f(true);
    });
    el.addEventListener('mouseout', function (evt) {
        this === evt.target && f(false);
    });
};

大多數元素都會冒泡,因此在某些時候這可能是完成此工作的正確方法。

編輯:如注釋中所述,在某些情況下,例如,當父元素未定義填充或邊距且子元素覆蓋所有父元素時, mouseovermouseout事件可能會出現問題。 即使沒有,鼠標的速度也可能足夠快,以致JS引擎無法在父元素上對鼠標進行采樣。 這個事實在本文中得到了很好的解釋

因此,如接受的答案中所述,我想使用mouseentermouseleave事件可以解決此問題。 因此正確的代碼應該像;

var onHover = function (el, f) {
    el.addEventListener('mouseenter', () => f(true));
    el.addEventListener('mouseleave', () => f(false));
};

編輯2:好吧...實際上,在這種特定情況下,有一種使用mouseovermouseout的安全方法。 這是關於在子級上使用CSS pointer-events屬性,該屬性使它們無法為鼠標活動發出事件。

 var container = document.getElementById('container'); container.addEventListener('mouseover', function (ev) { console.log(container === ev.target); }); container.addEventListener('mouseout', function (ev) { console.log(container === ev.target); }); 
 #container * { pointer-events: none } 
 <div id="container"> <div> <span>text</span> </div> </div> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM