一文带你了解原生js实现拖拽的具体细节

目录

1.准备

2.效果实现

需要用到的方法、属性

拖拽过程

移动盒子

3.出现的问题

问题1

问题2

问题3

4.最终版本

5.写在最后


1.准备

  • 准备一个正方形盒子作为拖拽的对象,简单的给些样式以及设置绝对定位
  • 清除浏览器默认样式
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      /* 清除浏览器默认的边距 */
      margin: 0;
      padding: 0;
    }
    #box {
      width: 100px;
      height: 100px;
      position: absolute;
      background-color: red;
    }
  </style>
</head>
<body>
  <div id="box"></div>
</body>

2.效果实现

需要用到的方法、属性

  • 需要用到的鼠标事件有:
    • mousedown/ mouseup 鼠标按下/松开时触发
    • mouseover 当指针设备 ( 通常指鼠标 ) 在元素上移动时,mousemove 事件被触发。
  • 在window.onload事件中添加逻辑

    load 事件在整个页面及所有依赖资源如样式表和图片都已完成加载时触发。

  • clientX,clientY
    • 用于获取鼠标相对于可视窗口的偏移量
  • offsetLeft,offsetTop

    offsetLeft:当前元素相对于其定位元素的水平偏移量

    offsetTop:当前元素相对于其定位元素的垂直偏移量

拖拽过程

  • 在我们点击盒子的时候开始拖拽,接着盒子跟着鼠标进行移动
  • 鼠标松开将盒子位置固定住

移动盒子

  • 在鼠标按下时执行移动逻辑,获取盒子dom元素,绑定 onmousedown,onmouseup 事件对于鼠标按下,抬起进行监听;
  • 给页面(document)绑定onmousemove事件,即document.onmousemove,鼠标在移动时clientX,clientY也随之变化,将最终偏移量设置给盒子的left, top属性;
  • 盒子位置设置完成后,在鼠标抬起时解绑事件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      /* 清除浏览器默认的边距 */
      margin: 0;
      padding: 0;
    }
    #box {
      width: 100px;
      height: 100px;
      position: absolute;
      background-color: red;
    }

  </style>
</head>
<body> 
	<script type="text/javascript">
    window.onload = function() {
      const box = document.getElementById('box')
      
      // 鼠标按下
      box.onmousedown = function(event) {
        event = event || window.event
        console.log('鼠标按下', event)
        // 鼠标在页面移动时触发,设置盒子位置
        document.onmousemove = function(e) {
          // console.log('进入了', e)
          e = e || window.event
          // 获取鼠标坐标
          const left = e.clientX + 'px'
          const top = e.clientY + 'px'
          box.style.left = left
          box.style.top = top
        }

        // 鼠标松开
        box.onmouseup = function(event) {
          console.log('松开了', event)
          // 取消跟随鼠标移动,鼠标松开事件
          document.onmousemove = null
          document.onmouseup = null
        }
      }
      
    }

  </script>
</body>

3.出现的问题

问题1(重点)

  • 很快我们能发现在移动过程中,无论点击盒子的那个位置,最终鼠标的光标总是指向盒子的左上角;
  • 而上面的代码确实也是存在些漏洞,首先我们已经知道了clientX,clientY是鼠标相对于可视窗口的偏移量,这个点位就是我们希望盒子移动时的点位,而不是总指向左上角;但是我们在给盒子设置位置时,是直接将clientX,clientY直接设置给了left与top;
  • 画了一个简图(橙色盒子为我们初始位置移动后的过程):
    1. 可以看出给盒子设置的距离应该是太大了,因为我们希望clientX与clientY设置给盒子距离左边和顶部的距离就是包括鼠标中心点左边以及上边的距离;
    2. 那么发现问题之后,我们要做的就是给盒子设置的left与top需要减去多出的偏移量;而这多出的距离,就是中心点距离盒子左边和上边的距离;
    3. 这时候之前介绍的offsetLeft,offsetTop派上用场,它们能够获取到当前元素相对于其 offsetParent (这里指的就是document)元素的左边和顶部的距离;结合已有的clientX,Y偏移量,相减得到咱们多出的距离

最终我们修改设置盒子位置的逻辑

document.onmousemove = function(e) {
  e = e || window.event //兼容写法
  const ol = e.clientX - box.offsetLeft
  const ot = e.clientY - box.offsetTop
  // 获取鼠标坐标
  const left = e.clientX - ol + 'px'
  const top = e.clientY - ot + 'px'
  box.style.left = left
  box.style.top = top
}

问题2

  • 当我们拖动时,一直往同一个方向盒子有可能会超出可视区域
  • 结果就像这样:

  • 问题就在于没有给盒子设置边界,这里通过left,top值的大小设置左边与顶部的拖拽范围;
  • 如果还想对右边以及底部做出限制,那么可以获取父容器(这里指document)的宽高,属性是cilentWidth,clientHeight,这里我就写个左边和顶部为例了

添加左,上边界

// 鼠标在页面移动时触发,设置盒子位置
document.onmousemove = function(e) {
  e = e || window.event //兼容写法    
  // 左边
  let left = e.clientX - ol < 0 ? 0 : e.clientX - ol 
  // 顶部
  let top = e.clientY - ot < 0 ? 0 : e.clientY - ot
  box.style.left = left + 'px'
  box.style.top = top + 'px'
}

