記一次多事件綁定中自己給自己設置的坑——click,dblclick,mousedown,mousemove,mouseup

項目綜述

  • 在頁面中模擬某作業系統的操作介面,提供應用窗口的最大化、最小化、還原等功能

需求

  • 對一個應用窗口標題欄雙擊使其鋪滿整個視口,再次雙擊還原到原來大小,和位置
  • 部分程式碼片段如下:
win.addEventListener('dblclick', (event) => {
    if (cache && cache.status === 'normal') {
        Win.maximize(id);
    } else if (cache && cache.status === 'maximize') {
        Win.restore(id);
    }
});
  • 在Win.restore()和Win.maximize()方法中通過id讀取該應用的快取資訊
{
    top: app.cache.pos.top,
    left: app.cache.pos.left,
    width: app.size.width,
    height: app.size.height,
}

問題

  • Chrome瀏覽器(87)

    • 使用電腦自帶觸摸板進行雙擊測試,正常
    • 使用滑鼠進行雙擊測試,雙擊事件觸發後cache.pos內的內容丟失,top和left屬性不存在,cache中其餘屬性正常
  • Edge瀏覽器(87)

    • 表現與Chrome瀏覽器一致
  • Firefox瀏覽器(84)

    • 在使用電腦自帶觸摸板和滑鼠測試時,雙擊事件觸發後均出現cache.pos內的內容丟失的情況,其餘屬性正常

猜想

  • 對象嵌套深度問題???畢竟嵌套最深的丟了,其他的都沒事
// 將left和top直接定義在cache,表現與之前測試結果一致,修改無效
{
    top: app.cache.top,
    left: app.cache.left,
    width: app.size.width,
    height: app.size.height,
}
  • 命名衝突問題???
// 將屬性名加上前綴,表現與之前測試結果一致,修改無效
{
    top: app.cache.winTop,
    left: app.cache.winLeft,
    width: app.size.width,
    height: app.size.height,
}
  • 事件衝突問題,該元素同時定義了單擊事件,但注釋掉單擊事件後問題依舊存在

  • 雙擊事件的BUG????????

// 使用單擊事件模擬雙擊事件,在Google和Edge中使用觸摸板最大化和還原也會造成數據丟失了
function doubleclick(elem, onsingle, ondouble) {
    if (dblFlag) {
        dblFlag = true;
        setTimeout(function () {
            if (dblFlag) {
                onsingle(elem);
            }
            dblFlag = false;
        }, 300);
    } else {
        dblFlag = false;
        ondouble(elem);
    }
}

解決

  • 就在我已經快要放棄這個功能的時候,發現這個元素還綁定了另外一個事件

  • 為了讓窗口可以在頁面中自由拖動,加入了mousedown,mousemove,mouseup事件模擬拖拽事件,提前聲明變數currentLeft和currentTop,在mousemove時修改兩個屬性的值,在mouseup時保存當前位置,如下程式碼:

window.onmouseup = function () {
    window.onmousemove = null;
    app.cache.pos.left = currentLeft;
    app.cache.pos.top = currentTop;

    return false;
}
  • 在雙擊事件中連續觸發了mouseup和mousedown,所以給top和left寫入了新值

但是,雙擊事件並沒有觸發到mousemove事件,導致currentLeft和currentTop沒有值寫入,還是初始的未賦值狀態,並將undefined寫入了快取,也就是cache.pos內屬性丟失的問題

  • 知道了問題就好解決了,加一個判空就行了
window.onmouseup = function () {
    window.onmousemove = null;
    app.cache.pos.left = currentLeft || app.cache.pos.left;
    app.cache.pos.top = currentTop || app.cache.pos.top;

    return false;
}
  • 至於使用觸摸板和使用滑鼠導致差異,大概是用滑鼠手比較穩,雙擊不會出現位置移動,而觸摸板兩次點擊很難都點中同一位置,或多或少有差異,觸發mousemove寫入了新值
  • 不同瀏覽器的不同表現,大概是對雙擊事件中兩次點擊的誤差範圍規定不同,改用了單擊事件模擬雙擊事件後,瀏覽器的表現就一致了

反思

  • 能給初始值就給初始值,不能給初始值在使用的時候一定要給默認值!
  • 別瞎想,看看自己的猜想,連邊都沒有摸到,在用單擊事件模擬雙擊時就應該聯想到其餘的事件,然後檢查是否相互影響
  • 就自己目前的水平,所有的問題都一定是自己的問題!
  • 自己坑起自己來果然是不遺餘力啊!