`
子衿青青
  • 浏览: 111564 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

用dojo.dnd实现拖放功能

 
阅读更多

<!-- [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 的核心组件之一,功能强大且代码优雅,相信你一定能从中学到不少东西。

分享到:
评论
1 楼 brown802 2013-04-07  

相关推荐

    dojo学习...........

    - DND(Drag-and-Drop):`dojo.dnd`模块实现了强大的拖放功能,使得交互操作更加直观。 学习Dojo不仅需要理解其模块和包的概念,还需要熟悉其API和组件系统,以及如何利用这些工具来构建高效、响应式的Web应用。...

    dojo api 中文版

    * dojo.dnd:拖放功能的辅助 API。 * dojo.string:字符串处理包,提供了修整、转换为大写、编码、esacpe、填充等功能。 * dojo.date:日期格式解析的有效助手。 * dojo.event:事件驱动的 API,支持 AOP 开发,以及...

    DOJO API 中文参考手册,附加注解实例(精心重新排版DOC文档)

    dojo.dnd提供拖放功能的API,dojo.string提供了字符串处理方法,dojo.date帮助解析和操作日期,dojo.event处理事件驱动和AOP开发,dojo.back管理撤销操作的栈,dojo.rpc用于与后端服务通信,dojo.data是统一的数据...

    DOJO开发指南(结合DOJO中国及网上的资料整理的结果)

    - **包系统**:基础层,按功能划分API,如`dojo.io`处理IO操作,`dojo.dnd`实现拖放功能。 - **语言库**:提供通用语言工具,如字符串处理、日期解析等。 - **环境相关包**:处理浏览器兼容性问题,确保DOJO在不同...

    Dojo工具使用说明

    4. **dojo.dnd**:实现了拖放功能的API,可以轻松创建支持拖放操作的应用程序。 5. **dojo.event**:事件管理API,支持面向切面编程(AOP)以及主题/队列功能,使事件处理更加灵活。 6. **dojo.lfx**:HTML和SVG的...

    dojo 树形列表 dijit.tree

    这涉及到`dojo.dnd.Source`和`dojo.dnd.Manager`模块,它们提供了拖放功能的核心。通过监听拖放事件,可以控制节点的移动、复制和删除。确保正确处理数据模型的更新,以保持视图和数据的一致性。 5. **数据库读取并...

    dojo study keep moving

    而“dojo.dnd”模块则包含了一系列与拖放操作相关的类,如 `HtmlDragObject`。 ##### 3.2 名称约定 Dojo 在命名模块时遵循一定的规则。一般来说,函数名的首字母为小写,而类名的首字母为大写。例如,“dojo....

    dojo中文文档分析与介绍

    - **dojo.dnd**:拖放功能的API。 - **dojo.event**:事件处理API,支持AOP和DOM事件的管理。 - **dojo.lfx**:HTML和SVG动画的支持,以及动画效果的实现。 - **dojo.fx**:特效支持,通常选择与dojo.lfx一起使用。 ...

    dojo控件的使用和入门心得

    - **dojo.dnd**:实现拖放功能。 - **dojo.string**:字符串处理工具,包括大小写转换、编码解码等。 - **dojo.date**:日期格式解析。 - **dojo.event**:事件驱动API,支持主题与队列功能。 - **dojo.data**:统一...

    DOJO_API_中文参考手册 附加注释实例

    - dojo.dnd:提供拖放功能的辅助API。 - dojo.string:处理字符串,包括修剪、大小写转换、编码、填充等。 - dojo.date:解析日期格式的工具。 - dojo.event:事件驱动的API,支持面向切面编程(AOP)开发。 - ...

    DOJO 中文 开发手册

    - **dojo.dnd**:支持拖放功能的API。 - **dojo.string**:处理字符串的工具,如修剪、大小写转换、编码等。 - **dojo.date**:日期解析和格式化助手。 - **dojo.event**:事件驱动API,支持面向切面编程和队列管理...

    掌握 Dojo 工具包---出自IBM

    2. **dojo.dnd**:辅助实现拖放功能。 3. **dojo.string**:字符串处理,如修剪、大小写转换、编码等。 4. **dojo.date**:日期解析和格式化工具。 5. **dojo.event**:事件驱动API,支持面向切面编程和队列管理。 6...

    Dojo 教程 笔记 (转载)

    例如,`dojo.html`模块提供了一系列处理HTML内容的函数,如`dojo.html.getContentBox()`,而`dojo.dnd`模块则包含了用于HTML拖放操作的相关类。 Dojo的模块和包管理机制允许按需加载,这在优化性能和减小网络传输量...

    dojo api最好资料

    - `dojo.dnd`:支持拖放功能。 - `dojo.string`:提供了字符串处理方法,如修剪、大小写转换等。 - `dojo.date`:用于日期格式化和解析。 - `dojo.event`:实现了事件驱动API,支持面向切面编程。 - `dojo.back...

    dojo api 1.0 中文文档

    - **dojo.dnd**:支持拖放功能。 - **dojo.string**:提供字符串处理方法,如修整、转换大小写、编码等。 - **dojo.date**:帮助解析日期格式。 - **dojo.event**:支持事件驱动的 API,可用于 AOP 开发及主题/队列...

    introduction to dojo toolkit(SUN)

    Dojo Toolkit 支持前进后退按钮以及书签功能,这意味着即使是在动态加载内容的情况下,用户也可以像使用传统 Web 页面一样使用浏览器的历史记录功能。这对于提升用户体验至关重要。 #### 4. 事件系统 (Dojo Event ...

    Dojo之路:如何利用Dojo实现Drag and Drop效果

    本文将详细介绍如何利用Dojo框架实现Drag and Drop功能,并通过一个简单的示例来展示其实现过程。 #### Dojo简介 Dojo是一个开源的JavaScript库,主要用于简化复杂的客户端脚本开发。它提供了丰富的UI控件、数据...

Global site tag (gtag.js) - Google Analytics