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 相关文章推荐
定义select的边框颜色
Apr 28 Javascript
JavaScript Perfection kill 测试及答案
Mar 23 Javascript
jquery遍历数组与筛选数组的方法
Nov 05 Javascript
Ext修改GridPanel数据和字体颜色、css属性等
Jun 13 Javascript
javascript Slip.js实现整屏滑动的手机网页
Nov 25 Javascript
js窗口震动小程序分享
Nov 28 Javascript
有关suggest快速删除后仍然出现下拉列表的bug问题
Dec 02 Javascript
js遍历添加栏目类添加css 再点击其它删除css【推荐】
Jun 12 Javascript
Angular父子组件通过服务传参的示例方法
Oct 31 Javascript
vue回到顶部监听滚动事件详解
Aug 02 Javascript
vue中的使用token的方法示例
Mar 10 Javascript
在Angular项目使用socket.io实现通信的方法
Jan 05 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
风格模板初级不完全修改教程
2006/10/09 PHP
深入理解PHP原理之异常机制
2010/08/21 PHP
使用dump函数,给php加断点测试
2013/06/25 PHP
PHP FATAL ERROR: CALL TO UNDEFINED FUNCTION BCMUL()解决办法
2014/05/04 PHP
PHP登录(ajax提交数据和后台校验)实例分享
2016/12/29 PHP
php抽象类和接口知识点整理总结
2019/08/02 PHP
lib.utf.js
2007/08/21 Javascript
深入理解JavaScript系列(8) S.O.L.I.D五大原则之里氏替换原则LSP
2012/01/15 Javascript
jQuery获得内容和属性方法及示例
2013/12/02 Javascript
使用jquery+CSS3实现仿windows10开始菜单的下拉导航菜单特效
2015/09/24 Javascript
js对字符串进行编码的方法总结(推荐)
2016/11/10 Javascript
vue-cli项目中使用公用的提示弹层tips或加载loading组件实例详解
2018/05/28 Javascript
javascript中的event loop事件循环详解
2018/12/14 Javascript
Vue动态创建注册component的实例代码
2019/06/14 Javascript
layer.open提交子页面的form和layedit文本编辑内容的方法
2019/09/27 Javascript
vue路由切换时取消之前的所有请求操作
2020/09/01 Javascript
Python 开发Activex组件方法
2009/11/08 Python
Python使用函数默认值实现函数静态变量的方法
2014/08/18 Python
Python日期的加减等操作的示例
2017/08/15 Python
Python实战小程序利用matplotlib模块画图代码分享
2017/12/09 Python
pytorch 实现tensor与numpy数组转换
2019/12/27 Python
tensorflow2.0保存和恢复模型3种方法
2020/02/03 Python
利用css3-animation实现逐帧动画效果
2016/03/10 HTML / CSS
美体小铺英国官网:The Body Shop英国
2017/01/24 全球购物
台湾网友喜爱的综合型网路购物商城:Yahoo! 奇摩购物中心
2018/03/10 全球购物
allbeauty美国:英国在线美容店
2019/03/11 全球购物
应用艺术毕业生的自我评价
2013/12/04 职场文书
微博营销计划书
2014/01/10 职场文书
洗车工岗位职责
2014/03/15 职场文书
陈胜吴广起义口号
2014/06/20 职场文书
2014年中秋寄语
2014/08/11 职场文书
个人四风对照检查材料
2014/09/26 职场文书
银行领导班子四风对照检查材料
2014/09/27 职场文书
中学生检讨书范文
2014/11/03 职场文书
项目备案申请报告
2015/05/15 职场文书
gateway与spring-boot-starter-web冲突问题的解决
2021/07/16 Java/Android