亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

JS拖拽插件實現步驟

2019-11-20 11:56:43
字體:
來源:轉載
供稿:網友

這篇文章詳細介紹了JS拖拽插件的實現步驟,主要從以下六步做詳細分析,具體內容如下:

一、js拖拽插件的原理
二、根據原理實現的最基本效果
三、代碼抽象與優化
四、擴展:有效的拖拽元素
五、性能優化和總結
六、jquery插件化
js拖拽是常見的網頁效果,本文將從零開始實現一個簡單的js插件。


一、js拖拽插件的原理
常見的拖拽操作是什么樣的呢?整過過程大概有下面幾個步驟:

  1、用鼠標點擊被拖拽的元素

  2、按住鼠標不放,移動鼠標

  3、拖拽元素到一定位置,放開鼠標

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

  1、用鼠標點擊被拖拽的元素觸發onmousedown

   ?。?)設置當前元素的可拖拽為true,表示可以拖拽

   ?。?)記錄當前鼠標的坐標x,y

   ?。?)記錄當前元素的坐標x,y

  2、移動鼠標觸發onmousemove

   ?。?)判斷元素是否可拖拽,如果是則進入步驟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元素上而不是拖拽元素本身,這樣能解決快速拖動造成的延遲或停止移動的問題

代碼如下:

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,傳入被拖拽的元素。

首先對一些常用的方法進行簡單的封裝:

; (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:

 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坐標:  

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事件,整合上面的代碼如下:     

 ; (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方法如下:

 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函數如下

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方法來操作

 ; (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拖拽插件實現步驟的詳細介紹,希望對大家有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲性夜色噜噜噜7777| 国产精品一区二区三| 美女久久久久久久| 亚洲欧美日韩视频一区| 国产一区二区av| 亚洲精品在线看| 欧美黄色免费网站| 北条麻妃一区二区在线观看| 亚洲二区中文字幕| 亚洲欧美日韩另类| 日韩一区二区在线视频| 久久精品一区中文字幕| 成人网在线免费观看| 狠狠躁夜夜躁人人爽天天天天97| 正在播放亚洲1区| 色偷偷偷亚洲综合网另类| 亚洲天堂成人在线视频| 国产成人精品优优av| 成人欧美在线观看| 国产一区二区三区在线观看视频| 成人妇女免费播放久久久| 久久久久免费精品国产| 九九久久精品一区| 欧美怡红院视频一区二区三区| 成人欧美在线视频| 91精品国产91| 欧美日韩aaaa| 国产精品高清在线| 成人激情视频在线观看| 中文字幕亚洲天堂| 国产精品视频大全| 在线电影欧美日韩一区二区私密| 色妞色视频一区二区三区四区| 日韩精品中文字幕在线播放| 亚洲第一二三四五区| 久久久久久久一| 欧美色视频日本版| 2019国产精品自在线拍国产不卡| 麻豆精品精华液| 国产成人精品电影| 成人欧美一区二区三区在线| 国产精品av在线播放| 国产成+人+综合+亚洲欧洲| 97在线观看免费高清| 国内揄拍国内精品少妇国语| 成人精品视频在线| 亚洲aa中文字幕| 97人人模人人爽人人喊中文字| 成人网在线观看| 国产一区二区三区精品久久久| 国内免费久久久久久久久久久| 色樱桃影院亚洲精品影院| 狠狠色香婷婷久久亚洲精品| 欧美日韩中国免费专区在线看| 91精品久久久久久久久久另类| 2019中文字幕在线观看| 久久视频国产精品免费视频在线| 日韩高清电影好看的电视剧电影| 青青草原成人在线视频| 国产成人综合亚洲| 成人黄色av播放免费| 性色av一区二区三区在线观看| 亚洲18私人小影院| 亚洲成人免费在线视频| 92看片淫黄大片欧美看国产片| 成人午夜两性视频| 亚洲欧美综合v| 久久精品在线播放| 国产有码一区二区| 成人激情免费在线| 亚洲美女福利视频网站| 国产成人精品电影| 精品久久久999| 欧美俄罗斯性视频| 日韩av在线免费观看| 亚洲在线第一页| 国产精品普通话| 欧美极品少妇xxxxⅹ免费视频| 国产欧美亚洲精品| 午夜精品一区二区三区av| 亚洲欧美第一页| 日韩国产高清污视频在线观看| 色综合伊人色综合网站| 国产一区二区三区高清在线观看| 午夜精品久久久久久99热软件| 黑人精品xxx一区| 国产成人激情小视频| 国产成人aa精品一区在线播放| 亚洲欧美另类自拍| 国产亚洲精品久久久优势| 亚洲欧美制服第一页| 亚洲片在线资源| 欧美视频在线观看免费网址| 欧美激情xxxx| 亚洲精品成人久久久| 91夜夜未满十八勿入爽爽影院| 国产精品草莓在线免费观看| 亚洲精品一二区| 国产精品白嫩美女在线观看| 亚洲福利影片在线| 成人免费福利视频| 久久免费视频在线观看| 韩国国内大量揄拍精品视频| 精品久久久久久久久久久| 在线观看国产成人av片| 国产精品久久久久久av| 高清亚洲成在人网站天堂| 国产成人高清激情视频在线观看| 久久亚洲精品国产亚洲老地址| 午夜精品久久久久久久99热| 中文字幕av一区二区| 色视频www在线播放国产成人| 久久精品视频va| 欧美色另类天堂2015| 国语自产精品视频在线看一大j8| 日韩精品亚洲精品| 福利视频导航一区| 国产精品日韩在线| 久久这里只有精品视频首页| 国产精品一久久香蕉国产线看观看| 中文字幕欧美视频在线| 亚洲片在线观看| 国产999精品视频| 欧美网站在线观看| 亚洲欧美日韩久久久久久| 久久精品亚洲国产| 欧美国产视频一区二区| 国产精品视频久久| 国产综合福利在线| 亚洲国产精品成人va在线观看| 欧美成人精品在线播放| 日本中文字幕成人| 久久久亚洲福利精品午夜| 中文字幕亚洲色图| 亚洲精品日韩欧美| 国产精品扒开腿做爽爽爽的视频| 亚洲欧美日韩中文在线制服| 久久久精品2019中文字幕神马| 国产激情综合五月久久| 国产日韩欧美夫妻视频在线观看| 久久久成人精品| 日韩美女在线观看| 欧美激情videoshd| 98精品国产自产在线观看| 91欧美日韩一区| 欧美视频13p| 97色在线播放视频| 欧美亚洲成人xxx| 欧美xxxx18国产| 国产精品一区二区女厕厕| 欧美在线视频一区二区| 欧洲s码亚洲m码精品一区| 日韩av影院在线观看| 中文字幕自拍vr一区二区三区| 欧美日韩国产一区二区| 亚洲午夜性刺激影院| 亚洲美女免费精品视频在线观看| 在线国产精品播放| 亚洲免费电影一区| 精品欧美国产一区二区三区| 亚洲香蕉av在线一区二区三区| 丝袜亚洲欧美日韩综合| 国产国产精品人在线视| 亚洲精品久久久久久久久久久|