一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

JavaScript实现元素的拖拽特效

时间:2014-01-04 编辑:简简单单 来源:一聚教程网

DOM节点的拖拽是一个很简单的JavaScript特效,也常称作为拖放,即:Drag-and-drop。

拖拽主要涉及到三个过程:

    鼠标点击要拖放的对象,记录鼠标相对于拖动对象(left和top值)坐标
    鼠标移动事件过程中,不断改变对象的left和top值,从而出现鼠跟随效果。
    鼠标松开事件,解除鼠标移动事件。

实现拖拽的相关HTML和CSS

以下是拖拽实现的HTML代码结构:

 代码如下 复制代码

   


   

   

下面是相关的CSS

 代码如下 复制代码

    .parent {
    position: relative;
    }
    #drag {
    position: absolute;
    top: 20px;
    left: 40%;
    width: 150px;
    height: 150px;
    cursor: move;
    }

下面是一般实现拖拽的方法,其很好的说明了拖拽的三个过程:

   

 代码如下 复制代码
var objMove = function(){
    //获取要移动的对象
    var mine = document.getElementById('drag'),
    //用来存储鼠标相对于对象的位置
    dx=dy=0;
    mine.onmousedown = function(e){
    var e = e || window.event,
    x = e.offsetLeft,
    y = e.offsetTop;
    //parseInt把"5px"类的字符转化为数植5 www.111com.net
    
    dx = x - parseInt(getStyle(this,'left')),
    dy = y - parseInt(getStyle(this,'top'));
    document.onmousemove = function(e){
    var e = e || window.event,
    x = e.offsetLeft,
    y = e.offsetTop;
    mine.style.left = x - dx + 'px';
    mine.style.top = y - dy + 'px';
    };
    document.onmouseup = function(){
    //鼠标松开时,把mousemove等解除引用
    document.onmousemove = null;
    document.onmouseup = null;
    };
    };
    };
    window.onload = objMove;
    //获取obj对象当前所应用的样式
    function getStyle(obj,style){
    if(window.getComputedStyle){
    //标准浏览器
    return getComputedStyle(obj,null)[style];
    } else {
    //针对IE8及IE8以下版本的浏览器
    return obj.currentStyle[style];
    }
    };

上面的代码中getStyle函数是来获取节点最终应用的样式。
更加完善的拖拽

下面先写出一些相关的代码,getStyle已经在上面介绍过了,故不重复说明了。

在拖拽中,涉及到事件的绑定和解除绑定。由于IE与标准浏览器中事件绑定与解除的方法不太一样,所以特地声明一个对象EventUtil。

 

 代码如下 复制代码
   var EventUtil = {
    addHandler: function(element, type, handler){
    //绑定事件
    if(element.addEventListener){
    element.addEventListener(type, handler, false);
    } else if(element.attachEvent){
    element.attachEvent('on'+type,handler);
    } else {
    element['on'+type] = handler;
    }
    },
    removeHandler:function(element,type,handler){
    //解除绑定的事件
    if(element.removeEventListener){
    element.removeEventListener(type,handler,false);
    }else if(element.detachEvent){
    element.detachEvent('on'+type,handler);
    }else {
    element['on'+type] = null;
    }
    }
    };

