原生js实现拖拽功能

在前端技术日新月异,飞速发展的当下,涌现出了很多优秀的开源框架以及优秀的开源组件,这些都是优秀的前端开发者的技术成果。当然,虽然有这么多现成的开源技术成果供我们再开发中使用,但我们不能仅抱着拿来主义的态度,只顾拿来用就行,更多的是要以学习的心态来对待开源技术,对待前端世界,要多汲取他(她)人的经验,且又不忘根本(基础知识),站在巨人的肩膀上继续前行!

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哈!**

原创文章,站在前辈们的经验上的总结,文中如有不正之处,还望指正!

你可能感兴趣的:(原生js实现拖拽功能)