实现一个简单的拖拽

  1. 拖拽的思路
    1. 拿到鼠标点击元素时,元素一开始的位置;
    2. 拿到鼠标移动的距离:鼠标移动实时的位置 - 鼠标点击的位置;
    3. 确定鼠标移动后,元素的位置:元素一开始的位置 + 鼠标移动的距离;
  2. 图解
  3. 示例代码(此时拖拽功能还是有瑕疵)
    HTML
    CSS
    JavaScript
    <body>
      <div id="test"></div>
    </body>
    
    * {
      margin: 0;
      padding: 0;
    }
    
    html,
    body {
      height: 100%;
      overflow: hidden;
      /*防止出现滚动条*/
    }
    
    #test {
      position: absolute;
      left: 0;
      top: 0;
      width: 150px;
      height: 150px;
      background: pink;
    }
    
    window.onload = function () {
      var testNode = document.querySelector("#test");
      // 元素相对于视口的初始位置
      var startPoint = { x: 0, y: 0 };
    
      // 鼠标点击的初始位置
      var mouseDownPoint = { x: 0, y: 0 }
    
      // 鼠标按下
      testNode.onmousedown = function (ev) {
        ev = ev || event;
    
        startPoint.x = this.offsetLeft;
        startPoint.y = this.offsetTop;
    
        mouseDownPoint.x = ev.clientX;
        mouseDownPoint.y = ev.clientY;
    
        // 由于 onmousemove 可以单独触发,则放到鼠标点击事件中
        // 鼠标移动过快不能触发移动事件,将事件绑定到 document 上面
        document.onmousemove = function (ev) {
          ev = ev || event;
          // 实时鼠标移动
          var mouseMovePoint = { x: 0, y: 0 }
          mouseMovePoint.x = ev.clientX;
          mouseMovePoint.y = ev.clientY;
    
          // 鼠标移动的距离
          var dis = { x: 0, y: 0 };
          dis.x = mouseMovePoint.x - mouseDownPoint.x;
          dis.y = mouseMovePoint.y - mouseDownPoint.y;
          testNode.style.left = startPoint.x + dis.x + "px";
          testNode.style.top = startPoint.y + dis.y + "px";
        }
    
        // 松掉鼠标:清除事件
        document.onmouseup = function () {
          document.onmousemove = document.onmouseup = null;
        }
      }
    }
    

处理阻止默认事件

  1. 示例代码

    HTML
    CSS
    JavaScript
    <body>
      这段文字被选中时,文字会被拖拽
      <div id="test"></div>
    </body>
    
    * {
      margin: 0;
      padding: 0;
    }
    
    html,
    body {
      height: 100%;
      overflow: hidden;
    }
    
    #test {
      position: absolute;
      left: 0;
      top: 0;
      width: 150px;
      height: 150px;
      background: pink;
    }
    
    window.onload = function () {
      var testNode = document.querySelector("#test");
      // 元素相对于视口的初始位置
      var startPoint = { x: 0, y: 0 };
    
      // 鼠标点击的初始位置
      var mouseDownPoint = { x: 0, y: 0 }
    
      // 鼠标按下
      testNode.onmousedown = function (ev) {
        ev = ev || event;
    
        startPoint.x = this.offsetLeft;
        startPoint.y = this.offsetTop;
    
        mouseDownPoint.x = ev.clientX;
        mouseDownPoint.y = ev.clientY;
    
        // 由于 onmousemove 可以单独触发,则放到鼠标点击事件中
        // 鼠标移动过快不能触发移动事件,将事件绑定到 document 上面
        document.onmousemove = function (ev) {
          ev = ev || event;
          // 实时鼠标移动
          var mouseMovePoint = { x: 0, y: 0 }
          mouseMovePoint.x = ev.clientX;
          mouseMovePoint.y = ev.clientY;
    
          // 鼠标移动的距离
          var dis = { x: 0, y: 0 };
          dis.x = mouseMovePoint.x - mouseDownPoint.x;
          dis.y = mouseMovePoint.y - mouseDownPoint.y;
          testNode.style.left = startPoint.x + dis.x + "px";
          testNode.style.top = startPoint.y + dis.y + "px";
        }
    
        // 松掉鼠标:清除事件
        document.onmouseup = function () {
          document.onmousemove = document.onmouseup = null;
        }
    
        // 阻止事件的默认行为,否则文字 会被拖拽
        // IE8 以下的默认行为 不能阻止,使用全局捕获解决
        return false;
      }
    }
    
  2. 效果展示(没有被阻止默认行为之前)

