JavaScript DOM 鼠标拖拽
程序员文章站
2022-06-17 10:33:04
在前端页面交互中,鼠标拖拽是一个体验良好的功能,实现鼠标拖拽需要了解鼠标行为坐标系和涉及到的许多兼容性写法。本文介绍鼠标位置的获取和、拽功能的实现以及拖拽函数的封装 ......
javascript dom 鼠标拖拽
在前端页面交互中,鼠标拖拽是一个体验良好的功能,实现鼠标拖拽需要了解鼠标行为坐标系和涉及到的许多兼容性写法。本文介绍鼠标位置的获取和、拽功能的实现以及拖拽函数的封装
鼠标行为坐标系
-
鼠标行为触发事件时,事件对象上会有一些属性提供鼠标的位置信息
属性 功能 兼容性 clientx/y 鼠标相对可视区域的坐标 / x/y 与 clientx/y 功能相同 firefox 低版本不支持 pagex/y 鼠标相对整个文档的坐标 兼容 ie9 及以上 layerx/y 与 pagex/y 功能相同 ie10 及以下同 clientx/y screenx/y 鼠标位置相对屏幕坐标 / offsetx/y 鼠标位置相对块元素的坐标(包含边框) safari 不包含边框 -
获取鼠标相对整个文档的坐标:pagex/y 兼容性差,需要进行封装
鼠标相对整个文档的坐标 = 鼠标相对可视区域的坐标 + 滚动条滚动距离 - 文档偏移
document.documentelement.clienttop 获取文档偏移,在 ie 一些版本中为 undefined
function pagepos(ev) { var stop = getscrolloffset().top, sleft = getscrolloffset().left, ctop = document.documentelement.clienttop || 0, cleft = document.documentelement.clientleft || 0; return { x: ev.clientx + sleft - cleft, y: ev.clienty + stop - ctop } } // 封装的函数:获取滚动条滚动距离 function getscrolloffset() { if (window.pagexoffset) { return { top: window.pageyoffset, left: window.pagexoffset } } else return { top:document.body.scrolltop || document.documentelement.scrolltop, left:document.body.scrollleft || document.documentelement.scrollleft } }
拖拽函数封装
-
拖拽效果基于鼠标事件:mousedown、mousemove、mouseup
分别为鼠标按下、鼠标移动、鼠标松开
-
原理:鼠标按下时,添加鼠标移动、鼠标松开的事件处理函数,鼠标移动时获取鼠标坐标,改变元素样式,鼠标松开时清除鼠标移动和鼠标松开的事件处理函数
<!doctype html> <html lang="zh"> <head> <meta charset="utf-8"> <title>index</title> <style type="text/css"> .box { position: absolute; top: 0; left: 0; width: 100px; height: 100px; background-color: red; } </style> </head> <body> <div class="box"></div> <script> var box = document.getelementsbytagname('div')[0]; box.onmousedown = function (ev) { var ev = ev || window.event, x = pagepos(ev).x - parseint(getstyles(box)['left']), y = pagepos(ev).y - parseint(getstyles(box)['top']); document.onmousemove = function (ev) { var ev = ev || window.event, mpos = pagepos(ev); box.style.left = mpos.x - x + 'px'; box.style.top = mpos.y - y + 'px'; } document.onmouseup = function () { this.onmousemove = null; this.onmouseup = null; } } // 封装的函数:获取鼠标相对整个文档的坐标 function pagepos(ev) { var stop = getscrolloffset().top, sleft = getscrolloffset().left, ctop = document.documentelement.clienttop || 0, cleft = document.documentelement.clientleft || 0; return { x: ev.clientx + sleft - cleft, y: ev.clienty + stop - ctop } } // 封装的函数:获取滚动条滚动距离 function getscrolloffset() { if (window.pagexoffset) { return { top: window.pageyoffset, left: window.pagexoffset } } else return { top: document.body.scrolltop || document.documentelement.scrolltop, left: document.body.scrollleft || document.documentelement.scrollleft } } // 封装的函数:获取元素样式的类数组 function getstyles(elem) { if (window.getcomputedstyle) { return window.getcomputedstyle(elem, null); } else return elem.currentstyle; } </script> </body> </html>
-
封装拖拽函数
var box = document.getelementsbytagname('div')[0]; elemdrag(box); // 封装的拖拽函数 function elemdrag(elem) { var x, y; addevent(elem, 'mousedown', function (ev) { var ev = ev || window.event; x = pagepos(ev).x - parseint(getstyles(elem)['left']); y = pagepos(ev).y - parseint(getstyles(elem)['top']); addevent(document, 'mousemove', mousemove); addevent(document, 'mouseup', mouseup); cancelbubble(ev); preventdefaultevent(ev); }); function mousemove(ev) { var ev = ev || window.event; elem.style.left = pagepos(ev).x - x + 'px'; elem.style.top = pagepos(ev).y - y + 'px'; } function mouseup(ev) { var ev = ev || window.event; removeevent(document, 'mousemove', mousemove); removeevent(document, 'mouseup', mouseup); } } // 绑定事件处理函数 function addevent(elem, type, fn) { if (elem.addeventlistener) { elem.addeventlistener(type, fn); } else if (elem.attachevent) { elem.attachevent('on' + type, function (ev) { fn.call(elem, ev); // call 兼容性比 bind 好 }); } else { elem['on' + type] = fn; } } // 解绑事件处理函数 function removeevent(elem, type, fn) { if (elem.addeventlistener) { elem.removeeventlistener(type, fn); } else if (elem.attachevent) { elem.detachevent('on' + type, fn); } else { elem['on' + type] = null; } } // 获取鼠标在整个文档中的坐标 function pagepos(ev) { var stop = getscrolloffset().top, sleft = getscrolloffset().left, ctop = document.documentelement.clienttop || 0, cleft = document.documentelement.clientleft || 0; return { x: ev.clientx + sleft - cleft, y: ev.clienty + stop - ctop } } // 获取滚动条滚动距离 function getscrolloffset() { if (window.pagexoffset) { return { top: window.pageyoffset, left: window.pagexoffset } } else return { top: document.body.scrolltop || document.documentelement.scrolltop, left: document.body.scrollleft || document.documentelement.scrollleft } } // 获取元素样式的类数组 function getstyles(elem) { if (window.getcomputedstyle) { return window.getcomputedstyle(elem, null); } else return elem.currentstyle; } // 阻止冒泡 function cancelbubble(ev) { if (ev.stoppropagation) { ev.stoppropagation(); } else ev.cancelbubble = true; // 兼容 ie8 及以下 } // 阻止默认事件 function preventdefaultevent(ev) { if (ev.preventdefault) { ev.preventdefault(); } else ev.returnvalue = false; // 兼容 ie8 及以下 }
推荐阅读