下面是基于EventUtil和getStyle,实现的一个功能相对比较完善的拖拽函数。先晒出代码:

  

 代码如下 复制代码
  var EventUtil = {
    //事件对象
    };
    function getStyle(node,style){
    //获取最终样式
    };
    function drag(obj){
    var isLimit = obj.isLimit || false,
    parentNode = obj.currentNode.offsetParent,
    currentNode = obj.currentNode,
    startDrag = obj.startDrag,
    onDrag = obj.onDrag,
    endDrag = obj.endDrag,
    limitX = obj.limitX || false,
    limitY = obj.limitY || false,
    retObj = {},
    x = 0,
    y = 0;
    EventUtil.addHandler(obj.currentNode,'mousedown',function(e){
    //绑定事件
    var e = e || window.event,
    _x= e.pageX || e.x,
    _y = e.pageY || e.y,
    bdWidth=[],
    dx = dy = 0;
    bdWidth =[
    parseInt(getStyle(parentNode,'borderTopWidth')),
    parseInt(getStyle(parentNode,'borderRightWidth')),
    parseInt(getStyle(parentNode,'borderBottomWidth')),
    parseInt(getStyle(parentNode,'borderLeftWidth'))
    ];
    //移动对象的原点坐标(相对于document.body)
    var origin = [
    parentNode.offsetLeft,
    parentNode.offsetTop,
    parentNode.offsetWidth-bdWidth[1]-bdWidth[3],
    parentNode.offsetHeight-bdWidth[0]-bdWidth[2]
    ],//定义新的原点坐标x,y,w,h
    mousePos = [_x-origin[0],_y-origin[1]], //鼠标点击相对原点坐标
    curPos = [
    currentNode.offsetLeft,
    currentNode.offsetTop,
    currentNode.offsetWidth,
    currentNode.offsetHeight
    ], //移动对象相对于原点坐标x,y,w,h
    limitSection = ['notLimit','notLimit','notLimit','notLimit']; //对象可以移动的区域minX,maxX,minY,maxY
    if(startDrag && typeof startDrag == 'function'){
    retObj = startDrag(currentNode,curPos);
    if(retObj){
    limitX = (retObj.limitX == undefined)?limitX:retObj.limitX;
    limitY = (retObj.limitY == undefined)?limitY:retObj.limitY;
    isLimit = (retObj.isLimit == undefined)?isLimit:retObj.isLimit;
    }
    }
    dx = mousePos[0] - curPos[0];
    dy = mousePos[1] - curPos[1];
    if(limitX){ //根据给定的区域来定义初始化limitSection
    if(limitX[0] != undefined){
    limitSection[0] = limitX[0];
    }
    if(limitX[1] != undefined){
    limitSection[1] = limitX[1];
    }
    }
    if(limitY){
    if(limitY[0] != undefined){
    limitSection[2] = limitY[0];
    }
    if(limitY[1] != undefined){
    limitSection[3] = limitY[1];
    }
    }
    if(isLimit){ //判断是否要限制在父级元素中
    for(var i=0; i     if(limitSection[i] == 'notLimit'){
    switch (i){
    case 0:
    limitSection[i] = 0;
    break;
    case 1:
    limitSection[i] = origin[2] - curPos[2];
    break;
    case 2:
    limitSection[i] = 0;
    break;
    case 3:
    limitSection[i] = origin[3] - curPos[3];
    break;
    }
    } else {
    switch (i){
    case 0:
    limitSection[i] = Math.max(limitSection[i],limitX[0]);
    break;
    case 1:
    limitSection[i] = Math.min(origin[2] - curPos[2],limitX[1]);
    break;
    case 2:
    limitSection[i] = Math.max(limitSection[i],limitY[0]);
    break;
    case 3:
    limitSection[i] = Math.min(origin[3] - curPos[3],limitY[1]);
    break;
    }
    }
    }
    }
    var moumove = function(e){
    var e = e || window.event,
    _x= (e.pageX || e.x) -origin[0],
    _y =(e.pageY || e.y) - origin[1];
    x = _x - dx;
    y = _y - dy;
    for(var i=0;i     if(limitSection[i] != 'notLimit'){
    switch (i){
    case 0:
    x = Math.max(x,limitSection[i]);
    break;
    case 1:
    x = Math.min(x,limitSection[i]);
    break;
    case 2:
    y = Math.max(y, limitSection[i]);
    break;
    case 3:
    y = Math.min(y, limitSection[i]);
    break;
    }
    }
    }
    currentNode.style.left = x + 'px';
    currentNode.style.top = y + 'px';
    if(onDrag && typeof onDrag == 'function'){
    onDrag(currentNode,[x,y]);
    }
    //防止鼠标移动过程内容被选中 www.111Cn.net
    return false;
    };
    EventUtil.addHandler(document,'mousemove',moumove);
    var mouup = function(){
    if(endDrag && typeof endDrag == 'function'){
    endDrag(currentNode,[x,y]);
    }
    EventUtil.removeHandler(document,'mousemove',moumove);
    EventUtil.removeHandler(document,'mouseup',mouup);
    };
    EventUtil.addHandler(document,'mouseup',mouup);
    return false;
    });
    }

