上一篇,我们了解了KitJs的基本的事件管理架构,在kit.js核心的js包里面通过自己的事件匿名函数来托管用户注册时间,实现事件的执行顺序以及保存事件句柄。
今天我们来了解下Kit是如何实现拖拽事件的,Demo地址:http://xueduany.github.com/KitJs/KitJs/demo/Puzzle/demo.html
KitJs官网:http://xueduany.github.com/KitJs
Source Code:https://github.com/xueduany/KitJs
不同于上一篇介绍的两个事件方法ev和delEv,对于增强型事件,即可能是浏览器自带的,但是存在复杂的兼容问题,或者是浏览器不带的,需要多次复合运算才能实现的事件,比如鼠标手势,画圈等等,kit统一使用Event.js进行管理。
Event.js的API DOC:http://xueduany.github.com/jsdoc/out/$Kit.Event.html
基本的事件注册机制是和上一篇介绍的完全一样,我们只是在浏览器兼容以及Event Object增强上做了手脚。
我们都知道目前市面上很多很多的js框架都是通过mousemove模拟的方式,判断拖拽元素的offset与目标元素的offset来实现拖拽。其主要原因是IE对于drag/drop的不支持,其实事实的真相真的是这样的吗?
我们可以看到微软自己的API DOC:http://msdn.microsoft.com/en-us/library/ie/ms536923(v=vs.85).aspx
他提供了详细的支持drag事件的元素列表
The pEvtObj parameter is required for the following interfaces:
- HTMLAnchorEvents2
- HTMLAreaEvents2
- HTMLButtonElementEvents2
- HTMLControlElementEvents2
- HTMLDocumentEvents2
- HTMLElementEvents2
- HTMLFormElementEvents2
- HTMLImgEvents2
- HTMLFrameSiteEvents2
- HTMLInputFileElementEvents2
- HTMLInputImageEvents2
- HTMLInputTextElementEvents2
- HTMLLabelEvents2
- HTMLLinkElementEvents2
- HTMLMapEvents2
- HTMLMarqueeElementEvents2
- HTMLObjectElementEvents2
- HTMLOptionButtonElementEvents2
- HTMLScriptEvents2
- HTMLSelectElementEvents2
- HTMLStyleElementEvents2
- HTMLTableEvents2
- HTMLTextContainerEvents2
- HTMLWindowEvents2
- HTMLDocumentEvents4
- HTMLWindowEvents4
可惜MSDN给出的文档上,只给了文字和form元素的例子,我们很多时候需要拖拽的是一个div Block元素,肿么办?
dottora给出了这个API:http://help.dottoro.com/ljmojcxu.php
结合我给出的这个例子: http://xueduany.github.com/KitJs/KitJs/demo/DragDrop/demo.html
我们可以发现,IE也是支持Bloack元素的拖拽的
秘密在哪儿呢?
查看Kit源代码,我们可以发现
Event.js里面,对于IE如果绑定的是drag类的事件,他做了两件事
1. 注册一个mousedown事件
2. 在mousedown事件里面执行元素的dragDrop方法
这两件事情很有意思,这样你就会惊喜的发现,在IE里面,原来不能拖动的block元素可以拖动了。一切就是这么的神奇。
相对于IE来说,其他的浏览器就显得简单了,只要支持HTML5的浏览器,我们只需要
设置元素的draggable属性为true即可拖动。
drop事件需要注意的是,必须要取消drop目标的dragOver默认事件,否则目标的drop事件不会触发,就像这样,全浏览器皆如此
以上的代码已经搞定了IE+高级浏览器的dragDrop事件了,现在唯一的问题就是
1. drag和drop是在不同元素上注册的事件,drag注册在拖动目标上,drop注册在需要drop的目标上。所以产生的EventObject不相同
2. 原生的drop事件,没有dragElement,他是通过事件的dataTranfer成员传递对象的,而dataTransfer成员是个剪贴板,只能保存String
所以肿么办?肿么办?
别急,如果你好好的看懂了我们上一篇介绍的KitJs高级事件管理的话,你一定会想到我们说的Event Object增强。
对,KitJs就是这么做的!
由于Js是单线程的,所以同一时间触发的drag事件,只有一个dragElement,利用这个特性,KitJs决定把这个dragElement引用保存在Event.js的实例中
上图的代码中,Kit注册了dragStart事件,将当前拖拽的元素,保存在Kit.Event实例kit.event里面
回顾上一篇,我们介绍了Kit的ev方法里面,会在托管事件的匿名函数中,给当前的EventObject合并一些额外的数据,来增强事件
Kit.Event采用同样的原理,而且KitEvent需要合并的数据更多,更可控,它自己保存了一个Event Object增强信息的数组,叫做eventExtraInfoFnArray,数组里面可以存放Function以及Map类型,用户可以通过暴露接口让用户自己选择给EventObject增强哪些数据,如果是Map,就直接mergeIf,如果是Function,就传入当前EventObejct,并执行Function,将返回值mergeIf
*Kit.Event重构了evExtra方法,原来在kit.js里面事件托管匿名函数中,用来增强Event Object,插入一些我们需要的额外信息的方法
因为dragDrop的执行顺序是drag->drop
所有只要有drag事件,触发,当前的dragElement就被保存在KitEvent实例中,这样到drop事件时,由于evExtra方法的缘故,KitEvent中的dragElement就被插入到drop事件的EventObject里面,这样在drop事件,既可以取到当前拖拽的元素了。
(当然,有人会问,按照这样的说法,kitEvent的dragElement岂不是一直被覆盖吗?就算没有发生drag事件,或者drag事件已经结束了,KitEvent的dragElement还存在吗?)
Kit会自己注册一个dragEnd事件,用于清除KitEvent的dragEleemnt以及相关的extraEventInfo
Kit通过注册dragStart事件,保存拖拽刚开始时候,拖拽元素的坐标信息
注册drag事件,获取鼠标移动的位移信息,根据之前的初始信息,移动元素的位置,实现拖拽
Demo:http://xueduany.github.com/KitJs/KitJs/demo/Dialog/demo.html
这里由于Firefox浏览器一向的垃圾以及BUG满天飞,Kit暂时无法获取FF下drag事件的鼠标移动数据,只有当dragEnd时,才能移动元素,敬请原谅。
这一篇的信息量比较大,可能需要有一定基础的同学才能看明白,如果有任何不明白的地方,可以留言,我会耐心解答
补充下:
”firefox下无法获取drag事件的鼠标位置,这个bug是真的:
https://bugzilla.mozilla.org/show_bug.cgi?id=590355