<!-- [if gte mso 9]><xml><w:WordDocument><w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel><w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery><w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery><w:DocumentKind>DocumentNotSpecified</w:DocumentKind><w:DrawingGridVerticalSpacing>7.8</w:DrawingGridVerticalSpacing><w:View>Normal</w:View><w:Compatibility></w:Compatibility><w:Zoom>0</w:Zoom></w:WordDocument></xml><![endif]-->
用dojo.dnd实现拖放功能
相信很多人都自己动手写过拖放。DHTML里做拖放的原理很简单,一般有这么三个阶段:mousedown
的时候做一些初始化,
mousemove
的时候更新拖放对象的位置,
mouseup
的时候再做一些清理工作。讲起来简单,但做起来总要花一些功夫的。
Dojo
的
dnd
模块提供了通用且功能强大的拖放支持,让我们可以不用自己造轮子,而且用起来也很方便。
废话少说,先来看看它到底有多方便。假设页面上有两个ul
,我们需要对
ul
里的
li
元素实现拖放,让它们可以自由地在两个列表间移动。如果自己手写,虽然不难但也要花点时间吧。用
Dojo
的话,除了加载模块之外,甚至连一行
javascript
语句都不需要:
这个例子用了host在google的dojo1.5版本,可以直接运行。这里唯一需要写的javascript
语句就是加载
dojo.dnd.Source
类。剩下的就是在要拖放的对象上做一些标记,用html和
CSSclass
就行了。而且
Dojo
为拖放对象添加的
CSSclass
非常丰富,让我们能自由定制它们的外观。
Fig.1: Source内部DnD
Fig.2: Source之间DnD
Fig.3: 在无法接受拖放内容的地方改变Avatar的外观
好,现在来仔细看一下dojo.dnd
模块到底是怎么一回事。
dojo.dnd包结构
打开dojo/dnd
源码文件夹,可以看到里面有很多东西:
Fig.4: dojo.dnd的目录结构
刚才用的
dojo.dnd.Source
就在Source.js里面。顾名思义,
Source
就是拖放源,一个存放可拖放对象的容器。相对的还有
dojo.dnd.Target(也在Source.js里)
,它继承了
dojo.dnd.Source
,不过只能接受从别处拖过来的东西,却不能拖出去。另一个Source的子类是AutoSource,如果你需要在运行时添加可拖放的结点(实时更新可拖放结点列表),那么它就是为你准备的。
Dojo.dnd
包中的几个主要类之间的关系大致是这样:
Fig.5: DnD包中主要类的结构
其中Container
是顶层基类,它的实例包含有一些子元素,能感知
onmouseover/onmouseout
事件,并且知道具体
over
的是哪个元素。
Selector
是
Container
的子类,让容器支持鼠标选择,可以支持单选或多选。
Avatar
就是在拖放时跟着鼠标跑的那个东西,一般会直接包含拖放对象的
dom
结点。而
Manager
(是一个
Singleton
)则统筹了整个
dnd
过程,管理拖放的起点和终点,以及负责创建、更新和销毁
Avatar
。
包里剩下的东西其实组成了一个子模块:
dojo.dnd.move
,如果你只是需要把某个
dom
结点拖来拖去,就应该用这个模块。这里只介绍
dojo.dnd
,以后再写
dojo.dnd.move
。
dojo.dnd工作流程
当你在要拖动的对象上按住鼠标左键并开始移动时,Source
会调用
Manager.startDrag
函数,标志拖放过程的开始。这个函数记录当前发起拖放的
Source
和拖放的结点,然后创建出
Avatar
,建立起一切必要的事件关联,并发布(
dojo.publish
)一个“开始拖放”(
/dnd/start
)的主题(
topic
)。
Dojo.dnd
里广泛采用主题广播的方式管理拖放过程,这样页面上所有的
Source
都能监听这些主题并作出反应。例如这个
/dnd/start
主题发布后,页面上所有的
Source
(包括刚才拖出来的那个)都将检查自己是否能够接受那些正在被拖动的结点(通过一个叫
checkAcceptance
的方法)。
这里有必要提一下默认的检查方法。Source
有一个属性叫
accept
,这是一个字符串数组,默认是
["text"]
,表示这个
Source
能够接受的东西只限于包含文本的结点。你可以自由定义
accept
里的内容,这将在下一节具体解释。
当这些结点被拖到一个Source
上时(
onmouseover
),将使
Manager
发布
/dojo/source/over
主题,更新
Avatar
上的图标,以反映是否能在这个
Source
上
Drop
。
当你释放鼠标的时候,首先触发Manager
对
onmouseup
事件的响应函数。这个函数将判断当前是否有
Source
能够接受拖放的内容,如果有,就发布
/dnd/drop/before
以及
/dnd/drop
主题;如果没有,就发布
/dnd/cancel
主题。然后销毁
Avatar
、事件句柄、以及所有与本次拖放相关的信息。所有的
Source
都会监听这些主题,并作出相应的应对。
如果某个Source
在响应/dnd/drop主题时发现自己就是
Drop
的目标,就把这次拖放的结点传给一个叫
_normalizedCreator
的私有方法,该方法负责把这些结点转换成自己可以接受的形式。这里其实有一个定制点,让用户自定义转换的方式,这也将在下一节讲到。最后
insertNodes
方法把这些新结点插进来。如果做的是“移动”而不是“复制”(拖动时按住CTRL就是复制),还需要通知作为拖放起点的
Source
删除那些拖出来的子结点。
定制dojo.dnd
定制dojo.dnd
的基本方式和
dijit
类似,就是在构造函数中传入参数对象。如果是声明式创建,就可以直接用
html
属性的方式写在
html
元素中。
Dojo.dnd
具有非常多的定制点,一一列举会过于冗长,这里只挑最常用的几个。(当然,一旦你阅读了源码,完全可以抛开一切约束,通过继承的方式任意扩展
dojo.dnd
里的内容)
1.首当其冲是
accept
数组,刚才已经讲到,只有和这个数组有交集的拖放源才能被接受。例如,一个
Source
的
accept
数组是
["text","image"]
,另一个是
["image","video"]
,那么这两个
Source
就能接受从对方那里拖过来的东西。你肯定会问:为什么这是一个数组而不是单个字符串?答:对不同的拖放结点可以再定制其拖放类型。例如一个
Source
里可以既有
text
类型的结点,也有
image
类型的结点,你可以通过
dndType
属性在这些结点上做标记:
这样,如果你拖的是标记为text
的
li
元素,那么那个
accept=["image","video"]
的
Source
就无法接受它了:
Fig.6: 运用accept和dndType精确控制拖放
2.第二重要的个人感觉就是
creator
,前面提到,通过这个函数可以任意定制拖进来的东西。这个函数接受两个参数,一个是拖进来的
dom
结点的
innerHTML
(注:
Container
里说这是一个形如
{data:data,type:type}
的对象,但在
Source
的实际使用中,传的仅仅是
data
),另一个叫
hint
字符串,目前据我所知其唯一的可能值是
"avatar"
,表示创建出的结点是在
Avatar
中使用的。它需要返回一个形如:
{node:node,data:data,type:type}
的对象。这里的
node
可以跟传进来的那个没有半点关系。
Data
表示拖动的真正内容,一般就是
node.innerHTML
。
Type
就是这个结点的
dndType
。例如我要在传进来的内容前面加一点东西,可以这样写:
效果如图:
3.
一个简单但有用的开关属性:horizontal
。如果你的拖放源是一个横向容器,请把它设为
true
。
4.
三个很有用的且互相有关联的开关属性:copyOnly
默认
false,selfAccept
默认
true
,
selfCopy
默认
false
。顾名思义,如果
copyOnly
是
true
,那么这个
Source
里的东西只能被复制而不能被移走。当
copyOnly
是
true
,且
selfAccept
是
false
的时候,在容器内
dnd
也被禁止了。当
copyOnly
是
true
,
selfAccept
是
true
,且
selfCopy
是
true
的时候,容器内
dnd
的意思是复制而不是移动。
结语
本文很粗浅地介绍了dojo.dnd
包的基本用法,如果要深入了解,强烈建议阅读源码并不断实践。
Dojo.dnd
是
dojo
的核心组件之一,功能强大且代码优雅,相信你一定能从中学到不少东西。
分享到:
相关推荐
dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2
dojo.js.uncompressed.js 1.4.2dojo.js.uncompressed.js 1.4.2dojo.js.uncompressed.js 1.4.2
dojo.js.核心jsDojo.js核心dojo的javaScript类库Dojo.js核心dojo的javaScript类库Dojo.js核心dojo的javaScript类库Dojo.js核心dojo的javaScript类库
dojo.xd.js 最新JavaScript框架组件!
dojo.js
dojo.js.uncompressed.js 1.92版
Addison.Wesley.Dojo.Using.the.Dojo.JavaScript.Library.to.Build.Ajax.Applications.Jun.2008.pdf
domino xapges 其中的dojo.xhrGet 和 dojo.xhrPost例子
难得纯净资源,不用下载其他乱起八糟的东西了
一、 Dojo学习笔记(1. 模块与包) 1 二、 Dojo学习笔记(2. djConfig解说) 4 三、 Dojo学习笔记(3. Dojo的基础对象和方法) 6 四、 Dojo学习笔记(4. dojo.string & dojo.lang) 9 五、 Dojo学习笔记(5. dojo.lang.array ...
6 使用dojo.io.bind()的Ajax远程调用...................8 6.1.1 淡出和移除......9 6.1.2 使用XMLHttpRequest来告诉服务器发生了什么................... 9 7 拖放操作...................... 10 7.1.1 连接...
非常优秀的js框架dojo,目前版本1.9.3
Pragmatic.Bookshelf.Mastering.Dojo.Jun.2008.pdf
很不错的中文教程!文件太大分3个包! 目录如下: dojo精品中文教程 Dojo.1.0 Practice Note [1] 什么是dojo 选择dojo的理由 AJAX架构之Dojo篇 Adding Ajax中文版 (DoJo) ...利用Dojo实现拖动(Drag and Drop)效果
很不错的中文教程!文件太大分3个包! 目录如下: dojo精品中文教程 Dojo.1.0 Practice Note [1] 什么是dojo 选择dojo的理由 AJAX架构之Dojo篇 Adding Ajax中文版 (DoJo) ...利用Dojo实现拖动(Drag and Drop)效果
分三个包上传时,第三个包好像传不上去,我给整合了一下,打在一个包里上传了! dojo精品中文教程 Dojo.1.0 Practice Note [1] 什么是dojo 选择dojo的理由 ...利用Dojo实现拖动(Drag and Drop)效果
dojo核心文件,一款很好用的javascript库文件
pencil非常好用的web原型设计工具,这个是DOJO GUI的模板
ajax dojo 实现ajax
很不错的教程!文件太大分三个包上传的! 目录如下: dojo精品中文教程 Dojo.1.0 Practice Note [1] 什么是dojo 选择dojo的理由 AJAX架构之Dojo篇 Adding Ajax中文版 ...利用Dojo实现拖动(Drag and Drop)效果