by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=12481
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
一、还在mousedown个棒槌
关于拖拽的文章,我之前写过至少两三篇,之前实现逻辑都是这样。
一个拖拽标志量,一个存储数据的变量。
mousedown后标志量开启,存储初始数据,
然后在document文档上绑定mousemove,实时计算位置。
等mouseup后再恢复和处理。
用了很多年,自我感觉也挺好的,眼睛闭着都能手写出来。
实际上,上面这套实现已经过时了,且过时很久了。
现在还在使用mousedown实现拖拽效果,那就是个棒槌了。
应该使用pointerdown、pointerup这类事件(PC、Mobile双通),同时,移动的事件也不需要绑定在document或者<body>元素上了,直接写在触发元素上即可!
有人会问了,要是拖动太快,鼠标从触发元素上移出,岂不是pointermove事件不会触发?
是有这个问题,不过,此事件在设计的时候就考虑到这种场景了,于是设计了setPointerCapture方法,专门针对此问题。
二、setPointerCapture与拖拽
setPointerCapture可以捕获事件的pointerId,在鼠标或手势释放之前,后续所有事件都将以该捕获元素为目标。
所以拖拽的时候,不要担心目标元素会丢失。
眼见为实,直接看案例,假设一个球是ball:
<div class="ball" id="ball"></div>
那么所有拖拽事件都可以绑定在 ball 元素上,通过setPointerCapture捕获,不要担心拖拽行为那么容易丢失。
JS代码参考示意:
let dragging = false; let offsetX = 0; let offsetY = 0; ball.addEventListener("pointerdown", function (event) { dragging = true; // 最关键代码就是我 ball.setPointerCapture(event.pointerId); ... }); ball.addEventListener("pointermove", function (event) { if (dragging == false) { return; } ... }); const stopDrag = function (event) { dragging = false; if (ball.hasPointerCapture(event.pointerId)) { ball.releasePointerCapture(event.pointerId); } }; ball.addEventListener("pointerup", stopDrag); ball.addEventListener("pointercancel", stopDrag); ball.addEventListener("lostpointercapture", stopDrag); 鼠标或手指按下的时候setPointerCapture,抬起的时候释放releasePointerCapture,就可以完成体验流畅的拖拽效果啦。
眼见为实,您可以狠狠地点击这里:setPointerCapture实现小球拖拽demo

演示效果是AI生成的,虽然不是我的UI美学风格,但是算了,省心啊,嘿嘿😋。
三、在唠叨点什么,水些字数
哎呀,内容有点少了,再水些内容吧。
说到Pointer,我不自觉又联想到了requestPointerLock,这个是用来实现无限滚动的,属于JS Pointer Lock的内容,之前写文章介绍过:鼠标无限移动 JS API Pointer Lock简介
CSS的pointer-events:none可以干掉JS pointer相关的事件,不过却阻止不了focus交互。
还有啥,好有啥,我想想……
哦,还有个touch-action,与触摸有关的,可以阻止滚动啥的,可以防止自怼拖拽和原生滚动冲突。
然后老的setCapture()方法已经废弃了,万不可使用。
噢啦,差不多就这么多了。
感谢大家的阅读,周末愉快,祝我爆护。
这是我上周末钓的,168五小时,钓得都铺出来了,😁😁。

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=12481
(本篇完)




