
这是现在的效果,可能改了一些,原来的效果是,里面的这张图是可以上下左右拖动的,然后房子上面的显示的楼栋号,也跟着图片一起移动,当时js能力还不行,未能实现项目经理的要求,不过后来项目经理又把这个效果推掉了,换了另外的一个效果
尽管项目经理不想要这个效果了,但是当时就在我心里留下了一个节,到今天都忘不了这个梗。
好了,这就是我今天想写这篇博客的初衷,希望能给想实现这类拖拽效果,但是不知道该怎么去实现的同学,提供一种思路,不给青春留遗憾,当然实现拖拽的方法有很多,这里就只介绍JavaScript中的一种方法,慢慢体会一下其中的原理!
好了,梗也说完了,开始正题,我们先要明白,拖拽到底是一个什么东西,你也知道,我也知道,但是我还是想来描述一下:
拖拽就是一个容器,你用鼠标可以在页面上拖着到处跑,废话,精确的描述应该是,鼠标移到容器上,然后鼠标按下去,注意要按着不放,然后拖动鼠标,容器能跟着鼠标跑,松开鼠标,容器就停在那里不动了,现实中的例子就是桌子上有一个盒子,我用手放在盒子上,然后移动盒子,手停盒子停,手拿开,盒子不动了,嘻嘻,都懂了哈!
别以为上面说了一堆的废话,我们可以从中得到很多的信息,总结如下就是:
拖拽 = 鼠标按下 + 鼠标移动 + 鼠标弹上
这样就完成了一个拖拽任务,好了,原来这就是拖拽的原理,想实现拖拽,自然实现上面的3个动作,便可以模拟拖拽效果,好,对应JavaScript中的语法就是需要实现这3个动作:
onmousedown , onmousemove , onmouseup
实现的代码就应该是:
obj.onmousedown = function(ev){ obj.onmousemove = function(ev){} ; obj.onmouseup = function(ev){}; }为什么后面2个动作要写的里面,好好回味一下,好了,第一步的大概思路就有了,下一步就需要考虑怎么让物体跟着鼠标一起移动,思路大概是这样的:
说明:蓝色框为屏幕宽高,黑色粗框为浏览器可视区宽高(浏览器缩小效果),黑色细框为鼠标要拖拽的对象,如图可知,获取鼠标的坐标,可以用event.clientX,event.clientY来获取,哦了;
计算的大致原理可以参照下图:

