原生JS快速拖動元素失效問題

快速拖動元素失效問題緣由及解決方法

情景再現

晚上在寫畢設時,碰到個快速拖動元素,元素會跟不上的問題。具體情形以下:html

代碼及演示結果

  • 出現的問題

    clipboard.png

  • 綁定在 documentbody

    clipboard.png

  • 綁定在 div 本身身上

    clipboard.png

解決方案

  • 首先,本身的思路是 div 以前已經綁定 mousedown 事件,再綁定 mousemove 事件,綁定事件過多從而出現快速移動失效問題。但這思路本身都感受是錯的,因而網上搜索相關問題,從一篇文章中找到了其中的緣由,緣由以下:函數

    鼠標滑動地太快,天然會形成 mousemove 事件屢次發生,相應的,事件處理函數也屢次被調用,天然形成延遲。延遲以後,元素移動的速度趕不上鼠標移動的速度,可能形成鼠標移出元素的狀態,從而觸發了 mouseout 事件,從而形成了被拖動元素中止移動。 ——原文來自 鳶飛魚躍

綁定到bodydocument 之間的細微差異

上面講到,綁定 mousemove 事件到 bodydocument 上,都能拖動地很流暢,可是它們之間仍是有些細微差異的,以下圖所示:測試

  • 綁定到 document
    clipboard.png
  • 綁定到 body
    clipboard.png

Chrome 測試結果中能夠看到,綁定到 document 上時,鼠標移動到菜單欄上,元素依舊能被拖動,而綁定在 body 上卻作不到這一點。spa

代碼

最後,如下是本次測試中用到的代碼,感興趣的小夥伴能夠貼下來本身跑一跑3d

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style>
        *{
            padding:0;
            margin:0;
        }
        div{
            position:absolute;
            left:100px;
            top:50px;
            width:100px;
            height:100px;
            border:1px solid #000;
        }
        body{
            width:100vw;
            height:100vh;
        }
    </style>
</head>
<body>

    <div>Drag Me</div>

    <script>
        const div = document.querySelector('div');
        const body = document.body;

        div.addEventListener('mousedown',(event) => {

            let startX = event.clientX,
            startY = event.clientY,
            left = div.offsetLeft,
            top = div.offsetTop;

            let callback = (event) => {
                const stepX = event.clientX - startX,
                stepY = event.clientY - startY;
                div.style.left = `${left + stepX}px`;
                div.style.top = `${top + stepY}px`;
            };

            document.addEventListener('mousemove',callback);

            div.addEventListener('mouseup',() => {
                document.removeEventListener('mousemove',callback);
            });

        });        
    </script>

</body>
</html>
相關文章
相關標籤/搜索