既然说是入门,本文给出的函数都尽可能短小,但不失强大,并兼容所有浏览器。要想拖动页面上的一个元素,说白了就是让它实现位移。CSS中最能体现这种思想的是绝对定位,因为绝对定位能使元素脱离原来的文档流,但原来的物理空间还保留着,这就不影响周围的元素了。接着下来就是设置事件侦听器,分别在mousedown,mousemove,mouseup绑定对应的回调函数,一旦触发这些事件,浏览器就会自动调用它们。我们分别把这些回调函数命名为dragstart,drag与dragend。
为了共享方法,我们把它们都做成原型方法。
01.var Drag = function(id){
02. this.node = document.getElementById(id);
03. this.node.style.position = "absolute"
04. this.node.me = this;//保存自身的引用
05. this.node.onmousedown = this.dragstart;//监听mousedown事件
06.}
07.Drag.prototype = {
08. constructor:Drag,
09. dragstart:function(e){
10. var e = e || window.event,//获得事件对象
11. self = this.me,//获得拖动对象
12. node = self.node;//获得拖动元素
13. //鼠标光标相对于事件源对象的坐标
14. node.offset_x = e.clientX - node.offsetLeft;
15. node.offset_y = e.clientY - node.offsetTop;
16. node.onmousemove = self.drag;//监听mousemove事件
17. node.onmouseup = self.dragend;//监听mouseup事件
18. },
19. drag:function(e){
20. var e = e || window.event,//获得事件对象
21. self = this.me,//获得拖动对象
22. node = self.node;//获得拖动元素
23. node.style.cursor = "pointer";
24. //将拖动的距离加再在原先的left与top上,以实现位移
25. !+"\v1"? document.selection.empty() : window.getSelection().removeAllRanges();
26. node.style.left = e.clientX - node.offset_x + "px";
27. node.style.top = e.clientY - node.offset_y + "px";
28. node.onmouseup = self.dragend;//监听mouseup事件
29. },
30. dragend:function(){
31. var self = this.me,//获得拖动对象
32. node = self.node;//获得拖动元素
33. node.onmousemove = null;
34. node.onmouseup = null;
35. }
36.}
运行代码
现在我们的类就可以运作了,但正如你们所看到的那样,当鼠标拖动太快会出现鼠标移出div的情况。这是因为移动得越快,位移的距离就越大,拖动元素一下子从我们的鼠标溜走了,就无法调用mouseup事件。在IE中我们可以利用setCapture()来补救,但一旦某个元素调用setCapture(),文档中所有后续的鼠标事件都会在冒泡之前传到该元素,直到调用了releaseCapture()。换言之,在完成这些鼠标事件之前,它是不执行其他事件,一直占着线程,于是出现了我们的光标离开拖动元素的上方也能拖动元素的怪异现象。
运行代码
你在拖动块上点一下,然后再到拖动块外面点一下,就可以实现"隔空拖动"的神奇效果了!(当然只限IE)
由于鼠标事件一直接着线程,所以在我们不用的时候,一定要releaseCapture()来解放它。
在firefox中我们可以使用window.captureEvents(),火狐说这方法已经废弃,但我怎么在各标准浏览器中运作良好呢?!不过不管怎么样,来来回回要设置捕获与取消捕获非常麻烦与吃内存,我们需要转换思路。因为如果鼠标离开拖动元素上方,我们的绑定函数就无法运作,要是把它们绑定在document上呢,鼠标就无论在何处都能监听拖动元素。但触发拖动的onmousedown事件我们还保留在拖动元素上,这事件不会因为不执行就引起差错之虞。不过,由于绑定对象一变,我们要在这些事件中获得拖动对象的引用的难度就陡然加大,这里我就直接把它们做成构造函数内的私有函数吧。
01.var Drag = function(id){
02. var el = document.getElementById(id);
03. el.style.position = "absolute";
04. var drag = function(e) {
05. e = e || window.event;
06. el.style.cursor = "pointer";
07. !+"\v1"? document.selection.empty() : window.getSelection().removeAllRanges();
08. el.style.left = e.clientX - el.offset_x + "px";
09. el.style.top = e.clientY - el.offset_y + "px";
10. el.innerHTML = parseInt(el.style.left,10)+ "X"+parseInt(el.style.top,10);
11. }
12.
13. var dragend = function(){
14. document.onmouseup = null;
15. document.onmousemove = null;
16. }
17.
18. var dragstart = function(e){
19. e = e || window.event;
20. el.offset_x = e.clientX - el.offsetLeft;
21. el.offset_y = e.clientY - el.offsetTop;
22. document.onmouseup = dragend;
23. document.onmousemove = drag;
24. return false;
25. }
26. el.onmousedown = dragstart;
27.}
运行代码