纸头折飞机
欢迎大家加入KitJs官方高级QQ群88093625,讨论前端技术,上海携程招聘H5,iOS,android,产品,设计,交互,测试,有意者发简历到xueduanyang1985@163.com

上一篇,我们了解了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

(一)独立的Event.js

不同于上一篇介绍的两个事件方法ev和delEv,对于增强型事件,即可能是浏览器自带的,但是存在复杂的兼容问题,或者是浏览器不带的,需要多次复合运算才能实现的事件,比如鼠标手势,画圈等等,kit统一使用Event.js进行管理。

Event.js的API DOC:http://xueduany.github.com/jsdoc/out/$Kit.Event.html

基本的事件注册机制是和上一篇介绍的完全一样,我们只是在浏览器兼容以及Event Object增强上做了手脚。

(二)原生的Drag/Drop事件

我们都知道目前市面上很多很多的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元素的拖拽的

秘密在哪儿呢?

(三)IE原生拖拽Block元素的秘密

查看Kit源代码,我们可以发现

image

 

Event.js里面,对于IE如果绑定的是drag类的事件,他做了两件事

1. 注册一个mousedown事件

2. 在mousedown事件里面执行元素的dragDrop方法

这两件事情很有意思,这样你就会惊喜的发现,在IE里面,原来不能拖动的block元素可以拖动了。一切就是这么的神奇。

(四)HTML5 Support浏览器的拖拽

相对于IE来说,其他的浏览器就显得简单了,只要支持HTML5的浏览器,我们只需要

image

设置元素的draggable属性为true即可拖动。

(五)Drop事件

drop事件需要注意的是,必须要取消drop目标的dragOver默认事件,否则目标的drop事件不会触发,就像这样,全浏览器皆如此

image

(六)原生的Drop事件没有dragElement,肿么办?

以上的代码已经搞定了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的实例中

imageimage

上图的代码中,Kit注册了dragStart事件,将当前拖拽的元素,保存在Kit.Event实例kit.event里面

 

回顾上一篇,我们介绍了Kit的ev方法里面,会在托管事件的匿名函数中,给当前的EventObject合并一些额外的数据,来增强事件

Kit.Event采用同样的原理,而且KitEvent需要合并的数据更多,更可控,它自己保存了一个Event Object增强信息的数组,叫做eventExtraInfoFnArray,数组里面可以存放Function以及Map类型,用户可以通过暴露接口让用户自己选择给EventObject增强哪些数据,如果是Map,就直接mergeIf,如果是Function,就传入当前EventObejct,并执行Function,将返回值mergeIf

image

*Kit.Event重构了evExtra方法,原来在kit.js里面事件托管匿名函数中,用来增强Event Object,插入一些我们需要的额外信息的方法

image

 

因为dragDrop的执行顺序是drag->drop

所有只要有drag事件,触发,当前的dragElement就被保存在KitEvent实例中,这样到drop事件时,由于evExtra方法的缘故,KitEvent中的dragElement就被插入到drop事件的EventObject里面,这样在drop事件,既可以取到当前拖拽的元素了。

(当然,有人会问,按照这样的说法,kitEvent的dragElement岂不是一直被覆盖吗?就算没有发生drag事件,或者drag事件已经结束了,KitEvent的dragElement还存在吗?)

Kit会自己注册一个dragEnd事件,用于清除KitEvent的dragEleemnt以及相关的extraEventInfo

(七)draggable拖拽移动

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 
Bug 590355 - "drag"-event not containing mouse position 
悲剧的是,在Firefox 12还没有修复。 “ 

 

posted on 2012-05-03 14:04  薛端阳  阅读(9267)  评论(20编辑  收藏  举报