处理全局捕获兼容问题

  1. 全局捕获

    1. 在谷歌下:没有全局捕获;
    2. 在火狐下:全局捕获有定义,但没有实际的作用;
    3. 在 IE 下:全局捕获专治各种不服;
  2. 设置全局捕获

    1. element.setCapture
    2. 在处理一个 mousedown 事件过程中调用这个方法来把全部的鼠标事件重新定向到这个元素,直到鼠标按钮被释放或者 document.releaseCapture() 被调用;
  3. 取消全局捕获

    1. document.releaseCapture
    2. 如果该 document 中的一个元素之上当前启用了鼠标捕获,则释放鼠标捕获;
  4. 示例代码

    HTML
    CSS
    JavaScript
    <body>
      文字拖拽已经被阻止
      <div id="test"></div>
    </body>
    
    * {
      margin: 0;
      padding: 0;
    }
    
    html,
    body {
      height: 100%;
      overflow: hidden;
    }
    
    #test {
      position: absolute;
      left: 0;
      top: 0;
      width: 150px;
      height: 150px;
      background: pink;
    }
    
    window.onload = function () {
      var testNode = document.querySelector("#test");
      // 元素相对于视口的初始位置
      var startPoint = { x: 0, y: 0 };
    
      // 鼠标点击的初始位置
      var mouseDownPoint = { x: 0, y: 0 }
    
      testNode.onmousedown = function (ev) {
        ev = ev || event;
        startPoint.x = this.offsetLeft;
        startPoint.y = this.offsetTop;
    
        mouseDownPoint.x = ev.clientX;
        mouseDownPoint.y = ev.clientY;
    
        //曲线救国:不让焦点离开元素,间接的阻止了 document 的默认行为
        if (this.setCapture) {
          this.setCapture();
        }
    
        document.onmousemove = function (ev) {
          ev = ev || event;
          var mouseMovePoint = { x: 0, y: 0 }
          mouseMovePoint.x = ev.clientX;
          mouseMovePoint.y = ev.clientY;
          var dis = { x: 0, y: 0 };
          dis.x = mouseMovePoint.x - mouseDownPoint.x;
          dis.y = mouseMovePoint.y - mouseDownPoint.y;
          testNode.style.left = startPoint.x + dis.x + "px";
          testNode.style.top = startPoint.y + dis.y + "px";
        }
    
        document.onmouseup = function () {
          document.onmousemove = document.onmouseup = null;
          if (document.releaseCapture) {
            document.releaseCapture();
          }
        }
    
        // IE8 以下的默认行为 不能阻止,使用全局捕获解决
        return false;
      }
    }
    

增加限制范围、磁性吸附

HTML
CSS
JavaScript
<body>
  <div id="test"></div>
</body>
* {
  margin: 0;
  padding: 0;
}

html,
body {
  height: 100%;
  overflow: hidden;
}

