一.拖拽的原理:选择元素时(鼠标按下),保存鼠标的位置和元素位置的差值(以保证鼠标拖住元素移动时相对于元素的位置固定);移动元素时(鼠标移动),不停地给元素位置赋值(当前鼠标位置减去保存的差值);释放元素时(鼠标抬起),取消移动事件。
二.可能会遇到的问题
1.若移动速度太快脱离元素时事件就不会执行了;
2.为了避免冒泡,onmousemove事件放在document上就可以了;
3.为了避免当鼠标在其他元素上抬起时元素不会停止运动,故将onmouseup事件也放在document上;
4.鼠标按下时,如果有文字被选中,拖拽会变成复制(浏览器默认行为),这时就会出现冲突,避免该冲突的做法:
A.标准浏览器下:
需要在onmousedown阻止默认行为来防止(非标准浏览器下无效)。
B.IE下:
IE浏览器里有个全局捕获(和事件流里面的捕获不同)。全局捕获的意思是当有其他元素执行一个事件时劫持该事件,在释放元素时需要把全局捕获也释放。
//全局捕获劫持事件
if(元素.setCapture){
元素.setCapture();
}
...
//释放元素时释放全局捕获
if(元素.releaseCapture){
元素.releaseCapture();
}
这样也可以达到和阻止默认事件一样的效果。
三.封装拖拽(限制范围的拖拽)
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
#box{width:100px; height:100px; background-color:red; position:absolute; left:100px; top:100px; z-index:5;}
#box1{width:500px; height:500px; background-color:green; position:absolute; left:100px; top:100px; z-index:3;}
</style>
</head>
<body style="height:2000px;">
<div id="box"></div>
<div id="box1"></div>
<script>
var oDiv = document.getElementById('box');
var oDiv1 = document.getElementById('box1');
downMove(oDiv,oDiv1);
function downMove(ele,ele2){
ele.onmousedown = function(ev){
var ev = ev || event;
if(ele.setCapture){ele.setCapture();}
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
var disX = ev.clientX - ele.offsetLeft + scrollLeft;
var disY = ev.clientY - ele.offsetTop + scrollTop;
document.onmousemove = function(ev){
var ev = ev || event;
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
var oLeft = ev.clientX - disX + scrollLeft;
if(oLeft<ele2.offsetLeft){
oLeft = ele2.offsetLeft;
}
if(oLeft>ele2.offsetLeft+ele2.offsetWidth-ele.offsetWidth){
oLeft = ele2.offsetLeft+ele2.offsetWidth-ele.offsetWidth;
}
var oTop = ev.clientY - disY + scrollTop;
if(oTop<ele2.offsetTop){
oTop = ele2.offsetTop;
}
if(oTop>ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight){
oTop = ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight;
}
ele.style.left = oLeft +'px';
ele.style.top = oTop + 'px';
}
document.onmouseup = function(){
if(ele.releaseCapture){ele.releaseCapture();}
document.onmousemove = document.onmouseup = null;
}
return false;
}
}
</script>
</body>
</html>
练习1:在上面封装的基础上,做一个磁性吸附效果(当元素距离边界小于50像素时,像磁铁一样一下吸附过去)
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
#box{width:100px; height:100px; background-color:red; position:absolute; left:100px; top:100px; z-index:5;}
#box1{width:500px; height:500px; background-color:green; position:absolute; left:100px; top:100px; z-index:3;}
</style>
</head>
<body>
<div id="box"></div>
<div id="box1"></div>
<script>
var oDiv=document.getElementById("box");
var oDiv1=document.getElementById("box1");
downMove(oDiv,oDiv1);
function downMove(ele,ele2){
ele.onmousedown = function(ev){
var ev = ev || event;
if(ele.setCapture){ele.setCapture();}
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
var disX = ev.clientX - ele.offsetLeft + scrollLeft;
var disY = ev.clientY - ele.offsetTop + scrollTop;
document.onmousemove = function(ev){
var ev = ev || event;
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
var oLeft = ev.clientX - disX + scrollLeft;
if(oLeft<ele2.offsetLeft+50){
oLeft = ele2.offsetLeft;
}
if(oLeft>ele2.offsetLeft+ele2.offsetWidth-ele.offsetWidth-50){
oLeft = ele2.offsetLeft+ele2.offsetWidth-ele.offsetWidth;
}
var oTop = ev.clientY - disY + scrollTop;
if(oTop<ele2.offsetTop+50){
oTop = ele2.offsetTop;
}
if(oTop>ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight-50){
oTop = ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight;
}
ele.style.left = oLeft +'px';
ele.style.top = oTop + 'px';
}
document.onmouseup = function(){
if(ele.releaseCapture){ele.releaseCapture();}
document.onmousemove = document.onmouseup = null;
}
return false;
}
}
</script>
</body>
</html>
四.拖拽的延伸
1.碰撞检测:就是检查是否有重合(思路:九宫格方式判断)
练习2:做一个方块和图片碰撞时,图片切换成另一张图片,离开时变回。
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
#box{width:100px; height:100px; background-color:red; position:absolute; left:100px; top:100px; z-index:5;}
#box1{width:500px; height:500px; background-color:green; position:absolute; left:100px; top:100px; z-index:3;}
</style>
</head>
<body style="height:2000px;">
<div id="box"></div>
<div id="box1"></div>
<script>
var oDiv = document.getElementById('box');
var oDiv1 = document.getElementById('box1');
downMove(oDiv,document,oDiv1);
function downMove(ele,ele2,ele3){
ele.onmousedown = function(ev){
var ev = ev || event;
if(ele.setCapture){ele.setCapture();}
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
var disX = ev.clientX - ele.offsetLeft + scrollLeft;
var disY = ev.clientY - ele.offsetTop + scrollTop;
document.onmousemove = function(ev){
var ev = ev || event;
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
if(ele2==document){
ele2.offsetLeft=scrollLeft;
ele2.offsetTop=scrollTop;
ele2.offsetWidth=document.documentElement.clientWidth;
ele2.offsetHeight=document.documentElement.clientHeight;
}
var oLeft = ev.clientX - disX + scrollLeft;
if(oLeft<ele2.offsetLeft){
oLeft = ele2.offsetLeft;
}
if(oLeft>ele2.offsetLeft+ele2.offsetWidth-ele.offsetWidth){
oLeft = ele2.offsetLeft+ele2.offsetWidth-ele.offsetWidth;
}
var oTop = ev.clientY - disY + scrollTop;
if(oTop<ele2.offsetTop){
oTop = ele2.offsetTop;
}
if(oTop>ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight){
oTop = ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight;
}
if(oLeft+ele.offsetWidth>ele3.offsetLeft&&oTop+ele.offsetHeight>ele3.offsetTop&&ele3.offsetLeft+ele3.offsetWidth>oLeft&&ele3.offsetTop+ele3.offsetHeight>oTop){
//碰撞时背景色变为黄色
ele3.style.backgroundColor='yellow';
}else{
//离开时背景色变为绿色
ele3.style.backgroundColor='green';
}
ele.style.left = oLeft +'px';
ele.style.top = oTop + 'px';
}
document.onmouseup = function(){
if(ele.releaseCapture){ele.releaseCapture();}
document.onmousemove = document.onmouseup = null;
}
return false;
}
}
</script>
</body>
</html>
2.拖拽改变元素大小
练习3:先找到鼠标按下时,它在元素的什么位置(判断要改变哪个方向),每个方向–上下左右分别为:改变height和top值;改变height;改变width和left值;改变width
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
#box{width:100px; height:100px; background-color:red; position:absolute; left:100px; top:100px;}
</style>
</head>
<body>
<div id="box"></div>
<script>
var oDiv = document.getElementById('box');
downMove(oDiv,document);
var oLeft=0;
var oTop=0;
var i=0;
function downMove(ele,ele2){
ele.onmousedown = function(ev){
var ev = ev || event;
if(ele.setCapture){ele.setCapture();}
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
var disX = ev.clientX - ele.offsetLeft + scrollLeft;
var disY = ev.clientY - ele.offsetTop + scrollTop;
document.onmousemove = function(ev){
var ev = ev || event;
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
if(ele2==document){
ele2.offsetLeft=scrollLeft;
ele2.offsetTop=scrollTop;
ele2.offsetWidth=document.documentElement.clientWidth;
ele2.offsetHeight=document.documentElement.clientHeight;
}
i++;
var oLeft1=oLeft;
oLeft = ev.clientX - disX + scrollLeft;
if(oLeft<ele2.offsetLeft){
oLeft = ele2.offsetLeft;
}
if(oLeft>ele2.offsetLeft+ele2.offsetWidth-ele.offsetWidth){
oLeft = ele2.offsetLeft+ele2.offsetWidth-ele.offsetWidth;
}
var oTop1=oTop;
oTop = ev.clientY - disY + scrollTop;
if(oTop<ele2.offsetTop){
oTop = ele2.offsetTop;
}
if(oTop>ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight){
oTop = ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight;
}
ele.style.left = oLeft +'px';
ele.style.top = oTop + 'px';
if((disX>0&&disX<20)&&(disY>20&&disY<ele.offsetHeight-20)){
if(oLeft1<oLeft){
ele.style.width=ele.offsetWidth+3+'px';
}else if(oLeft1>oLeft){
ele.style.width=ele.offsetWidth-3+'px';
}
}
if(((disX>ele.offsetWidth-20*i)&&(disX<ele.offsetWidth))&&(disY>20&&disY<ele.offsetHeight-20)){
if(oLeft1<oLeft){
ele.style.width=ele.offsetWidth+3+'px';
}else if(oLeft1>oLeft){
ele.style.width=ele.offsetWidth-3+'px';
}
}
if((disY>0&&disY<20)&&(disX>20&&disX<ele.offsetWidth-20)){
if(oTop1<oTop){
ele.style.height=ele.offsetHeight+3+'px';
}else if(oTop1>oTop){
ele.style.height=ele.offsetHeight-3+'px';
}
}
if((disY>ele.offsetHeight-20*i&&disY<ele.offsetHeight)&&(disX>20&&disX<ele.offsetWidth-20)){
if(oTop1<oTop){
ele.style.height=ele.offsetHeight+3+'px';
}else if(oTop1>oTop){
ele.style.height=ele.offsetHeight-3+'px';
}
}
}
document.onmouseup = function(){
if(ele.releaseCapture){ele.releaseCapture();}
document.onmousemove = document.onmouseup = null;
}
return false;
}
}
</script>
</body>
</html>
3.模拟滚动条:定义一个元素在另一个元素里拖拽,只需要一个方向移动。原理:内部元素的top和两个元素高度差的比例,等于当前要控制的滚动条scrollTop和整个页面高度的比例
练习4:做一个限制范围的模拟滚动条
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
#box{width:20px; height:50px; background-color:red; position:absolute; left:100px; top:100px; z-index:5;}
#box1{width:20px; height:500px; background-color:green; position:absolute; left:100px; top:100px; z-index:3;}
</style>
</head>
<body style="height:2000px;">
<div id="box"></div>
<div id="box1"></div>
<script>
var oDiv = document.getElementById('box');
var oDiv1 = document.getElementById('box1');
downMove(oDiv,oDiv1,0);
function downMove(ele,ele2,adsorb){
ele.onmousedown = function(ev){
var ev = ev || event;
if(ele.setCapture){ele.setCapture();}
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var disY = ev.clientY - ele.offsetTop + scrollTop;
document.onmousemove = function(ev){
var ev = ev || event;
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var eleTop = eleHeight = null;
if(ele2 == 'allWindow'){
eleTop = scrollTop;
eleHeight = document.documentElement.clientHeight;
}else{
eleTop = ele2.offsetTop;
eleHeight = ele2.offsetHeight;
}
var oTop = ev.clientY - disY + scrollTop;
if(oTop<eleTop +adsorb){
oTop = eleTop;
}
if(oTop>eleTop+eleHeight-ele.offsetHeight -adsorb){
oTop = eleTop+eleHeight-ele.offsetHeight;
}
ele.style.top = oTop + 'px';
}
document.onmouseup = function(){
if(ele.releaseCapture){ele.releaseCapture();}
document.onmousemove = document.onmouseup = null;
}
return false;
}
}
</script>
</body>
</html>
练习5:做一个滚动条下拉一个元素高度跟着改变,直到元素高度等滚动条高度
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
#box{width:20px; height:60px; background-color:red; position:absolute; left:500px; top:100px; z-index:5;}
#box1{width:20px; height:1000px; background-color:green; position:absolute; left:500px; top:100px; z-index:3;}
#box2{width:100px;background-color:pink;position:absolute;top:100px; left:540px; }
</style>
</head>
<body>
<body style="height:2000px;">
<div id="box"></div>
<div id="box1"></div>
<div id="box2"></div>
<script>
var oDiv = document.getElementById('box');
var oDiv1 = document.getElementById('box1');
var oDiv2 = document.getElementById('box2');
downMove(oDiv,oDiv1,oDiv2);
function downMove(ele,ele2,ele3){
ele.onmousedown = function(ev){
var ev = ev || event;
if(ele.setCapture){ele.setCapture();}
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
var disX = ev.clientX - ele.offsetLeft + scrollLeft;
var disY = ev.clientY - ele.offsetTop + scrollTop;
document.onmousemove = function(ev){
var ev = ev || event;
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
var oTop = ev.clientY - disY + scrollTop;
if(oTop<ele2.offsetTop){
oTop = ele2.offsetTop;
}
if(oTop>ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight){
oTop = ele2.offsetTop+ele2.offsetHeight-ele.offsetHeight;
}
ele3.style.height=(ele.offsetTop-ele2.offsetTop)*ele2.offsetHeight/(ele2.offsetHeight-ele.offsetHeight) + 'px';
ele.style.top = oTop + 'px';
}
document.onmouseup = function(){
if(ele.releaseCapture){ele.releaseCapture();}
document.onmousemove = document.onmouseup = null;
}
return false;
}
}
</script>
</body>
</html>