原生js實現拖拽功能

weixin_34185364發表於2017-04-21
在前端技術日新月異,飛速發展的當下,湧現出了很多優秀的開源框架以及優秀的開源元件,這些都是優秀的前端開發者的技術成果。當然,雖然有這麼多現成的開源技術成果供我們再開發中使用,但我們不能僅抱著拿來主義的態度,只顧拿來用就行,更多的是要以學習的心態來對待開源技術,對待前端世界,要多汲取他(她)人的經驗,且又不忘根本(基礎知識),站在巨人的肩膀上繼續前行!

js拖拽功能

拖拽功能是前端很多業務場景都能使用到的一種普遍的技術,比如彈窗視口的拖拽等,前端世界的很多優秀框架元件都擁有封裝完美的拖拽功能,別人封裝的優秀原始碼,健壯,穩定,同時又優雅美觀,自然是值得我們去學習的。這篇文章主要講解下如何用原生js實現一個簡單的拖拽功能。

拖拽原理

對於PC端來說,拖拽功能無非就是滑鼠點選,滑鼠開始移動,滑鼠鬆開三個步驟,當然這三個步驟裡面有拆分了很多的細節,越是健壯,穩定的程式碼,對細節的處理就越嚴謹(我們主要講實現一個簡單的拖拽功能,可能有些細節處理得不妥當,待以後再次進行封裝)。

  • 滑鼠點選:當滑鼠按下點選的時候,需要拖拽的容器就已應該準備就緒 進去拖拽狀態了

  • 滑鼠移動:需要拖拽的容器根據滑鼠的移動位置而移動,這裡面就包含的很多對細節的處理,如:當容器某一端的位置到達了瀏覽器邊緣的時候,是不應該超出瀏覽器範圍區域的,不然會撐出滾動條或者被遮擋,這不是一個很好的效果。那麼要如何把容器的位置控制在瀏覽器規定的範圍區域呢?這裡就要分別處理上下左右四個方向的位置變化。
    1.top端:當容器的頂部到達了瀏覽器頂部邊緣的時候,滑鼠移動的方向繼續是向上移動,那麼就要設定容器頂端的top值始終為0,保證容器位置不會溢位瀏覽器範圍。
    2.bottom端:當容器的底部到達了瀏覽器底部邊緣的時候,滑鼠移動的方向繼續是向下移動,那麼就要設定容器底端的bottom值始終為瀏覽器可視區域的高度值減去容器的高度值,保證容器位置不會溢位瀏覽器範圍。
    3.left端:當容器的左端到達了瀏覽器左端邊緣的時候,滑鼠移動的方向繼續是向左移動,那麼就要設定容器頂端的left值始終為0,保證容器位置不會溢位瀏覽器範圍。
    3.right端:當容器的右端到達了瀏覽器右端邊緣的時候,滑鼠移動的方向繼續是向右移動,那麼就要設定容器頂端的right值始終為瀏覽器可視區域的寬度值減去容器的寬度值,保證容器位置不會溢位瀏覽器範圍。

  • 滑鼠鬆開:代表著容器拖拽結束,停止改變容器的位置。這裡也有個小細節需要注意下,就是,滑鼠點選容器準備拖拽時候的位置要和滑鼠鬆開後滑鼠在容器中的位置是一致的,意思就是在拖拽的過程當中不管滑鼠的位置在什麼地方,停止拖拽後都要回到原點。

介面引數暴露

完美的封裝往往都是需要搭配強大的配置引數來維護它的健壯,穩定的。

對於拖拽功能,需要配置的引數通常需要有以下內容:

  • 需要拖拽的容器(必選)

  • 需要拖拽的區域(可選)

  • 是否可拖拽,拖拽開關(可選)

  • 是否需要虛擬拖拽容器(可選)

  • 控制虛擬拖拽容器的樣式(可選)

配置上這些引數,一個簡單的拖拽功能就可以使用了。

拖拽示例核心程式碼

呼叫方式

new DragView({
    "dragWrap": document.getElementById("drag_wrap"),    //容器,必選
    "dragableArea": document.getElementById("drag_area"),  //可拖拽區域,可選
    "isDrag": true,  //是否可拖拽,可選
    "isDummyWrap": true, //是否需要虛擬拖拽框,可選
    "dummyWrapClass": "dragview_dummy_wrap2" //控制虛擬拖拽框的樣式,可選
})

封裝的部分程式碼

