setPointerCapture实现小球拖拽实例页面

回到相关文章 »

效果:

 按住小球拖动,可以试试把指针快速移出小球或容器。

left: 20px, top: 20px

代码:

CSS代码:
.drag-area {
    position: relative;
    height: 240px;
    border: 1px dashed #a0b3d6;
    background-color: #f7f9fd;
    overflow: hidden;
    /* 触屏拖动时禁止页面滚动 */
    touch-action: none;
    user-select: none;
}
.ball {
    position: absolute;
    left: 20px;
    top: 20px;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background-image: radial-gradient(circle at 32% 28%, #fff 0, #7eaaf5 35%, #2b6ce1 100%);
    cursor: grab;
    touch-action: none;
}
.ball.dragging { cursor: grabbing; }
HTML代码:
<label><input type="checkbox" id="useCapture" checked> 使用 setPointerCapture</label>
<div class="drag-area" id="dragArea">
    <div class="ball" id="ball"></div>
</div>
<p class="remind" id="pos">left: 20px, top: 20px</p>
                
JS代码:
const area = document.getElementById("dragArea");
const ball = document.getElementById("ball");
const useCapture = document.getElementById("useCapture");
const pos = document.getElementById("pos");

let dragging = false;
let offsetX = 0;
let offsetY = 0;

ball.addEventListener("pointerdown", function (event) {
    dragging = true;
    ball.classList.add("dragging");
    // 关键:把后续所有指针事件都重定向到 ball
    if (useCapture.checked) {
        ball.setPointerCapture(event.pointerId);
    }
    const rect = area.getBoundingClientRect();
    offsetX = event.clientX - rect.left - ball.offsetLeft;
    offsetY = event.clientY - rect.top - ball.offsetTop;
});

ball.addEventListener("pointermove", function (event) {
    if (dragging == false) {
        return;
    }
    const rect = area.getBoundingClientRect();
    const maxX = area.clientWidth - ball.offsetWidth;
    const maxY = area.clientHeight - ball.offsetHeight;
    // 限制在容器内
    const x = Math.max(0, Math.min(maxX, event.clientX - rect.left - offsetX));
    const y = Math.max(0, Math.min(maxY, event.clientY - rect.top - offsetY));
    ball.style.left = x + "px";
    ball.style.top = y + "px";
    pos.textContent = "left: " + Math.round(x) + "px, top: " + Math.round(y) + "px";
});

const stopDrag = function (event) {
    dragging = false;
    ball.classList.remove("dragging");
    if (ball.hasPointerCapture(event.pointerId)) {
        ball.releasePointerCapture(event.pointerId);
    }
};

ball.addEventListener("pointerup", stopDrag);
ball.addEventListener("pointercancel", stopDrag);
ball.addEventListener("lostpointercapture", stopDrag);