EXT 树的拖放

新0.40版的yui-ext将带有TreePanel 组件。本文会针对该组件讨论一些需要考虑的事情,一些关键的功能,和看看几个例子的执行方式。别犯困,我保证这些例子绝对值得一读!

重新开发 Tree组件的原因

最初我打算对YUI自带的TreeView组件进行扩展,但不幸地是,由于其采用Table的方式来布局Tree节点,要弄起Drag& Drop来就不太方便了,而且还有其它的问题....本文的目的不是在抱怨YUI TreeView的不是。YUI旨在各种环境中提供一个较单一的执行方式,一个轻型的库。

在新版的组件中加入了若干关键的功能,并且从总体设计上进行改进,以便能够更进一步地自定义实现执行。对于很感兴趣的一些用户,他们的赞助、捐献亦促成了这个组件的开发。(暗示Jack会聆听用户的需求)

设计考虑
开发组件的第一步:将逻辑子组件和可复用代码分类。就像Gird组件,其设计目标是,能够以某种方式,在不被其它组件的影响下,自定义tree里面的单个节点(如selection model)
数据结构 - YAHOO.ext.data.Tree/Node
运行TreePanel的核心是树结构本身( Tree structure)。Tree类 和 Node类与TreePanel没什么联系,只适合不用UI设计或太多功能的Tree数据结构。在后面的组件中会派上用场,像 TreeGrid或 菜单或任何你想得出来需要用“分级数据结构”的地方。Tree的API亦支持大多数的DOM操纵,例如appendChild(), insertBefore(), firstChild, lastChild, nextSibling, 和一些有用的函数,如sort(), cascade() and bubble()等等。
关于Tree structure最特别的地方是其暴露出来的 事件突变mutation event。 结构里的每项操作 (如append, insert, remove, move等等)都会触发一个事件. 当某些内容改变时便会触发事件通知你, 另有在操作发生之前的触发的事件,允许你中断或(同时)取消操作的事件。
事件上报Bubbling
所有事件触发在节点上,然后冒泡到Tree,使得你可以侦听某个单独节点上关联的事件。
逻辑层 - TreePanel/TreeNode/AsyncTreeNode
逻辑层让TreePanel运行起来。该类增加了一些TreePanel组件所需的功能,好像展开、收缩,UI层事件的排列。 它也定义了一些“主事件”( host of other events), 如 expand, collapse, click, dblclick, contextmenu, 等等。像上述的 tree/node操作,大多数这类事件有一个 之前的 等价物 ,允许你override/cancel 默认的动作和事件。这些事件触发在节点并且冒泡(bubble up)到主TreePanel实例1
UI 层 - TreeNodeUI
默认地,每个元素使用TreeNodeUI,TreeNodeUI通过treeNode.ui 属性来可用。来默认 UI 类 提供如 highlight(), focus(), getAnchor(), getTextEl(), getIconEl()的函数, 那你可以获取UI元素节点上的引用(References) ,或者一旦其被渲染后,触发UI update。由于UI在节点与其动作Behaviors之间作出了分离,你可以随便地自定义UI而不受其它组件的影响。
Drag and Drop拖放功能
新0.40放在SVN上,一个高性能的 Drag and Drop包. YAHOO.ext.dd 扩展了 YUI Drag and Drop的代码提供了一些好玩你的、必须的新功能。
Overflow Scrolling滚动溢出
很多时候,拖放的目标区域应该是可溢出的区域。YAHOO.ext.dd.ScrollManager为所有登记好的溢出区域,提供一个可配置的,自动滚动,带动画效果的对象。
DragSource/DropTarget 拖放源、拖放目标
这两个类推翻了原YUI的拖放事件。当拖放发生时,提供一个反馈到用户。
改写事件
YUI的拖放有一样东西我感到奇怪的是,被拖动的那项,拥有100%的拖放控制权。这些拖放操作跟在桌面上的类似,必须知道对方是怎么运作的。一般来说,目标Target只是为允许放到其身上的内容服务。在这两个扩展中,已一一修正。
对用户提供反馈信息