问题3

  • 当页面上存在两个盒子的时候,移动的盒子经过另一个盒子时并且出现重叠的情况下,在鼠标松开后无法将盒子定位至所在区域
  • 就像下图这样:

  • 问题就出在重叠时,onmouseup事件变为了绿盒子(box1)的,所以没有触发红盒子(box)的鼠标抬起事件;
  • 为了测试我们给绿盒子(box1)添加onmouseup事件,然后在红盒子(box)移入其中并且松开鼠标时看控制台输出情况;

解决方式

  • 这里有两个方式,一是通过css样式给盒子添加层级,因为这两个盒子都是绝对定位,在移动过程中因为相互覆盖导致的问题,这里通过z-index属性把红盒子层级设置高一点或者绿盒子设置低一点,保证红盒子重叠时处于上方
#box {
  width: 100px;
  height: 100px;
  background-color: red;
  position: absolute;
  z-index: 99;
}
  • 二是把鼠标松开事件绑定给盒子的父元素也就是document,这里采用这种方式进行处理
// 鼠标松开
document.onmouseup = function(event) {
  console.log('box红,鼠标松开了')
  // 取消跟随鼠标移动,鼠标松开事件
  document.onmousemove = null
  document.onmouseup = null
}

4.最终版本

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      /* 清除浏览器默认的边距 */
      margin: 0;
      padding: 0;
    }
    #box {
      width: 100px;
      height: 100px;
      background-color: red;
      position: absolute;
      /* z-index: 99; */
    }
    // #box1 {
    //   width: 100px;
    //   height: 100px;
    //   left: 600px;
    //   top: 300px;
    //   background-color: green;
    //   position: absolute;
    // }
  </style>
</head>
<body>
  <div id="box"></div>
  <div id="box1"></div>

  <script type="text/javascript">
    window.onload = function() {
      const box = document.getElementById('box')
      // const box1 = document.getElementById('box1')
      // box1.onmouseup = function() {
      //   console.log('box1鼠标松开了')
      // }
      
      // 鼠标按下
      box.onmousedown = function(event) {
        // 设置box捕获所有鼠标点击事件 仅支持ie
        box.setCapture && box.setCapture()

        event = event || window.event
        const ol = event.clientX - box.offsetLeft
        const ot = event.clientY - box.offsetTop
        // 鼠标在页面移动时触发,设置盒子位置
        document.onmousemove = function(e) {
          e = e || window.event //兼容写法          
          // 获取鼠标坐标
          let left = e.clientX - ol < 0 ? 0 : e.clientX - ol 
          let top = e.clientY - ot < 0 ? 0 : e.clientY - ot
          box.style.left = left + 'px'
          box.style.top = top + 'px'
        }

        // 鼠标松开
        document.onmouseup = function(event) {
          // console.log('box红鼠标松开了')
          // 取消跟随鼠标移动,鼠标松开事件
          document.onmousemove = null
          document.onmouseup = null
          // 取消捕获所有鼠标点击事件
          box.releaseCapture && box.releaseCapture()
        }
        /* 
         1.当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,
            此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,
         2. 如果不希望发生这个行为,则可以通过return false来取消默认行为
         3. 但是这招对工E8不起作用 
        */
        return false
      }
    }

  </script>
</body>
</html>

5.写在最后

  • 以上就是js实现拖拽的全部内容了,如果觉得文章写得不够好或是存在问题欢迎评论指正,感谢你这么优秀还来看我的文章。
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LVS(Linux Virtual Server)是一种基于 Linux 系统的负载均衡集群技术,它主要用于将网络流量分发到多个服务器上,以提高系统的可靠性、可扩展性和性能。 LVS 集群一般包括四个组件:调度器(LVS 调度器)、前端服务器(负载均衡器)、后端服务器(真实服务器)和存储服务器(用于共享数据)。首先,调度器接收来自客户端的请求,然后根据配置的调度算法(如轮询、加权轮询、最小连接数等)将请求分发到多个前端服务器。前端服务器接收到请求后,通过相应的负载均衡算法将请求转发到后端的真实服务器上进行处理。在整个过程中,存储服务器用于存放共享的数据,以确保所有的真实服务器都能获取到相同的数据,并提供一致的服务。 LVS 集群的优点是能够提高网站的稳定性和可靠性,当某一台服务器出现故障时,调度器会自动将请求分发到其他可用的服务器上,从而保证服务的连续性。同时,LVS 集群还能够通过增加前端服务器和后端服务器的数量来提高系统的性能和吞吐量,以满足不断增长的用户需求。 在实际应用中,LVS 集群需要合理配置,包括选择合适的调度算法、调整每台服务器的权重、选择适当的硬件设备等。此外,还需要及时监控集群的运行状态,及时发现和解决故障,以确保整个系统的正常运行。 总的来说,LVS 负载均衡集群是一种强大而高效的集群技术,能够帮助企业提高系统的可靠性和性能,是现代互联网应用中不可或缺的重要组成部分。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值