zoukankan      html  css  js  c++  java
  • 通过 JS 实现简单的拖拽功能并且可以在特定元素上禁止拖拽

    前言

    关于讲解 JS 的拖拽功能的文章数不胜数,我确实没有必要大费周章再写一篇重复的文章来吸引眼球。本文的重点是讲解如何在某些特定的元素上禁止拖拽。这是我在编写插件时遇到的问题,其实很多插件的拖拽功能并没有处理这些细节,经过翻阅 jquery ui 的源码才找到答案。

    拖拽实现

    关于拖拽功能不再啰嗦,直接贴代码

    /**
     * [draggable 拖拽方法]
     * @param  {[type]} modal  [移动元素]
     * @param  {[type]} handle [拖拽元素]
     */
    var draggable = function(modal, handle) {
    
      var isDragging = false;
    
      var startX = 0,
        startY = 0,
    
        left = 0,
        top = 0;
    
      var dragStart = function(e) {
    
        var e = e || window.event;
    
        e.preventDefault();
    
        isDragging = true;
    
        startX = e.clientX;
        startY = e.clientY;
    
        left = $(modal).offset().left;
        top = $(modal).offset().top;
    
      }
    
      var dragMove = function(e) {
    
        var e = e || window.event;
    
        e.preventDefault();
    
        if (isDragging) {
    
          var endX = e.clientX,
            endY = e.clientY,
    
            relativeX = endX - startX,
            relativeY = endY - startY;
    
          $(modal).css({
            left: relativeX + left + 'px',
            top: relativeY + top + 'px'
          });
    
        }
    
        return false;
    
      }
    
      var dragEnd = function(e) {
    
        isDragging = false;
    
      }
    
      $(handle).on('mousedown', dragStart);
    
      $(document).on('mousemove', dragMove);
    
      $(document).on('mouseup', dragEnd);
    }

    使用方法

    演示 Demo HTML

    <div class="modal" id="modal">
      <div class="modal-header">
        <button class="btn-close"><i class="fa fa-times"></i></button>
      </div>
      <div class="modal-body"></div>
    </div>

    演示 Demo CSS

    .modal {
      position: fixed;
      top: 100px;
      left: 100px;
      width: 300px;
      border: 1px solid #aaa;
      padding: 3px;
      border-radius: 5px;
    }
    
    .modal-header {
      height: 24px;
      line-height: 24px;
      background-color: #ddd;
      color: #222;
      padding: 5px;
      border-radius: 3px;
    }
    
    .modal-body {
      height: 100px;
    }
    
    .btn-close {
      width: 24px;
      height: 24px;
      float: right;
      padding: 3px;
    }

    演示 Demo JS

    draggable('#modal', '#modal .modal-header');

     我们可以通过第二个参数指定不同的拖拽元素,比如可以指定整个 modal 为拖拽元素

    draggable('#modal','#modal');

    拖拽问题

    整个拖拽功能并没有太大的问题,但是如果我们拖拽关闭按钮,仍然可以拖拽整个 modal,看起来不太和谐而且在某些情况下会影响功能,所以我们需要排除掉关闭按钮。

    排除特定元素的方法

    关于如何排除特定元素的方法,很多人会推荐阻止冒泡的方法,但是我试了很多次,这种方法是不行的,因为拖拽事件绑定在了 document 对象上。解决的方法就是在拖拽开始时添加限制条件,代码如下

    ...
      var dragStart = function(e) {
    
        var e = e || window.event;
    
        e.preventDefault();
    
        // 获取需要排除的元素
        var elemCancel = $(e.target).closest(element);
        // 如果拖拽的是排除元素,函数返回
        if (elemCancel.length) {
          return true;
        }
    
        isDragging = true;
    
        startX = e.clientX;
        startY = e.clientY;
    
        left = $(modal).offset().left;
        top = $(modal).offset().top;
    
      }
    ...

    为什么使用 closest() 方法呢?因为我们在排除特定元素的同时也要排除它的子元素。如果使用原生 JS 的话,需要添加获取子元素的方法。以下是完整代码:

    /**
     * [draggable 拖拽方法]
     * @param  {[type]} modal  [移动元素]
     * @param  {[type]} handle [拖拽元素]
     * @param  {[type]} cancle [排除元素]
     */
    var draggable = function(modal, handle, cancle) {
    
      var isDragging = false;
    
      var startX = 0,
        startY = 0,
    
        left = 0,
        top = 0;
    
      var dragStart = function(e) {
    
        var e = e || window.event;
    
        e.preventDefault();
    
        // 获取需要排除的元素
        var elemCancel = $(e.target).closest(cancle);
        // 如果拖拽的是排除元素,函数返回
        if (elemCancel.length) {
          return true;
        }
    
        isDragging = true;
    
        startX = e.clientX;
        startY = e.clientY;
    
        left = $(modal).offset().left;
        top = $(modal).offset().top;
    
      }
    
      var dragMove = function(e) {
    
        var e = e || window.event;
    
        e.preventDefault();
    
        if (isDragging) {
    
          var endX = e.clientX,
            endY = e.clientY,
    
            relativeX = endX - startX,
            relativeY = endY - startY;
    
          $(modal).css({
            left: relativeX + left + 'px',
            top: relativeY + top + 'px'
          });
    
        }
    
        return false;
    
      }
    
      var dragEnd = function(e) {
    
        isDragging = false;
    
      }
    
      $(handle).on('mousedown', dragStart);
    
      $(document).on('mousemove', dragMove);
    
      $(document).on('mouseup', dragEnd);
    }
    View Code

    上面的案例的 JS 修改如下:

    draggable('#modal','#modal .modal-header', '#modal .btn-close');

    总结

    其实这个拖拽案例算是 jquery ui 拖拽功能的简单实现。仍然是之前的老话,实现一个功能并不困难,但是如果要把这个功能做好,我们需要考虑很多的细节,或许很多时候我们都把时间花费在调整细节上了。

  • 相关阅读:
    mysql 函数 存储过程 事件(event) job 模板
    protobuf 无proto 解码 decode 语言 java python
    mitmproxy fiddler 抓包 填坑
    android adb 常用命令
    android机器人 模拟 踩坑过程
    RabbitMQ添加新用户并支持远程访问
    Windows下RabbitMQ安装及配置
    Java mybatis mysql 常用数据类型对应关系
    easyExcel 踩坑
    linux防火墙查看状态firewall、iptable
  • 原文地址:https://www.cnblogs.com/nzbin/p/8158440.html
Copyright © 2011-2022 走看看