当进行拖动的时候。目标对DragSource拖动源作出一个反馈,表明它是否允许放进来Drop,并提供自定义的信息(例如,可添加或可插入)。用户看到这熟悉的icon,就好像在用windows或MacOS

DragZone/DropZone
第二个我遇到的问题是,大量Drag and Drop的实例,带来性能上的下降。例如,你拖动一个节点到Tree的时候,那个Tree会自动展开,其实是有点延迟的。当节点展开, YUI DragDropMgr必须刷新这个页面上DD元素的 locationCache。 10到20个元素是没问题,但一个有500或1000节点的Tree。浏览器会因为Cache不断刷新而锁定,导致很糟糕的用户体验。如果进行滚动 Scrolling的话,ScrollManager又会刷新每个Scroll的cache。
YUI.Ext Grid组件也正是遇到这种问题(对所有 行委托Delegating拖放),继而我创建两个类DragZone和DropZone,打算用于整体元素的高性能的拖放。窥见其中,它是利用 mouseover目标和mouseover事件决定DD操作的目标,而不是用cache。忠告一样东西,因为它使用了事件机制代替了cached regions,它只能用于Point Mode,不支持intersect mode.
结果是?拖放一个1000节点的TreePanel如同10个节点。实际上,在我的测试中,我一边load两个TreePanel,一边用包含1000节点的contaniner作拖放。无论滚动还是拖放页面元素到TREE都表现的没什么瑕疵。
这两个类的设计目的是自定义怎样查找拖放的元素。默认它使用了YAHOO.ext.dd.Registry来查找元素和句柄,而且更能轻松地自定义一个事件基本的查找(event based lookup,如JsonView Container)我将会在后面的帖子再讨论. 我决定再做第三个例子,以便演示委托DD查找 (还有委托多个元素的拖放).
Feedback
我把一些页面放在一起了,最后的那个挺COOL的,其它的标准。
渲染节点,一个简易例子:

树之间的拖放,异步加载和节点排序

用拖放来组织图片,实现了用JSON视图和其它好玩的东西做的DragZone。
特点
下面是当前的功能列表。期待你的反馈,哪怕是古灵精怪的想法也好。
  • 高性能的拖放支持自动展开,排序和用户反馈自定义点。允许树与树之间、标准YUI DDTargets到树之间的拖放
  • 完整的键盘 expand/collapse操作。
  • 可自定义 selection models。有两种方式在SVN上, 默认的TreeSelectionModel (single selection)和一个 MultiSelectionModel.
  • 异步加载和渲染。同时亦有一个默认的 TreeLoader,用于执行JSON数据(XML本版待续)
  • 可在节点上即时编辑(inline Editor)
  • 支持树的突发事件(如上述)
  • 动态节点排序 包括一个 folderSort 选项 (folders顶部)
  • 内置、自动化 QuickTips 支持 (如上面截图的自定义 HTML tooltips)
  • 可选渲染根节点
  • 可通过Tree冒泡Bubbing和自定义层叠的逻辑
  • 基本 TreeFilter 执行
保持不懈的开发!

整个圣诞假期我犹如疯子般地工作,为新版Yui-ext 4.0。包括TreePanel、之前发布的DD包、新QucikTips组件,InlineEditor、各种常用类、一个新主题方案、两个仿 Vista主题。这都要大量的时间和人力,开发YUI-ext百分百靠来自使用者捐献/赞助的基金。而且我则付出110%的力量来开发和支持这个库。我每个礼拜七天都不够用,每天工作超过12个小时。如果你觉得它帮到你,别忘了报答一下(如,点击一下BLOG上广告)。只有你的支持,我才能够再接再厉,全职做好Yui-Ext!


下载代码

最新版的YUI-EXT可以在http://code.google.com/p/yui-ext找到大多数新代码是没归档的,但这些代码是OK的,而0.40就快发布了。所有东西也会照旧地放入文档。如果你不知道SVN,装不了JS BUILDER,或压根懒得做,那留下你的EMAIL或直接在BBS上发我私人信息,我会发个ZIP给你的了~谢

译者姓名:Frank
译者博客:http://www.ajaxjs.com/blog/