使用 AJAX 拖放的拼图游戏






4.74/5 (16投票s)
使用 ASP.NET 2.0 AJAX Futures November CTP 实现的拼图游戏。
- 下载示例 (Visual Studio 2005) - 637 KB
- 下载源代码 (Visual Studio 2005) - 648 KB
- 下载示例 (Visual Studio 2008) - 638 KB
- 下载源代码 (Visual Studio 2008) - 649 KB
- 在线演示 (已在 Vista 上的 IE7 中测试)
引言
本教程旨在快速解释如何使用 ASP.NET 2.0 AJAX Futures November CTP 实现拖放功能。为了解释这项技术,我创建了一个简单的项目,其中包含一个实现了拼图游戏的自定义 AJAX 控件。
背景
当我开始学习新的 ASP.NET AJAX 框架时,我让公司给我买了一本书,我选择了一本非常棒的书
在这本书中,我找到了一个解释如何使用 PreviewDragDrop
在 Web 上实现拖放功能的章节。我使用了这一章以及从互联网 (Google) 获得的其他信息来创建我的 AJAX 控件。
ASP.NET AJAX Framework
ASP.NET AJAX Framework 的基本思想是能够使用面向对象编程 (模拟 OOP) 的 JavaScript,并使其类似于 C#。大多数 C# 功能在 JavaScript 中都可用:命名空间、类、接口、枚举等。除了 OOP 功能外,还可以实现可视化的自定义控件 (客户端控件),从而扩展 HTML 元素的功能。
基本上,我们有两种类型的控件 (可视控件)
- 行为 (继承自
Sys.UI.Behavior
) - 控件 (继承自
Sys.UI.Control
)
区别仅仅在于逻辑,但通常 Sys.UI.Behavior
用于扩展不同类型 HTML 元素的行为,而 Sys.UI.Control
则用于扩展单一类型 HTML 元素的行为。
例如,如果我们想实现一个在点击事件上显示警报的行为,我们可以创建一个继承自 Sys.UI.Behavior
的类,然后我们可以将此代码用于多种 HTML 元素类型:DIV
、SPAN
、INPUT
等。
//Namespace declaration
Type.registerNamespace("MyNamespace");
//Constructor
MyNamespace.MyBehavior = function(element)
{
MyNamespace.MyBehavior.initializeBase(this, [element]);
}
MyNamespace.MyBehavior.prototype =
{
initialize : function()
{
// Add event handler on click
// Parameters:
// 1) The HTML element
// 2) Event name without "on" ("onclick"="click")
// 3) Control instance
$addHandlers(this.get_element(), { "click" : this._onClick }, this);
},
dispose : function()
{
// Remove all events handlers for the current HTML element
$clearHandlers(this.get_element());
},
// Event handler onclick
_onClick : function(evt)
{
// Show the id of current HTML Element
alert(this.get_id());
}
};
// Register class
MyNamespace.MyBehavior.registerClass("MyNamespace.MyBehavior", Sys.UI.Behavior);
当我们需要在页面中使用它时,我们可以写如下代码
// Create an instance of our Behavior
// and attach it to HTML element with id 'elementId'
// Parameters:
// 1) Class name with namespace
// 2) Properties in JSON format
// 3) Events in JSON format
// 4) References in JSON format
// 5) HMTL element
$create(MyNamespace.MyBehavior, {}, {}, {}, $get('elementId'));
如果我们想为一种元素类型实现行为,或者想实现一个复杂的控件 (由不同元素组成的视觉控件),我们需要继承 Sys.UI.Control
。
支持 AJAX 的服务器控件
通常,控件不是通过 JavaScript 中的 $create
手动创建的,而是由 ASP.NET 服务器控件 (控件的服务器端版本) 自动生成的。这样,我们就可以实现一个服务器控件并在 Visual Studio 中获得设计时支持。当我们想创建一个支持 AJAX 的服务器控件时,我们需要继承 ScriptControl
(而不是 WebControl
)。这个基类包含了所有有用的方法,可以使客户端控件 (JavaScript) 和服务器控件 (.NET) 之间建立关联。
在 ScriptControl
中,我们需要重写两个方法
GetScriptDescriptors
: 将 JavaScript 类名和属性传递给客户端控件。GetScriptReferences
: 传递我们客户端控件使用的脚本。(ScriptManager
会在页面加载期间自动加载这些脚本)。
protected override IEnumerable<System.Web.UI.ScriptDescriptor> GetScriptDescriptors()
{
if (!string.IsNullOrEmpty(this.Filename))
{
ScriptControlDescriptor descriptor = new
ScriptControlDescriptor("JigsawPuzzleGameControl.PuzzleGameAjax",
this.ClientID);
descriptor.AddProperty("nRows", this.NRows);
descriptor.AddProperty("nColumns", this.NColumns);
yield return descriptor;
}
}
protected override IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences()
{
if (!string.IsNullOrEmpty(this.Filename))
{
List<ScriptReference> scripts = new List<ScriptReference>();
ScriptReference scriptReference1 = new ScriptReference("PreviewScript.js",
"Microsoft.Web.Preview");
scripts.Add(scriptReference1);
ScriptReference scriptReference2 = new ScriptReference("PreviewDragDrop.js",
"Microsoft.Web.Preview");
scripts.Add(scriptReference2);
ScriptReference scriptReference3 = new ScriptReference();
scriptReference3.Path = this.Page.ClientScript.GetWebResourceUrl(this.GetType(),
"JigsawPuzzleGameControl.Resources.Helpers.js");
scripts.Add(scriptReference3);
ScriptReference scriptReference4 = new ScriptReference();
scriptReference4.Path = this.Page.ClientScript.GetWebResourceUrl(this.GetType(),
"JigsawPuzzleGameControl.Resources.PuzzleGameAjax.js");
scripts.Add(scriptReference4);
return scripts;
}
else
{
return new List<ScriptReference>();
}
}
拖放
为了在我们的控件中实现拖放功能,我们需要在两个客户端控件中实现两个接口
- 继承自
Sys.Preview.UI.IDropTarget
的客户端控件:此控件代表放置区域 - 继承自
Sys.Preview.UI.IDragSource
的客户端控件:此控件代表拖动元素
在 Sys.Preview.UI.IDropTarget
中,我们需要实现以下方法
get_dropTargetElement
: 返回放置区域的 HTML 元素canDrop
: 检查是否允许放置特定的拖动元素drop
: 执行放置操作onDragEnterTarget
: 通常与onDragLeaveTarget
一起使用来实现视觉效果onDragLeaveTarget
: 通常与onDragEnterTarget
一起使用来实现视觉效果
我们还需要在 Initialize
方法中为 MouseDown
事件添加一个事件处理程序,然后调用 Sys.Preview.UI.DragDropManager.startDragDrop
initialize : function()
{
JigsawPuzzleGameControl.DragPuzzleGameAjaxElement.callBaseMethod(this,
"initialize");
$addHandlers(this.get_element(),
{ "mousedown" : this._onMouseDown }, this);
},
_onMouseDown : function(evt)
{
window._event = evt;
evt.preventDefault();
Sys.Preview.UI.DragDropManager.startDragDrop(this,
this.get_element(), null);
},
在 Sys.Preview.UI.IDragSource
中,我们需要实现以下方法
get_dragDataType
: 返回拖动元素的类型 (在canDrop
中用于检查拖动项是否与放置区域兼容的字符串)getDragData
: 返回拖动项的数据并传递给放置区域 (drop 方法)get_dragMode
: 返回拖动操作是Move
还是Copy
onDragStart
: 在拖动操作开始时调用onDragEnd
: 在拖动操作结束时调用onDrag
: 在拖动操作完成时调用
我们还需要注册和注销客户端组件作为放置区域
initialize : function()
{
JigsawPuzzleGameControl.DropPuzzleGameAjaxElement.callBaseMethod(this, "initialize");
Sys.Preview.UI.DragDropManager.registerDropTarget(this);
},
dispose : function()
{
Sys.Preview.UI.DragDropManager.unregisterDropTarget(this);
JigsawPuzzleGameControl.DropPuzzleGameAjaxElement.callBaseMethod(this, "dispose");
},
游戏
项目分为两个项目
- 包含控件使用示例的网站
- 包含控件的库项目
在库项目中,有一个名为 PuzzleGameAjax
的类,它继承自 ScriptControl
(AJAX 中所有自定义控件的基类)。这个类是我控件的服务器端代码。
在客户端,我们有三个 JavaScript 类
PuzzleGameAjax
(包含实现游戏的代码)DropPuzzleGameAjaxElement
(包含实现放置区域的代码)DragPuzzleGameAjaxElement
(包含实现拖动区域的代码)
DropPuzzleGameAjaxElement
实现 Sys.Preview.UI.IDropTarget
接口,DragPuzzleGameAjaxElement
实现 Sys.Preview.UI.IDragSource
接口。这两个接口由 AJAX 框架使用,以通用的方式处理拖放。
关注点
AJAX ASP.NET 是一项非常好的技术,我目前正在使用它来实现非常复杂的行为以改善用户体验。拖放功能绝对是最用户友好的功能,它使软件非常直观易用。通常,在 Web 上,此功能需要大量的 JavaScript 代码,但有了 PreviewDragDrop
,一切都变得容易。
历史
- 2008 年 3 月 30 日 - 首次发布 (老实说很糟糕,但我想要做得更好!)。
- 2008 年 4 月 6 日 - 我使文章更加完整。
- 2008 年 4 月 8 日 - 修复了解决方案中的一个问题。
- 2008 年 4 月 9 日 - 现在可与 Visual Studio 2005/2008 (包括 Express Edition) 配合使用。
- 2008 年 4 月 22 日 - 添加了在线演示。