向函数drag中传递一个对象,可以对拖拽区域进行限制。标准的参数格式如下:

  

 代码如下 复制代码
  var obj = {
    currentNode : document.getElementById('mine'), //要移动的DOM节点
    isLimit: '', //是否把当前元素锁定到父节点中
    limitX: [], //数组,限制移动对象的水平坐标,可以为空,也可以只设置一个坐标
    limitY: [], //数组,限制移动对象的竖起坐标
    startDrag:function(){}, //开始拖拽执行的函数
    onDrag:function(){}, //拖拽过程中执行的函数
    endDrag:function(){} //回调函数
    }

对象参数中currentNode是必须的,而其它的几个参数是可以根据须要进行选择的设置。

    isLimit:值可以为true或false(默认值)。当为true时表示限制在其定位的那个div中。
    limitX:的值为一个数组,长度可以为1或2。数组的第一个值表示移动的最左边区域边界,第二个值表示最右边区域边界。你可以只设置第一个值,或第二个值。
    limitY:与limitX类似,主要是限制竖直方向。
    startDrag:是一个开始拖拽时执行的函数。可以有两个参数,第一个参数是表示currentNode的DOM节点,第二个参数是长度为4的数组表示currentNode的left、top、width、height。另外,startDrag还可以返回一个对象,对象可以包含isLimit、limitX、limitY来对区域进行重新限制。
    onDrag:是在拖拽过程中执行的函数,而endDrag是在拖拽完成时执行的。它们都可以传递两个参数,第一个参数表示currentNode,而第二个参数为一个数组表示当前currentNode的left、top。

 
以下是用以上的drag函数实现的小应用。

jQuery插件dragPlugin