#test {
  position: absolute;
  left: 0;
  top: 0;
  width: 150px;
  height: 150px;
  background: pink;
}
window.onload = function () {
  var testNode = document.querySelector("#test");
  // 元素相对于视口的初始位置
  var startPoint = { x: 0, y: 0 };

  // 鼠标点击的初始位置
  var mouseDownPoint = { x: 0, y: 0 }

  testNode.onmousedown = function (ev) {
    ev = ev || event;
    startPoint.x = this.offsetLeft;
    startPoint.y = this.offsetTop;

    mouseDownPoint.x = ev.clientX;
    mouseDownPoint.y = ev.clientY;

    //曲线救国
    if (this.setCapture) {
      this.setCapture();
    }

    document.onmousemove = function (ev) {
      ev = ev || event;
      var mouseMovePoint = { x: 0, y: 0 }
      mouseMovePoint.x = ev.clientX;
      mouseMovePoint.y = ev.clientY;

      var dis = { x: 0, y: 0 };
      dis.x = mouseMovePoint.x - mouseDownPoint.x;
      dis.y = mouseMovePoint.y - mouseDownPoint.y;

      var L = startPoint.x + dis.x;
      var T = startPoint.y + dis.y;

      // // 限制左边界
      // if (L < 0) {
      //   L = 0;
      // }
      // // 限制上边界
      // if (T < 0) {
      //   T = 0;
      // }
      // // 限制下边界
      // if (T > (document.documentElement.clientHeight - testNode.offsetHeight)) {
      //   T = (document.documentElement.clientHeight - testNode.offsetHeight)
      // }
      // // 限制右边界
      // if (L > (document.documentElement.clientWidth - testNode.offsetWidth)) {
      //   L = (document.documentElement.clientWidth - testNode.offsetWidth)
      // }

      // 左边距 小于 10 ,设置为 0
      if (L < 10) {
        L = 0;
      }
      // 上边距 小于 10 ,设置为 0
      if (T < 10) {
        T = 0;
      }
      // 下边距 小于 10,设置为 0
      if (T > (document.documentElement.clientHeight - testNode.offsetHeight - 10)) {
        T = (document.documentElement.clientHeight - testNode.offsetHeight)
      }
      // 右边距 小于 10,设置为 0
      if (L > (document.documentElement.clientWidth - testNode.offsetWidth - 10)) {
        L = (document.documentElement.clientWidth - testNode.offsetWidth)
      }
      testNode.style.left = L + "px";
      testNode.style.top = T + "px";
    }

    document.onmouseup = function () {
      document.onmousemove = document.onmouseup = null;
      if (document.releaseCapture) {
        document.releaseCapture();
      }
    }

    return false;
  }
}

增加碰撞检测

  1. 图解:(根据视口中的元素距离视口的距离来判断)

  2. 示例代码

    HTML
    CSS
    JavaScript
    <body>
      <div id="test"></div>
      <img id="zaw" src="img/tg.png" />
    </body>
    
    * {
      margin: 0;
      padding: 0;
    }
    
    html,
    body {
      height: 100%;
      overflow: hidden;
    }
    
    #test {
      position: absolute;
      left: 0;
      top: 0;
      width: 200px;
      height: 200px;
      background: pink;
    }
    
    #zaw {
      position: absolute;
      left: 600px;
      top: 200px;
      width: 500px;
      height: 300px;
    }
    
    window.onload = function () {
      var testNode = document.querySelector("#test");
      var imgNode = document.querySelector("img");
    
      // 元素相对于视口的初始位置
      var startPoint = { x: 0, y: 0 };
    
      // 鼠标点击的初始位置
      var mouseDownPoint = { x: 0, y: 0 }
    
      testNode.onmousedown = function (ev) {
        ev = ev || event;
        startPoint.x = this.offsetLeft;
        startPoint.y = this.offsetTop;
    
        mouseDownPoint.x = ev.clientX;
        mouseDownPoint.y = ev.clientY;
    
        //曲线救国
        if (this.setCapture) {
          this.setCapture();
        }
    
        document.onmousemove = function (ev) {
          ev = ev || event;
          var mouseMovePoint = { x: 0, y: 0 }
          mouseMovePoint.x = ev.clientX;
          mouseMovePoint.y = ev.clientY;
    
          var dis = { x: 0, y: 0 };
          dis.x = mouseMovePoint.x - mouseDownPoint.x;
          dis.y = mouseMovePoint.y - mouseDownPoint.y;
    
          var L = startPoint.x + dis.x;
          var T = startPoint.y + dis.y;
    
          //限制范围  磁性吸附
          if (L < 10) {
            L = 0;
          } else if (L > (document.documentElement.clientWidth - testNode.offsetWidth - 10)) {
            L = (document.documentElement.clientWidth - testNode.offsetWidth)
          }
          if (T < 10) {
            T = 0;
          } else if (T > (document.documentElement.clientHeight - testNode.offsetHeight - 10)) {
            T = (document.documentElement.clientHeight - testNode.offsetHeight)
          }
          testNode.style.left = L + "px";
          testNode.style.top = T + "px";
    
          //碰撞检测
          var T1 = testNode.offsetTop;
          var B1 = testNode.offsetTop + testNode.offsetHeight;
          var R1 = testNode.offsetLeft + testNode.offsetWidth
          var L1 = testNode.offsetLeft;
    
          var T2 = imgNode.offsetTop;
          var B2 = imgNode.offsetTop + imgNode.offsetHeight;
          var R2 = imgNode.offsetLeft + imgNode.offsetWidth
          var L2 = imgNode.offsetLeft;
    
          if (R1 < L2 || B1 < T2 || L1 > R2 || T1 > B2) {
            //没有撞到
            imgNode.src = "img/tg.png";
          } else {
            imgNode.src = "img/xfz.png";
          }
        }
    
        document.onmouseup = function () {
          document.onmousemove = document.onmouseup = null;
          if (document.releaseCapture) {
            document.releaseCapture();
          }
        }
    
        return false;
      }
    }
    
  3. 效果展示

