js拖拽一些常见的思路方法整理


Posted in Javascript onMarch 19, 2014

js拖拽的常见思路

1.通过onmousedown,onmousemove,onmouseup分别模拟开始拖拽,拖拽中和拖拽结束时的事件()。

如果手机的触摸事件的话则分别是ontouchstart,ontouchmove和ontouchend。

2.鼠标按下即发生onmousedown事件时:获取鼠标位置,获取被拖动元素的位置,记录两者之间的纵横坐标的差值()。对document元素绑定onmousemove,onmouseup事件。

刚开始接触js拖拽时,我当时疑惑的是为什么是对document绑定而不是对被拖动的元素绑定呢?原来是如果对被拖动元素绑定的话当鼠标拖动过快时,会导致鼠标与被拖动元素的脱离。

3.鼠标拖动即发生onmousemove事件时:将被拖拽元素的position改成绝对位置,这个可以通过left和top改变该元素的位置,从而使得该元素随着鼠标的拖拽而移动。获取鼠标位置,将鼠标x坐标(e.clientX)减去第2步储存的横坐标差作为被拖动元素的left值,将鼠标x坐标(e.clientY)减去第2步储存的纵坐标差作为被拖动元素的top值。实现元素跟随鼠标拖动的效果。

4.鼠标按键弹起即发生onmouseup事件时:清空onmousemove和onmouseup事件

比较流行的拖拽插件dom-drag类库(作者: Aaron Boodman)

其源代码如下

/*其中( dom-drag.js )文件************************************************** 
* dom-drag.js 
* 09.25.2001 
* www.youngpup.net 
************************************************** 
* 10.28.2001 - fixed minor bug where events 
* sometimes fired off the handle, not the root. 
**************************************************/ var Drag = { 
obj : null, 
init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper) 
{ 
o.onmousedown = Drag.start; 
o.hmode = bSwapHorzRef ? false : true ; 
o.vmode = bSwapVertRef ? false : true ; 
o.root = oRoot && oRoot != null ? oRoot : o ; 
if (o.hmode && isNaN(parseInt(o.root.style.left ))) o.root.style.left = "0px"; 
if (o.vmode && isNaN(parseInt(o.root.style.top ))) o.root.style.top = "0px"; 
if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right = "0px"; 
if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px"; 
o.minX = typeof minX != 'undefined' ? minX : null; 
o.minY = typeof minY != 'undefined' ? minY : null; 
o.maxX = typeof maxX != 'undefined' ? maxX : null; 
o.maxY = typeof maxY != 'undefined' ? maxY : null; 
o.xMapper = fXMapper ? fXMapper : null; 
o.yMapper = fYMapper ? fYMapper : null; 
o.root.onDragStart = new Function(); 
o.root.onDragEnd = new Function(); 
o.root.onDrag = new Function(); 
}, 
start : function(e) 
{ 
var o = Drag.obj = this; 
e = Drag.fixE(e); 
var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom); 
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right ); 
o.root.onDragStart(x, y); 
o.lastMouseX = e.clientX; 
o.lastMouseY = e.clientY; 
if (o.hmode) { 
if (o.minX != null) o.minMouseX = e.clientX - x + o.minX; 
if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX; 
} else { 
if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x; 
if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x; 
} 
if (o.vmode) { 
if (o.minY != null) o.minMouseY = e.clientY - y + o.minY; 
if (o.maxY != null) o.maxMouseY = o.minMouseY + o.maxY - o.minY; 
} else { 
if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y; 
if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y; 
} 
document.onmousemove = Drag.drag; 
document.onmouseup = Drag.end; 
return false; 
}, 
drag : function(e) 
{ 
e = Drag.fixE(e); 
var o = Drag.obj; 
var ey = e.clientY; 
var ex = e.clientX; 
var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom); 
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right ); 
var nx, ny; 
if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX); 
if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX); 
if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY); 
if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY); 
nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1)); 
ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1)); 
if (o.xMapper) nx = o.xMapper(y) 
else if (o.yMapper) ny = o.yMapper(x) 
Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px"; 
Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px"; 
Drag.obj.lastMouseX = ex; 
Drag.obj.lastMouseY = ey; 
Drag.obj.root.onDrag(nx, ny); 
return false; 
}, 
end : function() 
{ 
document.onmousemove = null; 
document.onmouseup = null; 
Drag.obj.root.onDragEnd( parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), 
parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"])); 
Drag.obj = null; 
}, 
fixE : function(e) 
{ 
if (typeof e == 'undefined') e = window.event; 
if (typeof e.layerX == 'undefined') e.layerX = e.offsetX; 
if (typeof e.layerY == 'undefined') e.layerY = e.offsetY; 
return e; 
} 
};

