• JS拖拽插件实现步骤


    实现JS拖拽插件主要从六个方面做介绍:一、js拖拽插件的原理,二、根据原理实现的最基本效果,三、代码抽象与优化,四、扩展:有效的拖拽元素,五、性能优化和总结,六、jquery插件化 ,需要的朋友可以参考下
     
     

    这篇文章详细介绍了JS拖拽插件的实现步骤,主要从以下六步做详细分析,具体内容如下:

    一、js拖拽插件的原理
    二、根据原理实现的最基本效果
    三、代码抽象与优化
    四、扩展:有效的拖拽元素
    五、性能优化和总结
    六、jquery插件化
    js拖拽是常见的网页效果,本文将从零开始实现一个简单的js插件。


    一、js拖拽插件的原理
    常见的拖拽操作是什么样的呢?整过过程大概有下面几个步骤:

      1、用鼠标点击被拖拽的元素

      2、按住鼠标不放,移动鼠标

      3、拖拽元素到一定位置,放开鼠标

    这里的过程涉及到三个dom事件:onmousedown,onmousemove,onmouseup。所以拖拽的基本思路就是:

      1、用鼠标点击被拖拽的元素触发onmousedown

        (1)设置当前元素的可拖拽为true,表示可以拖拽

        (2)记录当前鼠标的坐标x,y

        (3)记录当前元素的坐标x,y

      2、移动鼠标触发onmousemove

        (1)判断元素是否可拖拽,如果是则进入步骤2,否则直接返回

        (2)如果元素可拖拽,则设置元素的坐标

          元素的x坐标 = 鼠标移动的横向距离+元素本来的x坐标 = 鼠标现在的x坐标 - 鼠标之前的x坐标 + 元素本来的x坐标

          元素的y坐标 = 鼠标移动的横向距离+元素本来的y坐标 = 鼠标现在的y坐标 - 鼠标之前的y坐标 + 元素本来的y坐标

      3、放开鼠标触发onmouseup

        (1)将鼠标的可拖拽状态设置成false

    回到顶部
    二、根据原理实现的最基本效果
    在实现基本的效果之前,有几点需要说明的:

      1、元素想要被拖动,它的postion属性一定要是relative或absolute

      2、通过event.clientX和event.clientY获取鼠标的坐标

      3、onmousemove是绑定在document元素上而不是拖拽元素本身,这样能解决快速拖动造成的延迟或停止移动的问题

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    var dragObj = document.getElementById("test");
       dragObj.style.left = "px";
       dragObj.style.top = "px";
      
       var mouseX, mouseY, objX, objY;
       var dragging = false;
      
       dragObj.onmousedown = function (event) {
        event = event || window.event;
      
        dragging = true;
        dragObj.style.position = "relative";
      
      
        mouseX = event.clientX;
        mouseY = event.clientY;
        objX = parseInt(dragObj.style.left);
        objY = parseInt(dragObj.style.top);
       }
      
       document.onmousemove = function (event) {
        event = event || window.event;
        if (dragging) {
      
         dragObj.style.left = parseInt(event.clientX - mouseX + objX) + "px";
         dragObj.style.top = parseInt(event.clientY - mouseY + objY) + "px";
        }
      
       }
      
       document.onmouseup = function () {
        dragging = false;
       }


    三、代码抽象与优化
    上面的代码要做成插件,要将其抽象出来,基本结构如下:
    复制代码代码如下:

     ; (function (window, undefined) {            
     
                 function Drag(ele) {}
     
                 window.Drag = Drag;
             })(window, undefined);

    用自执行匿名函数将代码包起来,内部定义Drag方法并暴露到全局中,直接调用Drag,传入被拖拽的元素。

    首先对一些常用的方法进行简单的封装:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    ; (function (window, undefined) {
        var dom = {
         //绑定事件
         on: function (node, eventName, handler) {
          if (node.addEventListener) {
           node.addEventListener(eventName, handler);
          }
          else {
           node.attachEvent("on" + eventName, handler);
          }
         },
         //获取元素的样式
         getStyle: function (node, styleName) {
          var realStyle = null;
          if (window.getComputedStyle) {
           realStyle = window.getComputedStyle(node, null)[styleName];
          }
          else if (node.currentStyle) {
           realStyle = node.currentStyle[styleName];
          }
          return realStyle;
         },
         //获取设置元素的样式
         setCss: function (node, css) {
          for (var key in css) {
           node.style[key] = css[key];
          }
         }
        };
        window.Drag = Drag;
       })(window, undefined);

    在一个拖拽操作中,存在着两个对象:被拖拽的对象和鼠标对象,我们定义了下面的两个对象以及它们对应的操作:

    首先的拖拽对象,它包含一个元素节点和拖拽之前的坐标x和y:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function DragElement(node) {
        this.node = node;//被拖拽的元素节点
        this.x = ;//拖拽之前的x坐标
        this.y = ;//拖拽之前的y坐标
       }
       DragElement.prototype = {
        constructor: DragElement,
        init: function () {    
         this.setEleCss({
          "left": dom.getStyle(node, "left"),
          "top": dom.getStyle(node, "top")
         })
         .setXY(node.style.left, node.style.top);
        },
        //设置当前的坐标
        setXY: function (x, y) {
         this.x = parseInt(x) || ;
         this.y = parseInt(y) || ;
         return this;
        },
        //设置元素节点的样式
        setEleCss: function (css) {
         dom.setCss(this.node, css);
         return this;
        }
       }

    还有一个对象是鼠标,它主要包含x坐标和y坐标:  

    1
    2
    3
    4
    5
    6
    7
    8
    function Mouse() {
         this.x = ;
         this.y = ;
        }
        Mouse.prototype.setXY = function (x, y) {
         this.x = parseInt(x);
         this.y = parseInt(y);
        

    这是在拖拽操作中定义的两个对象。

    如果一个页面可以有多个拖拽元素,那应该注意什么:

    1、每个元素对应一个拖拽对象实例

    2、每个页面只能有一个正在拖拽中的元素

    为此,我们定义了唯一一个对象用来保存相关的配置:

    复制代码代码如下:

    var draggableConfig = {
                     zIndex: ,
                     draggingObj: null,
                     mouse: new Mouse()
                 };

    这个对象中有三个属性:

    (1)zIndex:用来赋值给拖拽对象的zIndex属性,有多个拖拽对象时,当两个拖拽对象重叠时,会造成当前拖拽对象有可能被挡住,通过设置zIndex使其显示在最顶层

    (2)draggingObj:用来保存正在拖拽的对象,在这里去掉了前面的用来判断是否可拖拽的变量,通过draggingObj来判断当前是否可以拖拽以及获取相应的拖拽对象

    (3)mouse:唯一的鼠标对象,用来保存当前鼠标的坐标等信息

    最后是绑定onmousedown,onmouseover,onmouseout事件,整合上面的代码如下:     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    ; (function (window, undefined) {
       var dom = {
        //绑定事件
        on: function (node, eventName, handler) {
         if (node.addEventListener) {
          node.addEventListener(eventName, handler);
         }
         else {
          node.attachEvent("on" + eventName, handler);
         }
        },
        //获取元素的样式
        getStyle: function (node, styleName) {
         var realStyle = null;
         if (window.getComputedStyle) {
          realStyle = window.getComputedStyle(node, null)[styleName];
         }
         else if (node.currentStyle) {
          realStyle = node.currentStyle[styleName];
         }
         return realStyle;
        },
        //获取设置元素的样式
        setCss: function (node, css) {
         for (var key in css) {
          node.style[key] = css[key];
         }
        }
       };
       //#region 拖拽元素类
       function DragElement(node) {
        this.node = node;
        this.x = ;
        this.y = ;
       }
       DragElement.prototype = {
        constructor: DragElement,
        init: function () {    
         this.setEleCss({
          "left": dom.getStyle(node, "left"),
          "top": dom.getStyle(node, "top")
         })
         .setXY(node.style.left, node.style.top);
        },
        setXY: function (x, y) {
         this.x = parseInt(x) || ;
         this.y = parseInt(y) || ;
         return this;
        },
        setEleCss: function (css) {
         dom.setCss(this.node, css);
         return this;
        }
       }
       //#endregion
       //#region 鼠标元素
       function Mouse() {
        this.x = ;
        this.y = ;
       }
       Mouse.prototype.setXY = function (x, y) {
        this.x = parseInt(x);
        this.y = parseInt(y);
       }
       //#endregion
       //拖拽配置
       var draggableConfig = {
        zIndex: ,
        draggingObj: null,
        mouse: new Mouse()
       };
       function Drag(ele) {
        this.ele = ele;
        function mouseDown(event) {
         var ele = event.target || event.srcElement;
         draggableConfig.mouse.setXY(event.clientX, event.clientY);
         draggableConfig.draggingObj = new DragElement(ele);
         draggableConfig.draggingObj
          .setXY(ele.style.left, ele.style.top)
          .setEleCss({
           "zIndex": draggableConfig.zIndex++,
           "position": "relative"
          });
        }   
        ele.onselectstart = function () {
         //防止拖拽对象内的文字被选中
         return false;
        }
        dom.on(ele, "mousedown", mouseDown);
       }
       dom.on(document, "mousemove", function (event) {
        if (draggableConfig.draggingObj) {
         var mouse = draggableConfig.mouse,
          draggingObj = draggableConfig.draggingObj;
         draggingObj.setEleCss({
          "left": parseInt(event.clientX - mouse.x + draggingObj.x) + "px",
          "top": parseInt(event.clientY - mouse.y + draggingObj.y) + "px"
         });
        }
       })
       dom.on(document, "mouseup", function (event) {
        draggableConfig.draggingObj = null;
       })
       window.Drag = Drag;
      })(window, undefined);

    调用方法:Drag(document.getElementById("obj"));

    注意的一点,为了防止选中拖拽元素中的文字,通过onselectstart事件处理程序return false来处理这个问题。


    四、扩展:有效的拖拽元素
    我们常见的一些拖拽效果很有可能是这样的:

    弹框的顶部是可以进行拖拽操作的,内容区域是不可拖拽的,怎么实现这样的效果呢:

    首先优化拖拽元素对象如下,增加一个目标元素target,表示被拖拽对象,在上图的登录框中,就是整个登录窗口。

    被记录和设置坐标的拖拽元素就是这个目标元素,但是它并不是整个部分都是拖拽的有效部分。我们在html结构中为拖拽的有效区域添加类draggable表示有效拖拽区域:


        

    复制代码代码如下:

    <div id="obj" class="dialog" style="position:relative;left:px">
             <div class="header draggable">
                 拖拽的有效元素
             </div>
             <div class="content">
                 拖拽对象
             </div>
         </div>

    然后修改Drag方法如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function drag(ele) {
     var dragNode = (ele.querySelector(".draggable") || ele);
     dom.on(dragNode, "mousedown", function (event) {
      var dragElement = draggableConfig.dragElement = new DragElement(ele);
     
      draggableConfig.mouse.setXY(event.clientX, event.clientY);
      draggableConfig.dragElement
       .setXY(dragElement.target.style.left, dragElement.target.style.top)
       .setTargetCss({
        "zIndex": draggableConfig.zIndex++,
        "position": "relative"
       });
     }).on(dragNode, "mouseover", function () {
      dom.setCss(this, draggableStyle.dragging);
     }).on(dragNode, "mouseout", function () {
      dom.setCss(this, draggableStyle.defaults);
     });
    }

    主要修改的是绑定mousedown的节点变成了包含draggable类的有效元素,如果不含有draggable,则整个元素都是有效元素。


    五、性能优化和总结
    由于onmousemove在一直调用,会造成一些性能问题,我们可以通过setTimout来延迟绑定onmousemove事件,改进move函数如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function move(event) {
       if (draggableConfig.dragElement) {
        var mouse = draggableConfig.mouse,
         dragElement = draggableConfig.dragElement;
        dragElement.setTargetCss({
         "left": parseInt(event.clientX - mouse.x + dragElement.x) + "px",
         "top": parseInt(event.clientY - mouse.y + dragElement.y) + "px"
        });
      
        dom.off(document, "mousemove", move);
        setTimeout(function () {
         dom.on(document, "mousemove", move);
        }, );
       }
      }

    总结:

    整个拖拽插件的实现其实很简单,主要是要注意几点

      1、实现思路:元素拖拽位置的改变就等于鼠标改变的距离,关键在于获取鼠标的变动和元素原本的坐标

          2、通过setTimeout来延迟加载onmousemove事件来提供性能


    六、jquery插件化
    简单地将其封装成jquery插件,主要是相关的dom方法替换成jquery方法来操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    ; (function ($, window, undefined) {
     //#region 拖拽元素类
     function DragElement(node) {
     
      this.target = node;
     
      node.onselectstart = function () {
       //防止拖拽对象内的文字被选中
       return false;
      }
     }
     DragElement.prototype = {
      constructor: DragElement,
      setXY: function (x, y) {
       this.x = parseInt(x) || ;
       this.y = parseInt(y) || ;
       return this;
      },
      setTargetCss: function (css) {
       $(this.target).css(css);
       return this;
      }
     }
     //#endregion
     
     //#region 鼠标元素
     function Mouse() {
      this.x = ;
      this.y = ;
     }
     Mouse.prototype.setXY = function (x, y) {
      this.x = parseInt(x);
      this.y = parseInt(y);
     }
     //#endregion
     
     //拖拽配置
     var draggableConfig = {
      zIndex: ,
      dragElement: null,
      mouse: new Mouse()
     };
     
     var draggableStyle = {
      dragging: {
       cursor: "move"
      },
      defaults: {
       cursor: "default"
      }
     }
     
     var $document = $(document);
     
     function drag($ele) {
      var $dragNode = $ele.find(".draggable");
      $dragNode = $dragNode.length > ? $dragNode : $ele;
       
     
      $dragNode.on({
       "mousedown": function (event) {
        var dragElement = draggableConfig.dragElement = new DragElement($ele.get());
     
        draggableConfig.mouse.setXY(event.clientX, event.clientY);
        draggableConfig.dragElement
         .setXY(dragElement.target.style.left, dragElement.target.style.top)
         .setTargetCss({
          "zIndex": draggableConfig.zIndex++,
          "position": "relative"
         });
       },
       "mouseover": function () {
        $(this).css(draggableStyle.dragging);
       },
       "mouseout": function () {
        $(this).css(draggableStyle.defaults);
       }
      })
     }
     
     function move(event) {
      if (draggableConfig.dragElement) {
       var mouse = draggableConfig.mouse,
        dragElement = draggableConfig.dragElement;
       dragElement.setTargetCss({
        "left": parseInt(event.clientX - mouse.x + dragElement.x) + "px",
        "top": parseInt(event.clientY - mouse.y + dragElement.y) + "px"
       });
     
       $document.off("mousemove", move);
       setTimeout(function () {
        $document.on("mousemove", move);
       }, );
      }
     }
     
     $document.on({
      "mousemove": move,
      "mouseup": function () {
       draggableConfig.dragElement = null;
      }
     });
     
     $.fn.drag = function (options) {
      drag(this);
     }
     
    })(jQuery, window, undefined)

    以上就是本文对JS拖拽插件实现步骤的详细介绍,希望对大家有所帮助。

  • 相关阅读:
    GitHub 源码,Framework 框架
    转int啥啥啥的
    查看apk签名 和 keystore 的信息
    一次apk打开时报内存溢出错误,故写下内存溢出的各种原因和解决方法
    客户端传值里面包含URL特殊字符的应对方法
    Linux全硬盘搜索文件名是xxxxx的命令
    pythonmysql运行报错解决过程中遇到的其中一个报错解决文章来源
    linux查看硬盘占用情况
    Linux使用nginx反向代理。可实现域名指向特定端口
    Linux下使用yum安装软件命令
  • 原文地址:https://www.cnblogs.com/lpw94/p/4976796.html
Copyright © 2020-2023  润新知