说明:左边为初始位置,右边为目标位置,原点为鼠标位置,大黑框为浏览器可视宽度,小黑框为拖拽对象,看拖拽对象到目标位置的状态,获取鼠标的最终位置,再减去鼠标距离对象的差值,再赋值给对象的top,left值,也可以获取鼠标的位置差值,再用初始的top,left值加上差值,我们采用第一种,第二种也可以,自己去试一下:
obj.onmousedown = function(ev){var ev = ev || event;var disX = ev.clientX - this.offsetLeft,disY = ev.clientY - this.offsetTop; document.onmousemove = function(ev){var ev = ev || event;obj.style.left = ev.clientX - disX + "px";obj.style.top = ev.clientY - disY + "px";};document.onmouseup = function(ev){var ev = ev || event;document.onmousemove = document.onmouseup = null;};}这里说明一下:onmousemove和onmouseup之所以用document对象而不用obj对象,是因为如果用obj对象,鼠标在obj内部还好,如果在obj外面的话,拖拽会很怪异,你也可以改成obj体会一下,最后我们在鼠标弹起的时候将事件都清空;if(ev.stopPropagation){ ev.stopPropagation();}else{ev.cancelBubble = true; //兼容IE}//简写成ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;将上面的代码放在onmousedown下,鼠标按下就清除浏览器默认事件,文字就不会被选中了,好了,一个简单的拖拽效果就完成了,当然你现在是看不到效果,之所以不给demo链接是为了让你自己试着写一写,这样印象更深刻,//左侧if(obj.offsetLeft <=0){obj.style.left = 0;};//右侧if(obj.offsetLeft >= pWidth - oWidth){obj.style.left = pWidth - oWidth + "px"; };//上面if(obj.offsetTop <= 0){obj.style.top = 0; };//下面if(obj.offsetTop >= pHeight - oHeight){obj.style.top = pHeight - oHeight + "px"; };说明:pWidth,pHeight 表示父级元素的宽高(这里是表示相对于父级的宽高限制),oWidth,oHeigt表示拖拽元素的宽高/*参数说明:元素绝对定位,父级相对定位,如果父级为window,则可以不用传一个参数,表示父级为window,物体相对于window范围拖动传2个参数,则父级为第二个参数,物体相对于父级范围拖动参数为id值*/function drag(obj,parentNode){var obj = document.getElementById(obj);if(arguments.length == 1){var parentNode = window.self; var pWidth = parentNode.innerWidth,pHeight = parentNode.innerHeight;}else{var parentNode = document.getElementById(parentNode);var pWidth = parentNode.offsetWidth,pHeight = parentNode.offsetHeight;}obj.onmousedown = function(ev){var ev = ev || event;var disX = ev.clientX - this.offsetLeft,disY = ev.clientY - this.offsetTop;var oWidth = obj.offsetWidth,oHeight = obj.offsetHeight; //阻止冒泡时间ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;document.onmousemove = function(ev){var ev = ev || event;obj.style.left = ev.clientX - disX + "px";obj.style.top = ev.clientY - disY + "px"; //左侧if(obj.offsetLeft <=0){obj.style.left = 0;};//右侧if(obj.offsetLeft >= pWidth - oWidth){obj.style.left = pWidth - oWidth + "px"; };//上面if(obj.offsetTop <= 0){obj.style.top = 0; };//下面if(obj.offsetTop >= pHeight - oHeight){obj.style.top = pHeight - oHeight + "px"; };};document.onmouseup = function(ev){var ev = ev || event;document.onmousemove = document.onmouseup = null;};} }说明:我这里处理的效果是,如果传一个参数,表示相对的对象是window对象,如果传2个参数,第一个是拖拽对象,第二个为相对父级<style>.box{width:600px;height:400px;margin:50px auto;position:relative;overflow:hidden;}#box{width:1000px;height:800px;position:absolute;left:50%;top:50%;margin:-400px 0 0 -500px;}#pic{ width:800px; height:600px; background:url(images/pic1.jpg) no-repeat; position:absolute; left:100px; top:100px; }#pic:hover{cursor:move;}</style>html:<div class="box"><div id="box"><div id="pic"></div></div></div>javascript:
window.onload = function(){ drag("pic","box");function drag(obj,parentNode){var obj = document.getElementById(obj);if(arguments.length == 1){var parentNode = window.self; var pWidth = parentNode.innerWidth,pHeight = parentNode.innerHeight;}else{var parentNode = document.getElementById(parentNode);var pWidth = parentNode.offsetWidth,pHeight = parentNode.offsetHeight;}obj.onmousedown = function(ev){var ev = ev || event;var disX = ev.clientX - this.offsetLeft,disY = ev.clientY - this.offsetTop;var oWidth = obj.offsetWidth,oHeight = obj.offsetHeight; //阻止冒泡时间ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;document.onmousemove = function(ev){var ev = ev || event;obj.style.left = ev.clientX - disX + "px";obj.style.top = ev.clientY - disY + "px"; //左侧if(obj.offsetLeft <=0){obj.style.left = 0;};//右侧if(obj.offsetLeft >= pWidth - oWidth){obj.style.left = pWidth - oWidth + "px"; };//上面if(obj.offsetTop <= 0){obj.style.top = 0; };//下面if(obj.offsetTop >= pHeight - oHeight){obj.style.top = pHeight - oHeight + "px"; };};document.onmouseup = function(ev){var ev = ev || event;document.onmousemove = document.onmouseup = null;};} }}效果完全是用的那个封装代码块,引用起来也挺方便,有人会问了,你这用的id获取DOM元素,一个页面只能用一次啊,如果页面多次使用呢,有道理,解决方案之一,那就命名不同的id呗,又不犯法,方案二,获取id的地方改成获取class,但是要注意的是,getElementsByClassName是获取的class集合,需要改写一下,这里我就不写了,有兴趣的同学自行改写一下,好了,到这里真的结束了!