DragView.prototype = {
        "constructor": DragView,
        "init": function(){
            var that = this;
            var dragMove = document.createElement("div");
            dragMove.setAttribute("class","dragview_move");
            document.body.appendChild(dragMove);
            that.options.isDrag && (that.options.dragableArea.style.cursor = "move");
            that.options.dragableArea.onmousedown = function(e){
                if(!that.options.dragStatus){
                    that.throttle(function(){
                        that.options.isDrag && that.mouseDown(e);
                    },null,0);
                }
            }.bind(that);
        },
        "getEvent": function(e){
            return e ? e : window.event;
        },
        "extend": function(setting,option){
          for(var attr in setting){
              if(typeof option[attr] != "undefined"){
                  setting[attr] = option[attr];
              }
          }
          return setting;
        },
        "throttle": function(fn,context,delay){
            clearTimeout(fn.timeoutId);
            fn.timeoutId = setTimeout(function(){
                fn.call(context);
            },delay);
        },
        "mouseDown": function(e){
            var that = this;
            var dragMoveArea = "";
            var dragWrap = that.options.dragWrap;
            var events = that.getEvent(e);
            var disX = events.clientX - dragWrap.offsetLeft;
            var disY = events.clientY - dragWrap.offsetTop;
            document.getElementsByClassName("dragview_move")[0].style.display = "block";
            dragWrap.style.position = "absolute";
            dragWrap.style.zIndex = "99999";
            that.options.tempDragWrap = that.options.dragWrap;
            if(that.options.isDummyWrap){
                dragMoveArea = document.createElement("div");
                dragMoveArea.setAttribute("class",that.options.dummyWrapClass);
                dragMoveArea.style.width = dragWrap.clientWidth + "px";
                dragMoveArea.style.height = dragWrap.clientHeight + "px";
                dragMoveArea.style.position = "absolute";
                dragMoveArea.style.zIndex = "99999";
                dragMoveArea.style.top = dragWrap.style.top;
                dragMoveArea.style.left = dragWrap.style.left;
                document.body.appendChild(dragMoveArea);
                that.options.tempDragWrap = dragMoveArea;
            }               
            that.options.dragStatus = true;
            document.onmousemove = function(e){
                that.throttle(function(){
                    var _events = that.getEvent(e);
                    that.mouseMove(_events,disX,disY,dragMoveArea);
                },null,0);
            }
            document.onmouseup = function(){
                that.options.dragStatus && that.mouseUp(dragMoveArea);
            }
        },
        "mouseMove": function(_events,disX,disY,dragMoveArea){
            if(this.options.dragStatus){
                var _x = _events.clientX - disX;
                var _y = _events.clientY - disY;
                var _winW = document.documentElement.clientWidth || document.body.clientWidth;
                var _winH=document.documentElement.clientHeight || document.body.clientHeight;
                var option = {
                    "x": _x,
                    "y": _y,
                    "winX": _winW,
                    "winY": _winH,
                    "dragW": this.options.tempDragWrap.offsetWidth,
                    "dragH": this.options.tempDragWrap.offsetHeight
                };
                this.limiteRange(option);
            }
        },
        "mouseUp": function(dragMoveArea){
            this.options.dragWrap.style.left = this.options.tempDragWrap.style.left;
            this.options.dragWrap.style.top = this.options.tempDragWrap.style.top;
            this.options.dragStatus = false;
            dragMoveArea!="" && document.body.removeChild(dragMoveArea);
            document.getElementsByClassName("dragview_move")[0].style.display = "none";
        },
        "limiteRange": function(option){
            if(option.x <= 0 || option.dragW >= option.winX){
                this.options.tempDragWrap.style.left = "0px";
            }else if((option.x + option.dragW) >= option.winX){
                this.options.tempDragWrap.style.left = (option.winX - option.dragW) + "px";
            }else{
                this.options.tempDragWrap.style.left = option.x + "px";
            }

            if(option.y <= 0 || option.dragH >= option.winY){
                this.options.tempDragWrap.style.top = "0px";
            }
            else if((option.y + option.dragH) >= option.winY){
                this.options.tempDragWrap.style.top = (option.winY - option.dragH) + "px";
            }
            else{
                this.options.tempDragWrap.style.top = option.y + "px";
            }
        }
};

顯示效果如下連結:https://webproblem.github.io/hello-world/drag-View/drag.html
具體示例及原始碼見我的 github , ** 如果喜歡,請記得Star哈!**

原創文章,站在前輩們的經驗上的總結,文中如有不正之處,還望指正!

相關文章