前面的话

  上一篇,我们介绍了元素拖拽的实现。但在实际应用中,常常需要为拖拽的元素限定范围。而通过限定范围,再增加一些辅助的措施,就可以实现磁性吸附的效果

范围限定

  如果我们限定元素只可以在可视范围内移动,那么就需要对其进行范围限定

  首先,先要搞清楚是可视区域限定被拖拽元素

  左侧范围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置L0if(L < L0){X = L0;}//如果脱离右侧范围,则left置为R0if(R > R0){X = R0 - EW;}//如果脱离上侧范围,则top置T0if(T < T0){Y = T0;}//如果脱离下侧范围,则top置为B0if(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置L0if(L - L0 < 50){X = L0;}//如果到达右侧的吸附范围,则left置为R0if(R0 - R < 50){X = R0 - EW;}//如果到达上侧的吸附范围,则top置T0if(T - T0 < 50){Y = T0;}//如果到达右侧的吸附范围,则top置为B0if(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>

转载于:https://www.cnblogs.com/xiaohuochai/p/5898185.html

javascript动画系列第二篇——磁性吸附相关推荐

  1. 深入理解javascript函数系列第二篇——函数参数

    前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数.本文是深入理解javascript函数 ...

  2. javascript动画系列第一篇——模拟拖拽

    前面的话 从本文开始,介绍javascript动画系列.javascript本身是具有原生拖放功能的,但是由于兼容性问题,以及功能实现的方式,用的不是很广泛.javascript动画广泛使用的还是模拟 ...

  3. javascript运动系列第二篇——变速运动

    前面的话 前面介绍过匀速运动的实现及注意事项,本文在匀速运动的基础上,更进一步,实现各种变速运动,包括加速运动.减速运动.缓冲运动.重力运动和弹性运动 准备工作 匀速运动 在原生javascript中 ...

  4. JavaScript设计模式系列—模式篇总结(上)

    转载请注明预见才能遇见的博客:http://my.csdn.net/ 原文地址:https://blog.csdn.net/pcaxb/article/details/102517956 JavaSc ...

  5. 前端工程师技能之photoshop巧用系列第二篇——测量篇

    前端工程师使用photoshop进行的大量工作实际上是测量.本文是photoshop巧用系列第二篇--测量篇 测量信息 在网页制作中需要使用photoshop测量的信息分为两类,分别是尺寸信息和颜色信 ...

  6. 焱老师带你学习MYSQL系列 第二篇 (MYSQL 数据结构)

    相关系列链接 焱老师带你学习MYSQL系列 第六篇 (MYSQL是如何实现锁的) 焱老师带你学习MYSQL系列 第五篇 (MYSQL事务隔离级别是如何实现的) 焱老师带你学习MYSQL系列 第四篇 ( ...

  7. 阿里出品移动研发“神器” 阿里移动云系列第二篇|“移”步到位:一站式移动应用研发体系...

    摘要:2017杭州云栖大会阿里移动云峰会专场上,阿里巴巴高级技术专家小木带来一站式应用研发体系方面的演讲.本文主要以互联网的应用背景开始谈起,进而阐述了已拥有APP的企业在APP的生命周期中会遇见哪些 ...

  8. [游戏开发]Python打表工具系列 [第二篇] [打表流程描简述]

    [上一篇链接] [游戏开发]Python打表工具系列 [第一篇][IDE开发环境部署] VSCode Python环境调试_Little丶Seven的博客-CSDN博客 [前言] 第二篇文章是对流程的 ...

  9. 深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame

    前面的话 与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔.这有什么好处呢?为什么requestAnimationFrame被称为神器呢 ...

最新文章

  1. SPIEC-EASI的微生物网络构建示例
  2. 蓝桥杯 历届试题 分考场(DFS+枚举)
  3. 乾颐堂安德网工认证1000问(持续更新)
  4. 数据结构与算法 | 树与二叉树
  5. 柱坐标系下的ns方程_麦克斯韦方程组小结
  6. 连续两年入选Gartner公共云容器,阿里云在边缘容器方面做了什么?
  7. mysql数据表中取几列_MySQL实现表中取出随机数据
  8. 怎么监听Android软键盘的打开和关闭
  9. 多种语言打印Hello World
  10. 排兵布阵问题java语言_hdu 4539 郑厂长系列故事——排兵布阵
  11. cheat sheet 打包打印版大全python R machine learning
  12. linux考出光盘数据,电脑如何复制数据到光盘|电脑在光盘中存储数据的方法
  13. 773-780---DOM事件高级(常用鼠标事件,案例:跟随鼠标的天使,常用的键盘事件,案例:模拟京东按键输入内容,案例:模拟京东快递单号查询)
  14. Python实现冒泡排序,从小到大输出(bubble)
  15. vue父组件往子组件传值时报错Property or method 选择操作人 is not defined on the instance but referenced during rende
  16. 关于微信公众号回复消息乱码的问题
  17. vue+elementui+springboot前后端分离实现学校帖子网站,模拟“淘柳职”学校大作业
  18. ST电机库v5.4.4源代码分析(2): 磁链圆限制之计算以及一个小bug
  19. 工具推荐:4个小众Chrome插件,最后一个互联网人必备!
  20. 为啥一直是第54行空指针异常

热门文章

  1. Webstorm 下的Angular2.0开发之路
  2. Linux文件权限的解析
  3. 可用性测试的权衡之道
  4. JavaScript------表单约束验证DOM方法
  5. 关于STM32库中 __IO 修饰符(volatile修饰符,反复无常的意思)
  6. C#自定义控件七水波纹
  7. C++11 range-based for loop
  8. reduce详细用法
  9. SharpGL学习笔记(一) 平台构建与Opengl的hello World (转)
  10. 机器学习工程师 - Udacity 强化学习 Part Nine