上面拖拽函数的drag功能已经比较强大了,很多时候,我们都会用jQuery来简化我们的工作,提高工作效率,所以把以上的代码转化成了一个简单的jQuery插件。因为jQuery提供的一些方法,我们可以在一定程度上精简部分代码,最终的代码如下:

  

 代码如下 复制代码
  /**
    * Created with JetBrains PhpStorm.
    * User: 刘洋
    * Date: 13-10-20
    * Time: 下午2:27
    * Description: 这是一个节点拖拽的jQuery插件
    */
    /*var obj = {
    isLimit: '', //是否把当前元素锁定到父节点中
    limitX: [], //数组,限制移动对象的水平坐标,可以为空,也可以只设置一个坐标
    limitY: [], //数组,限制移动对象的竖起坐标
    startDrag:function(){}, //开始拖拽执行的函数
    onDrag:function(){}, //拖拽过程中执行的函数
    endDrag:function(){} //回调函数
    }*/
    (function($){
    $.fn.dragPlugin = function(option){
    function drag(obj){
    var isLimit = obj.isLimit || false,
    parentNode = obj.currentNode.offsetParent,
    currentNode = obj.currentNode,
    startDrag = obj.startDrag,
    onDrag = obj.onDrag,
    endDrag = obj.endDrag,
    limitX = obj.limitX || false,
    limitY = obj.limitY || false,
    retObj ={},
    x = 0,
    y = 0;
    $(currentNode).bind('mousedown',function(e){
    //绑定事件
    var e = e || window.event,
    _x= e.pageX || e.x,
    _y = e.pageY || e.y,
    bdWidth=[],
    dx = 0,dy =0;
    bdWidth =[
    parseInt($(parentNode).css('borderTopWidth')),
    parseInt($(parentNode).css('borderRightWidth')),
    parseInt($(parentNode).css('borderBottomWidth')),
    parseInt($(parentNode).css('borderLeftWidth'))
    ];
    //移动对象的原点坐标(相对于document.body)
    var origin = [
    parentNode.offsetLeft,
    parentNode.offsetTop,
    parentNode.offsetWidth-bdWidth[1]-bdWidth[3],
    parentNode.offsetHeight-bdWidth[0]-bdWidth[2]
    ],//定义新的原点坐标x,y,w,h
    mousePos = [_x-origin[0],_y-origin[1]], //鼠标点击相对原点坐标
    curPos = [
    currentNode.offsetLeft,
    currentNode.offsetTop,
    currentNode.offsetWidth,
    currentNode.offsetHeight
    ], //移动对象相对于原点坐标x,y,w,h
    limitSection = [
    'notLimit',
    'notLimit',
    'notLimit',
    'notLimit'
    ]; //对象可以移动的区域minX,maxX,minY,maxY
    if(startDrag && typeof startDrag == 'function'){
    retObj = startDrag(currentNode,curPos);
    if(retObj){
    limitX = (retObj.limitX == undefined)?limitX:retObj.limitX;
    limitY = (retObj.limitY == undefined)?limitY:retObj.limitY;
    isLimit = (retObj.isLimit == undefined)?isLimit:retObj.isLimit;
    }
    }
    dx = mousePos[0] - curPos[0];
    dy = mousePos[1] - curPos[1];
    if(limitX){ //根据给定的区域来定义初始化limitSection
    if(limitX[0] != undefined){
    limitSection[0] = limitX[0];
    }
    if(limitX[1] != undefined){
    limitSection[1] = limitX[1];
    }
    }
    if(limitY){
    if(limitY[0] != undefined){
    limitSection[2] = limitY[0];
    }
    if(limitY[1] != undefined){
    limitSection[3] = limitY[1];
    }
    }
    if(isLimit){ //判断是否要限制在父级元素中
    for(var i=0; i     if(limitSection[i] == 'notLimit'){
    switch (i){
    case 0:
    limitSection[i] = 0;
    break;
    case 1:
    limitSection[i] = origin[2] - curPos[2];
    break;
    case 2:
    limitSection[i] = 0;
    break;
    case 3:
    limitSection[i] = origin[3] - curPos[3];
    break;
    }
    } else {
    switch (i){
    case 0:
    limitSection[i] = Math.max(limitSection[i],limitX[0]);
    break;
    case 1:
    limitSection[i] = Math.min(limitSection[i],limitX[1]);
    break;
    case 2:
    limitSection[i] = Math.max(limitSection[i],limitY[0]);
    break;
    case 3:
    limitSection[i] = Math.min(limitSection[i],limitY[1]);
    break;
    }
    }
    }
    }
    var moumove = function(e){
    var e = e || window.event,
    _x= (e.pageX || e.x) -origin[0],
    _y =(e.pageY || e.y) - origin[1];
    x = _x - dx;
    y = _y - dy;
    for(var i=0;i     if(limitSection[i] != 'notLimit'){
    switch (i){
    case 0:
    x = Math.max(x,limitSection[i]);
    break;
    case 1:
    x = Math.min(x,limitSection[i]);
    break;
    case 2:
    y = Math.max(y, limitSection[i]);
    break;
    case 3:
    y = Math.min(y, limitSection[i]);
    break;
    }
    }
    }
    $(currentNode).css({
    'left':x,
    'top':y
    });
    if(onDrag && typeof onDrag == 'function'){
    onDrag(currentNode,[x,y]);
    }
    return false;
    };
    $(document).bind('mousemove',moumove);
    var mouup = function(){
    if(endDrag && typeof endDrag == 'function'){
    endDrag(currentNode,[x,y]);
    }
    $(document).unbind('mousemove',moumove);
    $(document).unbind('mouseup',mouup);
    };
    $(document).bind('mouseup',mouup);
    return false;
    });
    }
    option = $.extend({}, $.fn.dragPlugin.defaults,option);
    return this.each(function(){
    option.currentNode = this;
    drag(option);
    });
    }
    $.fn.dragPlugin.defaults = {
    isLimit: false
    };
    })(jQuery);

因为此插件是基于上面的drag函数转化过来的,所以参数的传递几乎相同,不同之处参数中currentNode是设置无效的。你可以返回到上面细看传递对象的相关内容。
jQuery.dragPlugin的简单应用 http://www.111cn.Net

jQuery.dragPlugin的使用和其它的jQuery插件一样,使用起来都是特别方便的。下面是最简单的一种调用方式:

 代码如下 复制代码

    $('#mine').dragPlugin();

关于dragPlugin的详细使用

热门栏目