javascript动画系列第二篇——磁性吸附

前面的话
上一篇,我们介绍了元素拖拽的实现。但在实际应用中,常常需要为拖拽的元素限定范围。而通过限定范围,再增加一些辅助的措施,就可以实现磁性吸附的效果
范围限定
如果我们限定元素只可以在可视范围内移动,那么就需要对其进行范围限定
首先,先要搞清楚是可视区域限定被拖拽元素
左侧范围L0 = 0
右侧范围R0 = document.documentElement.clientWidth
上侧范围T0 = 0
下侧范围B0 = document.documentElement.clientHeight
元素的上下左右四边分别为
左侧边 L = offsetLeft
右侧边 R = offsetLeft + offsetWidth
上侧边 T = offsetTop
下侧边 B = offsetTop + offsetHeight
function limitedRange(obj,fn){ var L0 = 0; var R0 = document.documentElement.clientWidth; var T0 = 0; var B0 = document.documentElement.clientHeight; var L = obj.offsetLeft; var R = obj.offsetLeft + obj.offsetWidth; var T = obj.offsetTop; var B = obj.offsetTop + obj.offsetHeight; if(L >= L0 && R <= R0 && T >= T0 && B <= B0){ fn(obj); } }
拖拽范围
如果将范围限定在拖拽元素上,则需要一些改变
首先,限定条件并不是在范围内执行什么,而是不在范围内时,应该执行什么
由于在拖拽实现中,已经获取了元素距离可视区域左上角的X轴和Y轴的距离,所以不需要再通过offsetLeft和offsetTop进行重新获取
<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;">测试文字</div> <script> function addEvent(target,type,handler){ if(target.addEventListener){ target.addEventListener(type,handler,false); }else{ target.attachEvent('on'+type,function(event){ return handler.call(target,event); }); } } (function(){ var x0,y0,x1,y1,isMoving; var ele = document.getElementById('test'); var L0,R0,T0,B0,EH,EW; var mousedownHandler = function(e){ e = e || event; //获取元素距离定位父级的x轴及y轴距离 x0 = this.offsetLeft; y0 = this.offsetTop; //获取此时鼠标距离视口左上角的x轴及y轴距离 x1 = e.clientX; y1 = e.clientY; //按下鼠标时,表示正在运动 isMoving = true; //鼠标按下时,获得此时的页面区域 L0 = 0; R0 = document.documentElement.clientWidth; T0 = 0; B0 = document.documentElement.clientHeight; //鼠标按下时,获得此时的元素宽高 EH = ele.offsetHeight; EW = ele.offsetWidth; } var mousemoveHandler = function(e){ //如果没有触发down事件,而直接触发move事件,则函数直接返回 if(!isMoving){ return; } e = e || event; //获取此时鼠标距离视口左上角的x轴及y轴距离 var x2 = e.clientX; var y2 = e.clientY; //计算此时元素应该距离视口左上角的x轴及y轴距离 var X = x0 + (x2 - x1); var Y = y0 + (y2 - y1); /******范围限定*******/ //获取鼠标移动时元素四边的瞬时值 var L = X; var R = X + EW; var T = Y; var B = Y + EH; //在将X和Y赋值给left和top之前,进行范围限定。只有在范围内时,才进行相应的移动 //如果脱离左侧范围,则left置L0 if(L < L0){X = L0;} //如果脱离右侧范围,则left置为R0 if(R > R0){X = R0 - EW;} //如果脱离上侧范围,则top置T0 if(T < T0){Y = T0;} //如果脱离下侧范围,则top置为B0 if(B > B0){Y = B0 - EH;} //将X和Y的值赋给left和top,使元素移动到相应位置 ele.style.left = X + 'px'; ele.style.top = Y + 'px'; } var mouseupHandler = function(e){ //鼠标抬起时,表示停止运动 isMoving = false; //释放全局捕获 if(ele.releaseCapture){ ele.releaseCapture(); } } var preventDefaultHandler = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } //IE8-浏览器阻止默认行为 if(ele.setCapture){ ele.setCapture(); } } addEvent(ele,'mousedown',mousedownHandler); addEvent(ele,'mousedown',preventDefaultHandler); addEvent(document,'mousemove',mousemoveHandler) addEvent(document,'mouseup',mouseupHandler) })(); </script>
磁性吸附
磁性吸附只需要在范围限定的基础上,做一些修改即可
下列代码中,只要元素的四边,距离可视区域范围的四边小于50px,则元素将直接吸附对应的边上
<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;">测试文字</div> <script> function addEvent(target,type,handler){ if(target.addEventListener){ target.addEventListener(type,handler,false); }else{ target.attachEvent('on'+type,function(event){ return handler.call(target,event); }); } } (function(){ var x0,y0,x1,y1,isMoving; var ele = document.getElementById('test'); var L0,R0,T0,B0,EH,EW; var mousedownHandler = function(e){ e = e || event; //获取元素距离定位父级的x轴及y轴距离 x0 = this.offsetLeft; y0 = this.offsetTop; //获取此时鼠标距离视口左上角的x轴及y轴距离 x1 = e.clientX; y1 = e.clientY; //按下鼠标时,表示正在运动 isMoving = true; //鼠标按下时,获得此时的页面区域 L0 = 0; R0 = document.documentElement.clientWidth; T0 = 0; B0 = document.documentElement.clientHeight; //鼠标按下时,获得此时的元素宽高 EH = ele.offsetHeight; EW = ele.offsetWidth; } var mousemoveHandler = function(e){ //如果没有触发down事件,而直接触发move事件,则函数直接返回 if(!isMoving){ return; } e = e || event; //获取此时鼠标距离视口左上角的x轴及y轴距离 var x2 = e.clientX; var y2 = e.clientY; //计算此时元素应该距离视口左上角的x轴及y轴距离 var X = x0 + (x2 - x1); var Y = y0 + (y2 - y1); /******磁性吸附*******/ //获取鼠标移动时元素四边的瞬时值 var L = X; var R = X + EW; var T = Y; var B = Y + EH; //在将X和Y赋值给left和top之前,进行范围限定。只有在范围内时,才进行相应的移动 //如果到达左侧的吸附范围,则left置L0 if(L - L0 < 50){X = L0;} //如果到达右侧的吸附范围,则left置为R0 if(R0 - R < 50){X = R0 - EW;} //如果到达上侧的吸附范围,则top置T0 if(T - T0 < 50){Y = T0;} //如果到达右侧的吸附范围,则top置为B0 if(B0 - B < 50){Y = B0 - EH;} //将X和Y的值赋给left和top,使元素移动到相应位置 ele.style.left = X + 'px'; ele.style.top = Y + 'px'; } var mouseupHandler = function(e){ //鼠标抬起时,表示停止运动 isMoving = false; //释放全局捕获 if(ele.releaseCapture){ ele.releaseCapture(); } } var preventDefaultHandler = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } //IE8-浏览器阻止默认行为 if(ele.setCapture){ ele.setCapture(); } } addEvent(ele,'mousedown',mousedownHandler); addEvent(ele,'mousedown',preventDefaultHandler); addEvent(document,'mousemove',mousemoveHandler) addEvent(document,'mouseup',mouseupHandler) })(); </script>
好的代码像粥一样,都是用时间熬出来的

标签:
javascript总结
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?