js实现拖拽

Posted viibo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js实现拖拽相关的知识,希望对你有一定的参考价值。

下面来说下实现这个拖拽的各个层次

Level 1 拖拽起来
使用原生方式实现拖拽,有几个基础的知识点要清楚

mousedown
mousemove
mouseup
能想到这三个事件说明是有大体的思路的;

offsetLeft
offsetTop
clientLeft
clientTop
看到这几个概念,估计有些懵了,因为可能我们写代码的时候,大部分时间都用不到这几个;先不具体说这四个概念,我们先分析拖拽的思路然后娓娓道来;

拖拽的思路很简单,鼠标移动的时候,让div跟上鼠标, 那最简单的,让div的position是absolute的,他的left和top不停地更替为鼠标目前的坐标即可;

那么鼠标的坐标怎么表示呢?
神器来了,就是鼠标事件的clientX和clientY,OK~ 那么就把每次的clientX和clientY付给div的left和top就好啦,每次结束的时候保留当前的位置即可;

但是实现之后会发现拖拽的时候div总是往右下方移动一下,才随着鼠标去移动,为什么会这样呢?
这就是鼠标事件的offsetX,offsetY,offsetX和offsetY就是鼠标指针位置相对于触发事件的对象的 x 和y坐标。

好了,组装一下上面的事件和方法,就好了,代码如下:

~function(){

let container = document.getElementById(\'container\');
[originX , originY ,dragTag]= [ 0, 0 ,false];

container.addEventListener(\'mousedown\', startDarg);
container.addEventListener(\'mousemove\', onDragging);
container.addEventListener(\'mouseup\'  , endDrag);


function startDarg(e) {

    dragTag = true;
    let {offsetX , offsetY }  = e ; 

    [ originX , originY ] = [offsetX ,offsetY];
        
}

function onDragging(e) {
    if(dragTag){

        let left = +(e.clientX  - originX) ;
        let top  = +(e.clientY  - originY) ; 
         
        container.style.left = left + \'px\';
        container.style.top  = top  + \'px\';
    }
}
function endDrag (e){

    if(dragTag){
        dragTag = false ;
    }
}

}()
好了,这样就愉快的拖拽起来了~

但是瞬间也发现问题了,我甩起来飞起来拖,div块块就会跟不上鼠标了;而且我拖一拖的就跑到看不到的窗口区域去了, 往右边,往下面拖超过窗口区域,好歹还有滚轮,滚过去能找到,但是往上面,左边,拖出去就没有啦!

能够意识到这些问题并且解决就是level2啦,下面进入

Level2 解决拖拽延迟和拖拽边界问题
(1) 拖拽延迟
首先要解释下为什么会有拖拽延迟
鼠标移动过快时, 鼠标移动出了div的范围,要再计算div的left和top就会出现延缓,解决方法就是把mousemove和mouesup绑定在document上即可;

this.ele.addEventListener(\'mousedown\', startDarg);
document.addEventListener(\'mousemove\',onDragging);
document.addEventListener(\'mouseup\' , endDrag);
解决完拖拽延迟的问题,下面就是拖拽边界的问题

(2) 边界问题
边界问题主要解决的是上面和左边的问题;

let left = +(e.clientX - e.offsetX) ;
let top = +(e.clientY - e.offsetY) ;
[left , top] = [ Math.max(0, left), Math.max(0, top) ] ;
当left和top小于零的时候,重置为0

好了,到这里就基本上就能解决大部分问题了;基本上可以无bug运行了;(兼容性的问题本篇不重点说明,毕竟用的是es6,IE本省很多都是没有支持的)

下面想想这样拖拽只绑定在了一个元素上,如果想新增一个拖拽的元素;怎么办?这个问题抛出来就是为了往封装上去想。

Level3 封装起来
以合理的方式封装必要内容个人认为是从功能开发进阶到底层开发最有效和简单的方式,能在开发中思考别人用我的东西如何用能更好用是应该逐渐锻炼起来的。

js的封装不想其他语言那么顺畅,但自从es6出来之后,有个class出现后封装变得更为方便,当然,更为支持用一些设计模式去搞定,毕竟标题是原生,用es6有点赖皮,class实现如下

class Drag{

constructor(ele){

    this.ele  = ele ;
    [this.originX , this.originY ,this.dragTag]= [ 0, 0 ,false];

    this.ele.addEventListener(\'mousedown\', this.startDarg.bind(this));
    document.addEventListener(\'mousemove\', this.onDragging.bind(this));
    document.addEventListener(\'mouseup\'  , this.endDrag.bind(this));
}

startDarg(e) {

    e = e || window.event ; 

    this.dragTag = true;
    let {offsetX , offsetY }  = e ; 

    [ this.originX , this.originY ] = [offsetX ,offsetY];
        
}

onDragging(e) {

    e = e || window.event ; 

    if(this.dragTag){
        let left = +(e.clientX  - this.originX) ;
        let top  = +(e.clientY  - this.originY) ; 

        let {clientWidth , clientHeight } = document.body;

        [clientWidth , clientHeight]  = [clientWidth - this.ele.clientWidth , clientHeight - this.ele.clientHeight] ; 

        [left , top]   = [  Math.max(0, left), Math.max(0, top) ] ;
        [left , top]   = 
        [ Math.min(clientWidth, left),  Math.min(clientHeight, top) ]  
         
        if(this.validatePos(left ,top)){
            this.ele.style.left = left + \'px\';
            this.ele.style.top  = top  + \'px\';

        }
    }
}
endDrag (e){

    e = e || window.event ; 

    if(this.dragTag){
        document.removeEventListener(\'mousemove\',() => {});
        document.removeEventListener(\'mouseup\',() => {});
        this.dragTag = false ;
    }
}


validatePos(left ,top)  {

    if(Number.isNaN(left) || Number.isNaN(top)){
        return false;
    }
    return true ;
}

}
这样的话,只要声明为每一个要拖拽的对象,声明自己独立的拖动对象即可

let container = document.getElementById(\'container\');
let dargObj = new Drag(container);

以上是关于js实现拖拽的主要内容,如果未能解决你的问题,请参考以下文章

纯js实现DIV拖拽

JS拖拽效果的原理及实现

vuejs2.0使用Sortable.js实现的拖拽功能( 转)

拖拽系列利用JS面向对象OOP思想实现拖拽封装

js实现拖拽

js拖拽问题,求大神详解