/?" 五. 声明性Dropzone
我们可以在一个页面上拖动HTML元素,然后让它们位于其投放位置。然而,为了使该行为真正有用,当投放发生时,应该抛出一个事件。而且,所抛出的事件应该依赖于在何处发生投放。换句话说,需要把行为添加到一个给定HTML元素-由它来把这一行为转换成一个"dropzone"或"投放目标",可以使用相同的方法把漂浮行为添加到一个HTML div标签以便把它转换成一个可拖放的元素。
在下列例子中,我将向你展示Atlas是如何支持dropzone概念的。在它的当前状态中,Atlas并不支持与其支持漂浮元素一样的方式来提供一种现成的行为以支持创建dropzone元素。然而,它确实实现了一个DragDropList元素和一个DraggableListItem元素的行为(这两个元素联用,允许你创建能够通过拖放重新排序的列表)。如果你想进一步探讨这一功能,你可以在网上找到若干使用DragDropList行为的好例子,例如,《Introduction to Drag And Drop with Atlas》。
dragdropzone行为的主要不利条件是,它仅与具有DragDropList行为的项一起工作。为了确定我上面描述的开放端点的dropzone功能的类型(它将与预定义的漂浮行为一同使用),你需要用JavaScript编写你自己的dropzone行为类。幸好,这并不困难。
Atlas把若干OOP扩展添加到JavaScript中以使加强其扩展能力,例如命名空间,抽象类和接口。在编写你自己的dropzone行为时你还要利用这些工具。如果你分析一下AtlasUIDragDrop.js文件的源码(可以使用Visual Studio调试器),那么你会发现在那里定义了若干接口,这包括一个相应于Sys.UI.DragSource而另一个相应于Sys.UI.DropTarget。事实上,FloatingBehavior类和DraggableListItem类都实现了Sys.UI.DragSource接口,而Sys.UI.DropTarget被DragDropList类所实现。这两个接口的代码如下所示:
Sys.UI.IDragSource = function() {
this.get_dataType = Function.abstractMethod;
this.get_data = Function.abstractMethod;
this.get_dragMode = Function.abstractMethod;
this.onDragStart = Function.abstractMethod;
this.onDrag = Function.abstractMethod;
this.onDragEnd = Function.abstractMethod;
}
Sys.UI.IDragSource.reGISterInterface('Sys.UI.IDragSource');
Sys.UI.IDropTarget = function() {
this.get_dropTargetElement = Function.abstractMethod;
this.canDrop = Function.abstractMethod;
this.drop = Function.abstractMethod;
this.onDragEnterTarget = Function.abstractMethod;
this.onDragLeaveTarget = Function.abstractMethod;
this.onDragInTarget = Function.abstractMethod;
}
Sys.UI.IDropTarget.registerInterface('Sys.UI.IDropTarget');
为什么你需要实现这些接口而不是简单地编写一些新类来支持拖放和dropzone呢?秘密是,在后台,还有一个类DragDropManager,负责实际协调可拖放元素与dropzone元素之间的交互,并且它仅仅知道如何与实现IDragSource或IDropTarget接口的类一起工作。这个DragDropManager类注册对于每一个可拖放的元素来说哪些dropzone是合法的目标,并处理MouseOver事件以决定何时一个dropzone上面具有一个可拖放的元素,以及其它你不需要自己做的大量事情。事实上,它处理得如此完美,以至后面你要编写的dropzone行为需要极少的代码。首先,创建一新的JavaScript文件DropZoneBehavior.js。我把我的JavaScript文件放到了一个子目录scriptLibrary下,但是,这对于实现dropzone行为是不必要的。然后,把下列代码复制到你的文件中:
Type.registerNamespace('Custom.UI');
Custom.UI.DropZoneBehavior = function() {
Custom.UI.DropZoneBehavior.initializeBase(this);
this.initialize = function() {
Custom.UI.DropZoneBehavior.callBaseMethod(this, 'initialize');
//把我们自己注册为一个拖放目标.
Sys.UI.DragDropManager.registerDropTarget(this);
}
this.dispose = function() {
Custom.UI.DropZoneBehavior.callBaseMethod(this, 'dispose');
}
this.getDescriptor = function() {
var td = Custom.UI.DropZoneBehavior.callBaseMethod(this, 'getDescriptor');
return td;
}
//IDropTarget成员.
this.get_dropTargetElement = function() {
return this.control.element;
}
this.drop = function(dragMode, type, data) {
alert('dropped');
}
this.canDrop = function(dragMode, dataType) {
return true;
}
this.onDragEnterTarget = function(dragMode, type, data) {}
this.onDragLeaveTarget = function(dragMode, type, data) {}
this.onDragInTarget = function(dragMode, type, data) {}
}
Custom.UI.DropZoneBehavior.registerClass('Custom.UI.DropZoneBehavior',
Sys.UI.Behavior, Sys.UI.IDragSource,
Sys.UI.IDropTarget, Sys.IDisposable);
Sys.TypeDescriptor.addType('script', 'DropZoneBehavior',
Custom.UI.DropZoneBehavior);
我需要解释一下这个类。首先要注意从第二(以"Custom.UI.DropZoneBehavior.registerClass"开始)到最后一行代码。这是上面定义的dropZoneBehaviorClass注册到Atlas的位置。registerClass方法的第一个参数相应于类的名字,第二个参数则相应于基类的名字。第三个参数相应于实现新类的接口。接下来的一行代码使你的类可用于声明性标记脚本。现在,我们回到开始,"Type.registerNamespace"方法允许你注册你的定制命名空间。下一行使用一个匿名方法语法声明我们的新类。这里使用了JavaScript面向对象的设计思想,这对于设计Atlas行为来说是必要的。在该匿名方法中,类方法Initialize,Dispose和getDescriptor都是一些简单的标准方法,用于所有的行为类,而且在这个简单实现中,你仅需要调用基方法(也就是,从这个例子的第二到最后一行代码中所指定的基类的方法)即可。你要做的唯一特别的一点是,使用在Initialize方法中的Sys.UI.DragDropManager来注册拖放目标。这里是大部分的拖放"魔术"所在。
然后,你实现IDropTarget方法。在这个例子中,你仅实现了两个方法:this.canDrop与this.drop。对于canDrop,你只是简单地返回true。其实,更有趣的逻辑可以放到其中,譬如实现有哪些div标签被实际拖放到一个给定的目标上,或者决定相应于不同类型的漂浮div,在拖放它们时各自的不同行为;但是,在此情况下,你仅想简单地实现IDropTarget-它允许任何漂浮div拖动到其上。你的"drop"方法的实现只是个框架而已。当一个漂浮元素被拖放到你的拖放目标之一时,将显示一条警告消息指示已经发生了一些事情。现在,你已经有了一个拖放行为,它能够与我们在上一个例子中所用的漂浮行为一同工作。
现在你应该创建一个页面来展示你的新定制的dropzone行为。为此,你可以在前面示例的基础上来实现。在Atlas脚本管理器中,除注册AtlasUIDragDrop脚本以外,你还要注册你的新的DropZoneBehavior脚本:
<atlas:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<atlas:ScriptReference ScriptName="AtlasUIDragDrop" />
<atlas:ScriptReference Path="scriptLibrary/DropZoneBehavior.js" />
</Scripts>
</atlas:ScriptManager>
然后,你要把一个新的div标签添加到HTML体,这可以被用作一个拖放的目标:
<div style="background-color:Red;height:200px;width:200px;">
<div id="draggableDiv" style="height:100px;width:100px;background-color:Blue;">
<div id="handleBar" style="height:20px;width:auto;background-color:Green;">
</div>
</div>
</div>
<div id="dropZone" style="background-color:cornflowerblue;height:200px;width:200px;">
Drop Zone
</div>
最后,你需要添加一个声明性标记元素以添加你的定制DropZone行为到你计划用作一个dropzone元素的div。该XML标记应该有如下所示形式:
<script type="text/XML-script">
<page XMLns:script="http://schemas.microsoft.com/XML-script/2005">
<components>
<control id="dropZone">
<behaviors>
<DropZoneBehavior/>
</behaviors>
</control>
<control id="draggableDiv">
<behaviors>
<floatingBehavior handle="handleBar"/>
</behaviors>
</control>
</components>
</page>
</script>
刚才的代码把一个dropzone添加到最初声明的拖放示例中。当你在dropzone上拖动元素时,将出现一个警告消息框。你可以扩展这些代码以便使你的定制dropzone行为的drop方法实现一些更为有趣的事情,例如激活当前的页面中的其它JavaScript事件,甚至使用Atlas调用一个Web服务-由它来为你处理服务器端代码。
()。








