一直以来,都对JS获取元素的位置感到非常的困惑:一会client、一会offset、一会scroll。
再加上各大浏览器之间的不兼容,唉,搞得哥晕晕乎乎的。
而很多页面效果都要用到这些位置。不得已,得练练,得记记。
下面就来说说这个基于 JQuery的简易拖拽插件吧。
按惯例,先说说拖拽的原理,以及搞这么一个东东的步骤:
那什么是拖拽呢? 看名字就知道了:就是把一个东东拖来拽去的。 放到我们的DOM上,就是改变它的位置。
它只有两个难点:1、如何知道是在拖? 2、如何知道从哪拖,拖到哪?
其实,这也算不上难点,毕竟两者都是基础的东西,关键在于熟练。
换到js 中,我们搞一个拖拽效果,大致有如下步骤:
1、让元素捕获事件(一般情况下,无非就是mousedown、mousemove、mouseup)
2、在mousedown时,标记开始拖拽,并获取元素及鼠标的位置。
3、在mousemove时,不断的获取鼠标的新位置,并通过相应的位置算法,来重新定位元素位置。
4、在mouseup时,结束拖拽。。。然后周而复始。
这中间,个需要注意的地方:被拖拽的元素,至少需要相对或绝对定位,否则拖拽不会有效果。
OK,不多说,无代码,无真相。相应的解释都在其中了:
<!
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<
html
xmlns
="http://www.w3.org/1999/xhtml"
>
<
head
>
<
meta
http-equiv
="Content-Type"
content
="text/html; charset=utf-8"
/>
<
title
>
Jeremy - DragDrop Test !
</
title
>
<
meta
name
="keywords"
content
="Javascript自由拖拽类"
/>
<
script
type
="text/javascript"
src
="jquery-1.4.2.min.js"
></
script
>
<
script
type
="text/javascript"
>
(
function
($)
{
$.extend({
//
获取鼠标当前坐标
mouseCoords:
function
(ev){
if
(ev.pageX
||
ev.pageY){
{x:ev.pageX, y:ev.pageY};}
return
x:ev.clientX
+
document.body.scrollLeft
-
y:ev.clientY
+
document.body.scrollTop
-
};
//
获取样式值
getStyle:
function
(obj,styleName) {
return
obj.currentStyle
?
obj.currentStyle[styleName] : document.defaultView.getComputedStyle(obj,
null
)[styleName];
//
return obj.currentStyle ? obj.currentStyle[styleName] : document.defaultView.getComputedStyle(obj,null).getPropertyValue(styleName);
} });
//
元素拖拽插件
$.fn.dragDrop
=
function
(options)
{
var
opts
=
$.extend({},$.fn.dragDrop.defaults,options);
return
this
.each(
function
(){
//
是否正在拖动
var
bDraging
=
false
;
//
移动的元素
var
moveEle
=
$(
this
);
//
点击哪个元素,以触发移动。
//
该元素需要是被移动元素的子元素(比如标题等)
var
focuEle
=
opts.focuEle
?
$(opts.focuEle,moveEle) : moveEle ;
if
(
!
focuEle
||
focuEle.length
<=
0
)
{
alert(
'
focuEle is not found! the element must be a child of
'
+
this
.id);
return
false
;
}
//
initDiffX|Y : 初始时,鼠标与被移动元素原点的距离
//
moveX|Y : 移动时,被移动元素定位位置 (新鼠标位置与initDiffX|Y的差值)
//
如果定义了移动中的回调函数,该对象将以参数传入回调函数。
var
dragParams
=
{initDiffX:
''
,initDiffY:
''
,moveX:
''
,moveY:
''
};
//
被移动元素,需要设置定位样式,否则拖拽效果将无效。
moveEle.css({
'
position
'
:
'
absolute
'
,
'
left
'
:
'
0
'
,
'
top
'
:
'
0
'
});
//
点击时,记录鼠标位置
//
DOM写法: getElementById('***').οnmοusedοwn= function(event);
focuEle.bind(
'
mousedown
'
,
function
(e){
//
标记开始移动
bDraging
=
true
;
//
改变鼠标形状
moveEle.css({
'
cursor
'
:
'
move
'
});
捕获事件。(该用法,还有个好处,就是防止移动太快导致鼠标跑出被移动元素之外)
if
(moveEle.get(
0
).setCapture)
{
moveEle.get(
0
).setCapture(); }
//
(实际上是鼠标当前位置相对于被移动元素原点的距离)
//
DOM写法:(ev.clientX + document.body.scrollLeft - document.body.clientLeft) - document.getElementById('***').style.left;
dragParams.initDiffX
=
$.mouseCoords(e).x
-
dragParams.initDiffY
=
$.mouseCoords(e).y
-
moveEle.position().top;
});
//
移动过程
focuEle.bind(
'
mousemove
'
,
function
(e){
if
(bDraging)
{
//
被移动元素的新位置,实际上鼠标当前位置与原位置之差
//
实际上,被移动元素的新位置,也可以直接是鼠标位置,这也能体现拖拽,但是元素的位置就不会精确。
=
$.mouseCoords(e).x
-
dragParams.moveY
=
$.mouseCoords(e).y
-
dragParams.initDiffY;
//
是否限定在某个区域中移动.
//
fixarea格式: [x轴最小值,x轴最大值,y轴最小值,y轴最大值]
if
(opts.fixarea)
{
if
(dragParams.moveX
<
opts.fixarea[
0
]) {
dragParams.moveX
=
opts.fixarea[
0
] }
if
(dragParams.moveX
>
opts.fixarea[
1
])
{
dragParams.moveX
=
opts.fixarea[
1
]
}
if
(dragParams.moveY
<
opts.fixarea[
2
])
{ dragParams.moveY
=
opts.fixarea[
2
]
}
if
(dragParams.moveY
>
opts.fixarea[
3
])
{
dragParams.moveY
=
opts.fixarea[
3
]
} }
//
移动方向:可以是不限定、垂直、水平。
if
(opts.dragDirection
==
'
all
'
)
{
//
DOM写法: document.getElementById('***').style.left = '***px';
moveEle.css({
'
left
'
:dragParams.moveX,
'
top
'
:dragParams.moveY});
}
else
if
(opts.dragDirection
==
'
vertical
'
)
{
moveEle.css({
'
top
'
:dragParams.moveY});
}
else
if
(opts.dragDirection
==
'
horizontal
'
)
{
moveEle.css({
'
left
'
:dragParams.moveX});
}
//
如果有回调
if
(opts.callback) {
//
将dragParams作为参数传递
opts.callback.call(opts.callback,dragParams);
}
}
});
//
鼠标弹起时,标记为取消移动
'
mouseup
'
,
function
(e){
bDraging
=
false
;
moveEle.css({
'
cursor
'
:
'
default
'
});
if
(moveEle.get(
0
).releaseCapture)
{
moveEle.get(
0
).releaseCapture();
}
}); });
};
//
默认配置
$.fn.dragDrop.defaults
=
{
focuEle:
null
,
//
点击哪个元素开始拖动,可为空。不为空时,需要为被拖动元素的子元素。
null
,
//
拖动时触发的回调。
dragDirection:
'
all
'
,
//
拖动方向:['all','vertical','horizontal']
fixarea:
null
//
限制在哪个区域拖动,以数组形式提供[minX,maxX,minY,maxY]
}; })(jQuery);
//
test
$(
function
(){
//
限定区域,有回调函数。
$(
'
#dragDiv
'
).dragDrop({fixarea:[
0
,$(
'
#dragContainer
'
).width()
-
50
,
0
,$(
'
#dragContainer
'
).height()
-
50
],callback:
function
(params){
$(
'
#span1
'
).text(
'
X:
'
+
params.moveX
+
'
Y:
'
+
params.moveY); }});
//
默认设置
$(
'
#dragDiv1
'
).dragDrop(); });
</
script
>
</
head
>
<
body
>
<
div
id
="dragContainer"
style
="position:relative;left:10px;top:10px;border:1px dashed blue;width:500px;height:500px;"
>
<
div
id
="dragDiv"
style
="background-color:blue;height:50px;width:50px;"
>
</
div
>
<
div
id
="dragDiv1"
style
="border:1px solid red;height:50px;width:50px;"
>
</
div
>
</
div
>
<
span
id
="span1"
></
span
>
</
body
>
</
html
>