• js实现页面元素的拖拽


    平时在我们页面上,经常会悬浮着一些功能按钮,如帮助,联系客服等,按钮的显示比较简单,用定位悬浮在自己需要的位置上就行,比如下面的页面上我们展示一个帮助的按钮,用户点击后可以展示一些帮助的信息:

     代码:

    1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8" />
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    6. <meta
    7. name="viewport"
    8. content="width=device-width, initial-scale=1.0"
    9. />
    10. <style type="text/css">
    11. .help-btn {
    12. width: 50px;
    13. height: 50px;
    14. border-radius: 50%;
    15. background: blue;
    16. color: #fff;
    17. position: fixed;
    18. display: flex;
    19. align-items: center;
    20. justify-content: center;
    21. cursor: pointer;
    22. right: 0;
    23. bottom: 150px;
    24. }
    25. </style>
    26. <title>js实现拖拽</title>
    27. </head>
    28. <body>
    29. <div class="help-btn" id="help-btn">帮助</div>
    30. </body>
    31. </html>

    但是这样定位一般是固定在这个位置,如果这时候刚好【帮助按钮】挡住了这个位置原本有的其他操作按钮,那么我们就需要能够把【帮助按钮】拖开,不影响原本页面上的操作。

    一般实现拖动的思路是:在【帮助按钮】上鼠标按下时,记录下当前的坐标,以及原本相对于父元素的位置,然后监听【帮助按钮】的鼠标移动事件【onmousemove】,然后取现在的坐标,计算出两轴上移动的距离,用原本的位置减去移动的位置得到现在的位置,再重新设置给【帮助按钮】即可。最后在【帮助按钮】鼠标抬起事件【onmouseup】上注销对鼠标移动的监听即可。

    代码:

    1. <script type="text/javascript">
    2. let btnEle = document.getElementById("help-btn");
    3. //帮助按钮鼠标按下时
    4. btnEle.onmousedown = (e) => {
    5. let defaultX = e.clientX; //默认位置的x轴坐标
    6. let defaultY = e.clientY; //默认位置的y轴坐标
    7. let defaultLeft = btnEle.offsetLeft; //默认左侧偏移位置
    8. let defaultTop = btnEle.offsetTop; //默认顶部偏移位置
    9. //帮助按钮鼠标移动时
    10. btnEle.onmousemove = (me) => {
    11. btnEle.style.cursor = "move"; //修改鼠标样式
    12. let nowX = me.clientX; //当前位置的x轴坐标
    13. let nowY = me.clientY; //当前位置的y轴坐标
    14. let moveX = defaultX - nowX; //在x轴上的移动距离
    15. let moveY = defaultY - nowY; //在y轴上移动的距离
    16. let nowLeft = defaultLeft - moveX; //当前位置左侧偏移量
    17. let nowTop = defaultTop - moveY; //当前位置顶部偏移量
    18. btnEle.style.left = `${nowLeft}px`; //将当前位置赋值给帮助按钮
    19. btnEle.style.top = `${nowTop}px`;
    20. };
    21. //鼠标抬起时
    22. btnEle.onmouseup = () => {
    23. btnEle.style.cursor = "default"; //重置鼠标样式
    24. //清除事件
    25. btnEle.onmousemove = null;
    26. btnEle.onmouseup = null;
    27. };
    28. };
    29. </script>

    至此可以实现拖动【帮助按钮】移动位置。但是会出现以下几个问题:

    问题1:移动过快,鼠标超过【帮助按钮】的范围,会导致鼠标抬起事件失效,造成移动卡顿;

    解决方法,将鼠标移动事件和鼠标抬起事件挂载在document上。

    代码:

    1. <script type="text/javascript">
    2. //帮助按钮鼠标按下时
    3. btnEle.onmousedown = (e) => {
    4. ...
    5. //鼠标移动时
    6. document.onmousemove = (me) => {
    7. ...
    8. };
    9. //鼠标抬起时
    10. document.onmouseup = () => {
    11. ...
    12. //清除事件
    13. document.onmousemove = null;
    14. document.onmouseup = null;
    15. };
    16. };
    17. </script>

    问题2:鼠标移动过快,可能会选中“帮助”文字,这时候会造成鼠标抬起事件失效。出现移动bug。

    解决方法:在移动时禁用文字选中。鼠标抬起时还原

    代码:

    1. <script type="text/javascript">
    2. //帮助按钮鼠标按下时
    3. btnEle.onmousedown = (e) => {
    4. ...
    5. //禁用文字选中
    6. document.onselectstart = () => {
    7. return false;
    8. };
    9. //鼠标移动时
    10. ...
    11. //鼠标抬起时
    12. document.onmouseup = () => {
    13. ...
    14. document.onselectstart = null;
    15. };
    16. };
    17. </script>

    问题3:会移动到屏幕外面去。

    解决方法:限制范围不超过页面区域(或者你自定义父容器的内容范围)。

    代码:

    1. <script type="text/javascript">
    2. ...
    3. //帮助按钮鼠标按下时
    4. btnEle.onmousedown = (e) => {
    5. ...
    6. let pageWidth = window.innerWidth; //页面宽度
    7. let pageHeight = window.innerHeight; //页面高度
    8. ...
    9. //鼠标移动时
    10. document.onmousemove = (me) => {
    11. ...
    12. //对位置进行限定,只显示在设定的区域内
    13. nowLeft = nowLeft <= 0 ? 0 : nowLeft;
    14. nowLeft =
    15. nowLeft >= pageWidth - btnEle.offsetWidth
    16. ? pageWidth - btnEle.offsetWidth
    17. : nowLeft;
    18. nowTop = nowTop <= 0 ? 0 : nowTop;
    19. nowTop =
    20. nowTop >= pageHeight - btnEle.offsetHeight
    21. ? pageHeight - btnEle.offsetHeight
    22. : nowTop;
    23. ...
    24. };
    25. ...
    26. };
    27. </script>

    问题4:拖动的时候也会触发【帮助按钮】的点击事件。

    解决方法:在鼠标按下时,记录当前时间,在鼠标抬起时再记录一次时间。在点击事件方法中对两个时间差值进行判断,此处我设定是100,可根据自己需求调整。大于这个时间间隔则为拖拽,不继续执行点击的方法。

    代码:

    1. <script type="text/javascript">
    2. ...
    3. let startTime = 0; //鼠标点击时间
    4. let endTime = 0; //鼠标抬起时间
    5. //帮助按钮鼠标按下时
    6. btnEle.onmousedown = (e) => {
    7. startTime = new Date().getTime();
    8. ...
    9. //鼠标抬起时
    10. document.onmouseup = () => {
    11. endTime = new Date().getTime();
    12. ...
    13. };
    14. };
    15. //按钮的点击事件
    16. btnEle.onclick = () => {
    17. if (endTime - startTime >= 100) return false; //说明是拖拽
    18. console.log("我被点击了!");
    19. };
    20. </script>

    到这里为止在单页面上可以实现元素的拖动。但是如果页面上还存在iframe窗口,当鼠标经过iframe窗口的时候,会出现拖拽卡顿,鼠标抬起事件失效的问题。

    解决思路,在鼠标点击的时候在页面上加上一个蒙层,把蒙层作为父元素进行监听。鼠标移除的时候,去除蒙层。

    完整代码:

    1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8" />
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    6. <meta
    7. name="viewport"
    8. content="width=device-width, initial-scale=1.0"
    9. />
    10. <style type="text/css">
    11. .help-btn {
    12. width: 50px;
    13. height: 50px;
    14. border-radius: 50%;
    15. background: blue;
    16. color: #fff;
    17. position: fixed;
    18. display: flex;
    19. align-items: center;
    20. justify-content: center;
    21. cursor: pointer;
    22. right: 0;
    23. bottom: 150px;
    24. z-index: 9999;
    25. }
    26. .move-modal {
    27. position: fixed;
    28. top: 0;
    29. right: 0;
    30. bottom: 0;
    31. left: 0;
    32. z-index: 9999;
    33. }
    34. </style>
    35. <title>js实现拖拽</title>
    36. </head>
    37. <body>
    38. <!-- 蒙层 -->
    39. <div id="move-modal"></div>
    40. <div class="help-btn" id="help-btn">帮助</div>
    41. </body>
    42. <script type="text/javascript">
    43. let btnEle = document.getElementById("help-btn");
    44. let startTime = 0; //鼠标点击时间
    45. let endTime = 0; //鼠标抬起时间
    46. //帮助按钮鼠标按下时
    47. btnEle.onmousedown = (e) => {
    48. startTime = new Date().getTime();
    49. let fatherModal =
    50. document.getElementById("move-modal"); //拿到蒙层元素
    51. fatherModal.classList.add("move-modal"); //给页面加上蒙层
    52. let defaultX = e.clientX; //默认位置的x轴坐标
    53. let defaultY = e.clientY; //默认位置的y轴坐标
    54. let defaultLeft = btnEle.offsetLeft; //默认左侧偏移位置
    55. let defaultTop = btnEle.offsetTop; //默认顶部偏移位置
    56. let pageWidth = fatherModal.offsetWidth; //页面宽度
    57. let pageHeight = fatherModal.offsetHeight; //页面高度
    58. //禁用文字选中
    59. window.onselectstart = () => {
    60. return false;
    61. };
    62. //鼠标移动时
    63. fatherModal.onmousemove = (me) => {
    64. btnEle.style.cursor = "move"; //修改鼠标样式
    65. let nowX = me.clientX; //当前位置的x轴坐标
    66. let nowY = me.clientY; //当前位置的y轴坐标
    67. let moveX = defaultX - nowX; //在x轴上的移动距离
    68. let moveY = defaultY - nowY; //在y轴上移动的距离
    69. let nowLeft = defaultLeft - moveX; //当前位置左侧偏移量
    70. let nowTop = defaultTop - moveY; //当前位置顶部偏移量
    71. //对位置进行限定,只显示在设定的区域内
    72. nowLeft = nowLeft <= 0 ? 0 : nowLeft; //不能超过左侧
    73. nowLeft =
    74. nowLeft >= pageWidth - btnEle.offsetWidth
    75. ? pageWidth - btnEle.offsetWidth
    76. : nowLeft; //不能超过右侧
    77. nowTop = nowTop <= 0 ? 0 : nowTop; //不能超过顶部
    78. nowTop =
    79. nowTop >= pageHeight - btnEle.offsetHeight
    80. ? pageHeight - btnEle.offsetHeight
    81. : nowTop; //不能超过底部
    82. //将当前位置赋值给帮助按钮
    83. btnEle.style.left = `${nowLeft}px`;
    84. btnEle.style.top = `${nowTop}px`;
    85. };
    86. //鼠标抬起时,此处必须是document,不然当多屏幕的时候,鼠标移出当前屏幕还是不会触发鼠标抬起
    87. document.onmouseup = () => {
    88. endTime = new Date().getTime();
    89. btnEle.style.cursor = "default"; //重置鼠标样式
    90. fatherModal.classList.remove("move-modal"); //给页面去除蒙层
    91. //清除事件
    92. fatherModal.onmousemove = null;
    93. document.onmouseup = null;
    94. window.onselectstart = null;
    95. };
    96. };
    97. //按钮的点击事件
    98. btnEle.onclick = () => {
    99. if (endTime - startTime >= 100) return false; //说明是拖拽
    100. console.log("我被点击了!");
    101. };
    102. </script>
    103. </html>

  • 相关阅读:
    基于Java的教学评价管理系统设计与实现(源码+lw+部署文档+讲解等)
    高新技术企业认证条件 ,高企申报流程
    Golang企业面试题
    【LeetCode热题100】--215.数组中的第K个最大元素
    Python开发技术—文件和异常2
    JavaFX、合并碰撞的弹球
    MySQL日志介绍
    推荐一款数据mock框架,无需任何依赖,贼牛逼
    VS2019_连接 SqlServer 数据库
    口碑好的猫罐头有哪些?宠物店受欢迎的5款猫罐头推荐!
  • 原文地址:https://blog.csdn.net/zongmaomx/article/details/125404526