拖拽(封装)

HTML
JavaScript
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title></title>
  <style type="text/css">
    * {
      margin: 0;
      padding: 0;
    }
    html,
    body {
      height: 100%;
      overflow: hidden;
    }
    #test {
      position: absolute;
      left: 0;
      top: 0;
      width: 200px;
      height: 200px;
      background: pink;
    }
    #zaw {
      position: absolute;
      left: 600px;
      top: 200px;
      width: 200px;
      height: 200px;
    }
  </style>
</head>
<body>
  <div id="test"></div>
  <img id="zaw" src="img/tg.png" />
</body>
<script src="js/damu.js"></script>
<script type="text/javascript">
  window.onload = function () {
    var testNode = document.querySelector("#test");
    var imgNode = document.querySelector("img");
    damu.drag(testNode, true, 100, imgNode);
  }
</script>
</html>
// damu.js
(function (w) {
  w.damu = {};
  /**
   * @param {*} node 拖拽元素
  * @param {*} flag flag:是否限制范围
  * @param {*} value 吸附程度
  * @param {*} node2 碰撞元素
  */
  damu.drag = function (node, flag, value, node2) {
    var limit = true;
    var adsorption = 0;
    var startPoint = { x: 0, y: 0 };
    var mouseDownPoint = { x: 0, y: 0 }

    node.onmousedown = function (ev) {
      ev = ev || event;
      startPoint.x = this.offsetLeft;
      startPoint.y = this.offsetTop;
      mouseDownPoint.x = ev.clientX;
      mouseDownPoint.y = ev.clientY;

      if (this.setCapture) {
        this.setCapture();
      }

      document.onmousemove = function (ev) {
        ev = ev || event;
        var mouseMovePoint = { x: 0, y: 0 }
        mouseMovePoint.x = ev.clientX;
        mouseMovePoint.y = ev.clientY;

        var dis = { x: 0, y: 0 };
        dis.x = mouseMovePoint.x - mouseDownPoint.x;
        dis.y = mouseMovePoint.y - mouseDownPoint.y;
        var L = startPoint.x + dis.x;
        var T = startPoint.y + dis.y;

        // 限制范围
        limit = flag === false ? false : true;
        if (limit) {
          // 吸附程度
          if (value) {
            adsorption = value;
          }

          if (L < adsorption) {
            L = 0;
          } else if (L > (document.documentElement.clientWidth - node.offsetWidth - adsorption)) {
            L = (document.documentElement.clientWidth - node.offsetWidth)
          }

          if (T < adsorption) {
            T = 0;
          } else if (T > (document.documentElement.clientHeight - node.offsetHeight - adsorption)) {
            T = (document.documentElement.clientHeight - node.offsetHeight)
          }
        }

        node.style.left = L + "px";
        node.style.top = T + "px";

        // 碰撞检测
        if (node2) {
          var T1 = node.offsetTop;
          var B1 = node.offsetTop + node.offsetHeight;
          var R1 = node.offsetLeft + node.offsetWidth
          var L1 = node.offsetLeft;

          var T2 = node2.offsetTop;
          var B2 = node2.offsetTop + node2.offsetHeight;
          var R2 = node2.offsetLeft + node2.offsetWidth
          var L2 = node2.offsetLeft;

          if (R1 < L2 || B1 < T2 || L1 > R2 || T1 > B2) {
            node2.src = "img/tg.png";
          } else {
            node2.src = "img/xfz.png";
          }
        }
      }

      document.onmouseup = function () {
        document.onmousemove = document.onmouseup = null;
        if (document.releaseCapture) {
          document.releaseCapture();
        }
      }

      return false;
    }
  }
})(window)
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 实现一个简单的拖拽
  2. 2. 处理阻止默认事件
  3. 3. 处理全局捕获兼容问题
  4. 4. 增加限制范围、磁性吸附
  5. 5. 增加碰撞检测
  6. 6. 拖拽(封装)