如何实现一个拖拽效果

178 阅读2分钟

最终效果

最终效果.gif

实现思路

简介:

首先我们可以先看一张图

image.png

我们可以从函数中拿到浏览器给我们的event对象,而event对象其中有几个值对这种效果的实现至关重要,从图中可以看出用到的这几个变量的意思

要实现这种效果,我们可以用定位来做,通过给draggable盒子定位,计算出他的top值跟left实现位置变动

而拖拽效果是我们点击盒子,按住鼠标才能拖拽,松开鼠标就终止拖拽

(注意:这里还要给拖动的盒子一个类,让里面的文字不能选中,不然在拖拽过程中可能会出现文字给选中的情况)

步骤一:初步实现基本拖拽

<!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>
    body,
    html {
      padding: 0;
      margin: 0;
      height: 100vh;
      width: 100vw;
    }

    #draggable {
      background-color: #eee;
      width: 200px;
      height: 200px;
      font-style: 2rem;
      display: flex;
      justify-content: center;
      align-items: center;
      position: fixed;
      left: 0;
      top: 0;
    }

    .no-select {
      /* 文字无法选中 */
      user-select: none;
      cursor: move;
    }
  </style>
</head>

<body>
  <div id="draggable">drag</div>
  <script>
    // 获取draggable盒子的dom元素(小知识点,直接拿该盒子的id直接当作dom元素用也行,id盒子可以不用做获取dom元素这步操作)
    const draggable = document.getElementById('draggable')
    // 盒子初始left
    let styleLeft = 0
    // 盒子初始top
    let styleTop = 0
    // draggable的盒子高度
    let height = draggable.offsetHeight
    // draggable的盒子宽度
    let width = draggable.offsetWidth
    // 盒子位移x距离
    let cx
    // 盒子位移y距离
    let cy
    // 鼠标按下事件
    draggable.onmousedown = function (e) {
      console.log(draggable.classList);
      draggable.classList.add("no-select");
      // 记录初始拖动鼠标位置
      const startX = e.clientX
      const startY = e.clientY
      document.onmousemove =  function (e) {
        // if (isMouseDown) {
          cx = e.clientX - startX + styleLeft
          cy = e.clientY - startY + styleTop
          draggable.style.left = cx + 'px';
          draggable.style.top = cy + 'px';
        // }
      }
      document.onmouseup = function (e) {
        document.onmousemove = null
        draggable.classList.remove('no-select');
        styleLeft = cx
        styleTop = cy
      }
    }

  </script>
</body>

</html>

基本拖拽效果已经完成,但是我们发现,我们竟然可以拖拽出去浏览器可视范围边界?明显是一个bug,所以我们要给它限定范围,不能让它拖出去

image.png

这时候我们就要看回到这张图了

最简单的两种情况不能拖出左边和上面,无非就是cx = e.clientX - startX + styleLeftcy = e.clientY - startY + styleTop的值不能小于0,如果拖到小于0了,那就让他强制等于0,卡在边界里面

还有两种情况,就是不能超出右边和下面,以右边为例子,从图中可以看出,当cx + draggable.offsetWidth = window.innerWidth的时候,盒子刚好在最右边靠边,所以在更右的时候,我们就要把值写死强制让它等于windows.innerWidth-draggable.innerWidth这里因为cx是一直变化的,所以不能直接让他等于cx

步骤二:解决缺陷(增加拖拽边界)

<!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>
    body,
    html {
      padding: 0;
      margin: 0;
      height: 100vh;
      width: 100vw;
    }

    #draggable {
      background-color: #eee;
      width: 200px;
      height: 200px;
      font-style: 2rem;
      display: flex;
      justify-content: center;
      align-items: center;
      position: fixed;
      left: 0;
      top: 0;
    }

    .no-select {
      /* 文字无法选中 */
      user-select: none;
      cursor: move;
    }
  </style>
</head>

<body>
  <div id="draggable">drag</div>
  <script>
    // 获取draggable盒子的dom元素(小知识点,直接拿该盒子的id直接当作dom元素用也行,id盒子可以不用做获取dom元素这步操作)
    const draggable = document.getElementById('draggable')
    // 盒子初始left
    let styleLeft = 0
    // 盒子初始top
    let styleTop = 0
    // draggable的盒子高度
    let height = draggable.offsetHeight
    // draggable的盒子宽度
    let width = draggable.offsetWidth
    // 盒子位移x距离
    let cx
    // 盒子位移y距离
    let cy
    // 鼠标按下事件
    draggable.onmousedown = function (e) {
      console.log(draggable.classList);
      draggable.classList.add("no-select");
      // 记录初始拖动鼠标位置
      const startX = e.clientX
      const startY = e.clientY
      document.onmousemove =  function (e) {
        // if (isMouseDown) {
          cx = e.clientX - startX + styleLeft
          cy = e.clientY - startY + styleTop
          if (cx < 0) {
            cx = 0
          }
          if (cy < 0) {
            cy = 0
          }
          if (cx + width > window.innerWidth) {
            cx = window.innerWidth - width
          }
          if (cy + height > window.innerHeight) {
            cy = window.innerHeight - height
          }
          draggable.style.left = cx + 'px';
          draggable.style.top = cy + 'px';
        // }
      }
      document.onmouseup = function (e) {
        document.onmousemove = null
        draggable.classList.remove('no-select');
        styleLeft = cx
        styleTop = cy
      }
    }
  </script>
</body>

</html>

结语

这时候一个基本的拖拽效果就实现了