最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
JavaScript实现元素的拖拽特效
时间:2014-01-04 编辑:简简单单 来源:一聚教程网
DOM节点的拖拽是一个很简单的JavaScript特效,也常称作为拖放,即:Drag-and-drop。
拖拽主要涉及到三个过程:
鼠标点击要拖放的对象,记录鼠标相对于拖动对象(left和top值)坐标
鼠标移动事件过程中,不断改变对象的left和top值,从而出现鼠跟随效果。
鼠标松开事件,解除鼠标移动事件。
实现拖拽的相关HTML和CSS
以下是拖拽实现的HTML代码结构:
代码如下 | 复制代码 |
|
下面是相关的CSS
代码如下 | 复制代码 |
.parent { |
下面是一般实现拖拽的方法,其很好的说明了拖拽的三个过程:
代码如下 | 复制代码 |
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 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 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。
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 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 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的详细使用
相关文章
- HTML简单购物数量小程序代码展示 10-31
- html canvas实现弹幕功能 10-31
- HTML中空格表示的意义 10-31
- html area标签解读 10-31
- html使用表单标签实现注册页面代码展示 10-31
- 使用HTML截图并保存为本地图片的代码展示 10-31