onmousemove 实现拖拽
说到前端的拖拽很多前端开发人员会很烦,尤其是涉及到边缘判断这块,还有就是兼容性。学习前端之初我一直是使用onmousemove来实现拖拽的,下面展示要给传统的通过onmousemove实现的拖拽。 代码如下:
HTML:
<div class="wrap">
<div class="drag"></div>
</div>
CSS:
.wrap{
width: 600px;
height: 600px;
margin: 150px auto;
border: 1px solid #000000;
position: relative;
}
.drag{
width: 50px;
height: 50px;
background: #DB0304;
cursor: pointer;
position: absolute;
}
JS:
var dragDom = document.querySelector('.drag');
var wrap = document.querySelector('.wrap');
function drag(ele){
var oldX, oldY, newX, newY;
ele.onmousedown = function(e){
this.style.position = 'relative';//元素相对定位
if(!this.style.left && !this.style.top){//第一次设置left、top为0
this.style.left = 0;
this.style.top = 0;
}
oldX = e.clientX;//记录初始光标相对于视窗坐标
oldY = e.clientY;
document.onmousemove = function(e){
newX = e.clientX;//获取当前新光标相对于视窗坐标
newY = e.clientY;
ele.style.left = parseInt(ele.style.left) + newX - oldX + 'px';//更新
ele.style.top = parseInt(ele.style.top) + newY - oldY + 'px';
oldX = newX;//新坐标变为老坐标
oldY = newY;
}
document.onmouseup = function(){
document.onmousemove = null;
document.onmouseup = null;
}
}
}
drag(dragDom)
最终效果:
代码分析:
首先是给dom绑定一个mousedown事件,并且记录初始化光标相对于浏览器的坐标。里面我们为什么使用 document 呢?因为当我们鼠标快速移动的时候经常会出现鼠标移出了目标dom这个时候如果我们给dom绑定mousemove事件的话会出现卡顿现象。所以我们给document加这个事件,里边我们设置新的x,y坐标是当前的鼠标相对于浏览器的坐标,然后我们我们开始计算此时的delta,也就是改变的值:
deltaX = newX - oldX, deltaY = newY - oldY
所以我们获取当前dom的位置加上变化的量,就是新的位置。并且把新的位置复制给oldX和oldY。
最后我们通过绑定mouseup来解绑事件。OK,大功告成,是不是也很简单,这里是因为我们没有加边缘判断,所以相对简单一些,如果我们要根据实际的项目需求,加上不同的边缘判断就不简单了。
ondragover 实现
这里我得先给大家大概讲讲这块的一个基本知识:
HTML draggable 属性
<div draggable="true></div>
兼容性:
| IE | Firefox | Chrome | Safari | Opera |
|---|---|---|---|---|
| 9+ | true | true | true | true |
结论:我们可以大胆的使用了,毕竟兼容IE8以及IE8之前的网页拖拽现在用的比较少了。
在拖动目标上触发事件 (源元素):
- ondragstart - 用户开始拖动元素时触发
- ondrag - 元素正在拖动时触发
- ondragend - 用户完成元素拖动后触发
释放目标时触发的事件:
- ondragenter - 当被鼠标拖动的对象进入其容器范围内时触发此事件
- ondragover - 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
- ondragleave - 当被鼠标拖动的对象离开其容器范围内时触发此事件
- ondrop - 在一个拖动过程中,释放鼠标键时触发此事件
DataTransfer
在进行拖放操作时,DataTransfer 对象用来保存,通过拖放动作,拖动到浏览器的数据。它可以保存一项或多项数据、一种或者多种数据类型。
这个对象可以从所有拖动事件 drag events 的 dataTransfer 属性上获取,但是不能单独创建。
DOMString dataTransfer.getData(format)
DOMString dataTransfer.setData()
上边是dataTransfer的两个方法,getData(format)中的format方法参数:text/plain, text/uri-list。我们常用的主要是text。format就是DOMString类型。
下面我们就简单的实现一个拖拽。
代码如下:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Drag</title>
<style type="text/css">
*{
margin: 0px;
padding:0px;
}
#con{
width:100%;
height:500px;
border:1px dotted #999;
}
#img{
margin-left: 10px;
margin-top: 0px;
}
</style>
</head>
<body>
<div id="con" ondragover="allowDrop(event);" ondrop="drop(event);">
<img id="img" src="./hot.png" draggable="true" ondragstart="drag(event)"/>
</div>
</body>
<script type="text/javascript">
//保存位置的状态值
var pos={
parent_top:0,
parent_left:0,
cur_top:0,
cur_left:0
}
function allowDrop(ev){ //ev是事件对象
ev.preventDefault(); //取消事件已经关联的默认活动
}
function drag(ev){
//dataTransfer是一个媒介,将目标对象放入媒介
//dataTransfer对象用来保存被拖动的数据,仅在拖动事件有效
//这里将被拖动元素的id保存为名为Text的键值对中
ev.dataTransfer.setData("Text",ev.target.id);
//获取被拖动对象相对于上层元素顶边和左边位置
pos.parent_top=ev.target.offsetTop;
pos.parent_left=ev.target.offsetLeft;
pos.cur_top=ev.screenY;
pos.cur_left=ev.screenX;
}
function drop(ev){
var new_top,new_left;
ev.preventDefault();
var data=ev.dataTransfer.getData("text");
var elem=document.getElementById(data);
elem.style.marginLeft=pos.parent_left+ev.screenX-pos.cur_left+"px";
elem.style.marginTop=pos.parent_top+ev.screenY-pos.cur_top+"px";
}
</script>
</html>
上边是实现简单的拖拽,工作中如果有这块需求还得根据具体业务需求来加相应的方法。