二:拖拽排序也是一种常见的效果

常见实现思路

1.将点击进行拖拽的元素转换为绝对路径,同时新建一个临时元素替代其所在的位置。

2.移动过程中通过循环计算鼠标与剩余元素的位置关系,如果鼠标位置处于该元素中时,在该元素的nextSibling前面插入第1步时创建的临时元素;

3.结束时在临时元素前面插入被拖拽元素,删除临时元素。

网上有个冷月无声博主写的挺好的,在此转载一下其代码

以下为其代码

(function(win, doc){ 
var _this = null; 
var info = {}; 
var list = []; 
var Sortable = function(opts) { 
this.opts = opts; 
_this = this; 
list = X.getByClass(this.opts.sortClass, doc); 
X.addEvent(doc, 'mousedown', this.handleEvent); 
X.addEvent(doc, 'mousemove', this.handleEvent); 
X.addEvent(doc, 'mouseup', this.handleEvent); 
}; 
Sortable.prototype = { 
handleEvent: function(event) { 
var e = event || win.event; 
var target = event.target || event.srcElement; 
switch (event.type) { 
case 'mousedown': 
X.hasClass(target, _this.opts.sortClass) && _this.downEvent.call(_this, e, target); 
break; 
case 'mousemove': 
info.dObj && _this.moveEvent.call(_this, e, target); 
break; 
case 'mouseup': 
info.dObj && _this.upEvent.call(_this, e, target); 
break; 
default: break; 
} 
}, 
downEvent: function(e, target) { 
info.dObj = target; 
var off = X.getOffset(target); 
target.x = e.clientX - off[0]; 
target.y = e.clientY - off[1]; 
target.style.position = 'absolute'; 
target.style.left = off[0] +'px'; 
target.style.top = off[1] +'px'; info.vObj = doc.createElement('div'); 
info.vObj.style.width = off[2] +'px'; 
info.vObj.style.height = off[3] +'px'; 
target.parentNode.insertBefore(info.vObj, target); 
}, 
moveEvent: function(e, target) { 
win.getSelection ? win.getSelection().removeAllRanges() : doc.selection.empty(); 
info.dObj.style.left = e.clientX - info.dObj.x +'px'; 
info.dObj.style.top = e.clientY - info.dObj.y +'px'; 
for(var i = 0; i < list.length; i++) { 
if(list[i] === info.dObj) { 
continue; 
} 
var off = X.getOffset(list[i]); 
if(e.clientX > off[0] && e.clientX < off[0] + off[2] && e.clientY > off[1] && e.clientY < off[1] + off[3]) { 
switch (true) { 
case e.clientY < (off[1] + off[3]) / 2: 
list[i].parentNode.insertBefore(info.vObj, list[i]); 
break; 
case !list[i].nextSibling: 
list[i].parentNode.appendChild(info.vObj); 
break; 
default: 
list[i].parentNode.insertBefore(info.vObj, list[i].nextSibling); 
break; 
} 
} 
} 
}, 
upEvent: function(e, target) { 
info.dObj.style.position = 'static'; 
info.vObj.parentNode.insertBefore(info.dObj, info.vObj); 
info.dObj.parentNode.removeChild(info.vObj); 
info = {}; 
} 
}; 
win.Sortable = Sortable; 
})(window, document);
Javascript 相关文章推荐
Javascript 面向对象特性
Dec 28 Javascript
用jquery实现等比例缩放图片效果插件
Jul 24 Javascript
javascript中的数字与字符串相加实例分析
Aug 14 Javascript
Js放到HTML文件中的哪个位置有什么区别
Aug 21 Javascript
jQuery中next方法用法实例
Apr 24 Javascript
RGB和YUV 多媒体编程基础详细介绍
Nov 04 Javascript
vue v-model表单控件绑定详解
May 17 Javascript
在Mac下彻底卸载node和npm的方法
May 16 Javascript
浅谈redux以及react-redux简单实现
Aug 28 Javascript
JQuery获取元素尺寸、位置及页面滚动事件应用示例
May 14 jQuery
新手如何快速理解js异步编程
Jun 24 Javascript
JS错误处理与调试操作实例分析
Apr 13 Javascript
使用jquery实现以post打开新窗口
Mar 19 #Javascript
jquery判断小数点两位和自动删除小数两位后的数字
Mar 19 #Javascript
改变隐藏的input中value值的方法
Mar 19 #Javascript
js获取url中的参数且参数为中文时通过js解码
Mar 19 #Javascript
JS 打印界面的CSS居中代码适用所有浏览器
Mar 19 #Javascript
兼容所有浏览器的js复制插件Zero使用介绍
Mar 19 #Javascript
javascript + jquery实现定时修改文章标题
Mar 19 #Javascript
You might like
PHP树的深度编历生成迷宫及A*自动寻路算法实例分析
2015/03/10 PHP
php中判断数组相等的方法以及数组运算符介绍
2015/03/30 PHP
PHP 返回数组后处理方法(开户成功后弹窗提示)
2017/07/03 PHP
php往mysql中批量插入数据实例教程
2018/12/12 PHP
Laravel框架实现多数据库连接操作详解
2019/07/12 PHP
win10下 php安装seaslog扩展的详细步骤
2020/12/04 PHP
JavaScript NodeTree导航栏(菜单项JSON类型/自制)
2013/02/01 Javascript
jQuery .tmpl() 用法示例介绍
2014/08/21 Javascript
jQuery源码分析之Callbacks详解
2015/03/13 Javascript
深入浅析JavaScript中数据共享和数据传递
2016/04/25 Javascript
js实现table添加行tr、删除行tr、清空行tr的简单实例
2016/10/15 Javascript
ionic+AngularJs实现获取验证码倒计时按钮
2017/04/22 Javascript
vue中axios请求的封装实例代码
2019/03/23 Javascript
JavaScript面向对象中接口实现方法详解
2019/07/24 Javascript
浅谈vue3中effect与computed的亲密关系
2019/10/10 Javascript
vue实现多级菜单效果
2019/10/19 Javascript
Python使用scrapy抓取网站sitemap信息的方法
2015/04/08 Python
深入flask之异步非堵塞实现代码示例
2018/07/31 Python
Python寻找两个有序数组的中位数实例详解
2018/12/05 Python
python制作简单五子棋游戏
2019/06/18 Python
python禁用键鼠与提权代码实例
2019/08/16 Python
jupyter 导入csv文件方式
2020/04/21 Python
Python 判断时间是否在时间区间内的实例
2020/05/16 Python
Python脚本如何在bilibili中查找弹幕发送者
2020/06/04 Python
踩坑:pytorch中eval模式下结果远差于train模式介绍
2020/06/23 Python
详解Html5微信支付爬坑之路
2018/07/24 HTML / CSS
三个Unix的命令面试题
2015/04/12 面试题
幼儿园教师国培感言
2014/02/02 职场文书
项目经理任命书范本
2014/06/05 职场文书
小学感恩教育活动总结
2014/07/07 职场文书
个人违纪检讨书
2014/09/15 职场文书
欠款纠纷起诉状
2015/05/19 职场文书
无违反计划生育证明格式
2015/06/24 职场文书
高中语文教学反思范文
2016/02/16 职场文书
Python 如何解决稀疏矩阵运算
2021/05/26 Python
浅谈MySQL之select优化方案
2021/08/07 MySQL