65.9K
CodeProject 正在变化。 阅读更多。
Home

编写面向对象的 JavaScript 第三部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.64/5 (18投票s)

2003年12月9日

11分钟阅读

viewsIcon

100960

downloadIcon

1098

使用 Cfx 开发 JavaScript 控件类库。

摘要

本系列的第一部分描述了 JavaScript 的面向对象特性。第二部分在此基础上进一步介绍了支持类继承的框架。在本最终章中,我们将使用 Cfx 来构建一个 JavaScript 控件类层次结构,为 ASP.NET 用户控件提供丰富的客户端行为。

引言

Web 控件代表网页的一部分,通常提供用户交互功能,如文本框、单选按钮、复选框等。Web 控件也可以是静态的。将页面细分为控件可以使页面成为 Web 控件的容器,从而提高抽象性,并增强重用性和可扩展性。

使用 ASP.NET,您可以利用传统的 HTML 元素或 ASP.NET 控件。您可以通过定义自己的用户控件来增强它们。最终,ASP.NET 会将所有控件渲染为客户端浏览器解释的 HTML 和 JavaScript。当然,您可以自己编写网站并使用默认的 ASP.NET 行为。然而,这在所有情况下都不可行,并且会限制用户体验。使用 Cfx,您现在可以通过编写面向对象的 JavaScript 来实现对客户端脚本的更大控制和丰富性。

注意 - ASP.NET 和 Web 控件的详细解释超出了本文的范围,因为有许多关于 ASP.NET 的优秀书籍和文章。本文的目的是展示 Cfx 如何用于构建利用 ASP.NET 来创建丰富客户端的类。

策略

利用 ASP.NET 控件命名

ASP.NET 在将控件渲染为 HTML 元素时,使用 idname 属性应用了一致的命名方案。ASP.NET 使用控件名称前加上其容器名称,并通过下划线分隔来命名 HTML 元素。例如,在附带的演示中,ASP.NET CfxText 用户控件封装了 ASP.NET 文本框控件,并为其提供了标识符 txtField

<asp:TextBox id="txtField" runat="server" maxlength="255"></asp:TextBox>

ASP.NET CfxText 用户控件的 id 是 txtName,随后被 id 为 CfxWebFormOption1CfxWebFormOptions 控件封装。ASP.NET 为 HTML 文本元素生成的 id 使用最外层容器的标识符,后跟分隔符,然后是下一个容器的名称,最后是控件标识符。

<input id="CfxWebFormOptions1_txtName_element" type="text" 
    maxlength="255" class="LgNorm" style="width:224px;" />

通过利用这种命名约定,我们可以逻辑地分组控件元素,并开发一个 JavaScript 中的 ASP.NET 控件包装器类层次结构,为 ASP.NET 用户控件提供客户端行为支持。

注意 - ASP.NET 2.0 使用美元符号 ($) 作为分隔符。美元符号消除了下划线分隔符可能在标识符中使用的歧义。Cfx.Dom.GetElementTerms 使用正则表达式来处理分割 ASP.NET 标识符为元素术语时的下划线歧义。

JavaScript 控件类层次结构

CfxControl 概念上代表页面上使用的用户控件类的集合。这些类代表布局描述及其客户端行为定义。布局描述使用 ASP.NET 定义,并保存在附带的 .aspx.cs 文件中。客户端行为用 JavaScript 编写在相应的 .js 文件中。因此,客户端行为与其布局是分离的。请注意,我们几乎实现了渲染文件和 JavaScript 文件之间的一对一对应关系。附加的 JavaScript 文件包含在 CfxControlCfxInput 类中定义的通用基类定义和实现。

在 JavaScript 控件类层次结构的顶层是 Object 类,紧接着是 CfxControl 类,它是所有 JavaScript 控件的根。CfxWebFormOptions 控件是 WebForm1 页面上输入控件的容器类。有三个输入控件从 CfxInput 类派生出特定的功能。CfxText 类代表文本输入控件。CfxSelect 类代表单选下拉列表,CfxLabel 包装了 ASP.NET Label 控件。CfxRadioSet 代表一组单选按钮元素。CfxHistoryOptions 类包含 CfxRadioSetCfxSelect 类,提供了一个用于进行“历史”选择的控件。

提供了一对不属于 CfxControl 继承体系的辅助类。CfxError 类扩展了 Error 类,增加了抛出异常的框架对象属性,以及用于 JavaScript event 对象的 CfxEvent 包装器。

图 1. CfxControl 类层次结构。

JavaScript 客户端控件

CfxControl

CfxControl 类是所有派生控件的基类,封装了所有控件继承的属性。name 属性是控件的名称。将控件视为文档元素容器,name 属性代表容器的名称。parent 属性是父 CfxControlitems 属性是一个文档元素数组,这些元素的 id 属性包含控件名称。

图 2. ASP.NET 控件标识符和术语。
例如,当创建名为 CfxWebFormOptions1CfxWebFormOptions 控件时,文档中所有 id 属性包含字符串 CfxWebFormOptions1 的元素和图像都会被添加到 CfxControlitems 数组中。

CfxInput

CfxInput 类是输入控件的基类。此类将输入控件定义为具有一个输入元素属性 element 和一个指示输入控件错误状态的图像属性 image。它定义了几个基本方法来操作 image 属性,以及 InitializeValidate 方法。CfxInput 没有被定义为抽象类,并且可以被实例化。这对于需要通用输入控件对象的情况很有用。

CfxText

CfxText 控件包装文本输入元素,并根据 regExp 正则表达式属性验证其输入。该控件还提供了监听 onkeypress 事件的能力,检测回车键以启动验证。用户可以通过 CfxText 控件的 SubmitHandler 方法提供一个事件处理程序,以应对回车键按下。

this.txtName.SubmitHandler( OnEnterKey );
图 3. 将 txtName 控件的 SubmitHandler 设置为 OnEnterKey 处理程序。

如果提供了提交处理程序,在文本输入元素的 onkeypress 事件期间,执行将转移到 CfxText 控件的 OnEnterKey 方法。CfxEvent 类包装了 JavaScript 事件对象,并检测回车键事件。如果按下了回车键事件,OnEnterKey 方法会调用 CfxText 提交处理程序。

function OnEnterKey( evnt )
{
    var cfxEvent = new CfxEvent( evnt );
    if ( cfxEvent.IsEnterKey() )
    {
        // Find the instance from the event source.

        var thisObj = cfxEvent.FindInstance( CfxText );
        
        // Call CfxText control submit handler.

        return thisObj.submit;
    }
    else
        return true;
}
图 4. CfxText OnEnterKey 事件处理程序。

onkeypress 事件触发的 OnEnterKey 方法中的 this 引用不指向 CfxText 实例,而是指向事件源元素。FindInstance 用于获取与源元素关联的 CfxText 实例。为了使 FindInstance 能够确定实例,CfxText.instance 标志在类定义中被设置为 true

CfxSelect

CfxSelect 控件包装了一个单选下拉列表输入元素,提供了向下拉列表中添加和删除元素的方法。CfxSelect 还提供了访问器方法来获取选定的文本和值,以及选定元素的索引。

CfxLabel

CfxLabel 包装了 ASP.NET Label 控件,提供了一种交互式的方式来更改页面文本。ASP.NET 将其标签渲染为 span 元素,CfxLabel 通过其 id 属性定位它,该 id 属性是通过连接其祖先控件的名称构建的。Value 访问器更新 span 元素的内部文本。CfxLabel 可用于增强错误通知的显示,而不是使用 alert。

CfxRadioSet

CfxRadioSet 控件包装了一组单选输入元素。ClickHandler 方法设置单选按钮元素的 onclick 事件处理程序。GetElement 返回 CfxRadioSet 的单选按钮元素,通过单选按钮索引。GetIndex 返回 CfxRadioSet 单选按钮元素的索引。CfxRadioSet 重写了从 CfxControl 继承的 GetItems 方法,因为单选按钮元素是通过 name 属性分组的,而基类方法使用 id 属性来查找元素。GetSelected 方法返回选中的单选按钮元素,Length 返回 CfxRadioSet 中的单选按钮元素数量。

CfxHistoryOptions

此控件提供了模拟选择历史标准的元素集客户端功能。此控件为 CfxRadioSet 控件以及与单选按钮相关的控件提供功能。

图 5. CfxHistoryOptions 用户界面。

CfxHistoryOptions 将控件分组到一个 CfxRadioSet 控件中,该控件包含单选按钮元素列表以及单选按钮的关联。例如,radioSet 属性包含单选按钮元素:radDefaultradByMonthradByYearradByMonth 单选输入元素的关联是名为 radByMonth_selByMonthCfxSelect 控件,而 radByYear 单选输入元素的关联是 radByYear_selByYear 控件。radDefault 单选元素没有关联。单选元素的 value 属性标识了关联,因此 CfxHistoryOptions 类可以分组包含该值的元素。在这种情况下,radByMonth 单选输入关联由 radByMonth 单选按钮和 radByMonth_selByMonth 下拉列表组成。

图 6. 分组单选元素关联控件。

在初始化过程中,CfxHistoryOptions 为单选按钮集建立了一个 onclick 事件处理程序。当单击单选按钮元素时,会调用 OnRadioClick 处理程序,该处理程序会更改单选按钮关联的禁用状态。请注意,处理程序使用 CfxEvent 类的 FindInstance 方法从事件源元素获取 CfxHistoryOptions 类的实例。最后,Validate 方法会验证选择。

Cfx 包装器类

CfxError

此包装器类增强了 JavaScript Error 对象,增加了一个属性,该属性引用抛出异常的 Cfx 类的实例。正如您将在演示中看到的,抛出的 CfxError 对象用于识别并更改正在抛出异常的 CfxText 对象的状态。

CfxEvent

CfxEvent 类是 JavaScript event 对象的包装器。event 对象包含有关 JavaScript 事件的信息,并传递给 CfxControl 事件处理程序。CfxEvent 隐藏了 event 对象的浏览器差异,提供了一致的接口。在演示中,CfxControl 事件处理程序负责检测回车键事件、单选按钮选中事件和提交按钮单击事件。处理程序创建一个 CfxEvent 对象来包装 event 对象,并调用 FindInstance 将触发事件的元素转换为其对应的 CfxControl 实例。

前端代码

控件的最终实现发生在 WebForm1 页面的 JavaScript 中。当 WebForm1 加载时,onload 事件调用页面的 OnLoad 函数,实例化一个新的 CfxWebFormOptions 控件并将其赋值给 formOptionsSubmitHandler 方法分配 OnSubmit 事件处理程序,该处理程序在控件提交按钮单击事件发生或从文本控件按下回车键时调用。OnSubmit 然后调用 Validate 方法,并在验证成功时执行回发。

<script type="text/javascript">
function OnLoad()
{
    formOptions = new CfxWebFormOptions( "CfxWebFormOptions1" );
    formOptions.SubmitHandler( OnSubmit );
}

function OnSubmit()
{
    if ( formOptions.Validate() == true )
        Cfx.Dom.PostBack();
    else
        return false;
}   
<script>
<body topmargin="0" leftmargin="0" marginheight="0" marginwidth="0" 
    onload="OnLoad();">
图 7. WebForm1 页面前端代码现已简化为例程。

基准测试

Cfx 的性能出奇地好。演示程序包含显示页面加载和提交性能的警报。对于 2GHz 的系统,IE 6.0 的每次任务时间不到 35 毫秒,Mozilla 1.4 的时间不到 50 毫秒。

演示

ControlDemo 演示程序展示了如何使用 Cfx 设计和实现控件类层次结构。此应用程序的方法是让 ASP.NET 负责页面布局,JavaScript 负责客户端用户交互。

此应用程序的 URL 为 https:///JsOOP/ControlDemo/WebForm1.aspx。将源代码复制到您 https:// 主目录的 JsOOP/ControlDemo 子目录中。您可以使用 Visual Studio 创建 ASP.NET 项目,或者使用“控制面板”中的“管理工具”中的 IIS 管理工具。此演示已在运行时版本 1.0 和 1.1 上进行了测试。

结论

本系列关于 JavaScript 面向对象编程的文章旨在填补客户端脚本开发领域的一个惊人空白。脚本常常被写成过程式附加项,而不是可重用对象。这很大程度上是因为 JavaScript 书籍未能充分解释该语言的面向对象功能,并且缺乏对类继承的内在支持。另一个促成因素是 ASP.NET 本身,其编程模型建议将 JavaScript 编写为 ASP.NET 控件的过程式附加项。

Cfx 提供了一个易于使用的编码模式,用于在 JavaScript 中编写类层次结构。编写面向对象脚本的结果是更丰富的客户端功能,通过让 JavaScript 承担更多的 UI 管理职责。虽然 ASP.NET 定义了页面布局,但代码隐藏变得微不足道,从而使服务器端代码能够更好地专注于业务逻辑。

另一方面,让 ASP.NET 控件发出 JavaScript 可能也很有用。使用 Cfx,您仍然可以以面向对象的方式构建脚本。Cfx 非常灵活,让您可以选择最适合您的部署方式。

Cfx 的另一个优点是它让您作为 Web 开发人员能够保留对代码更大的控制权。ASP.NET 功能强大,但过度依赖任何单一供应商的工具,在针对多个平台和浏览器时可能会带来麻烦。Cfx 由于其面向对象,因此可以轻松地将特殊性隔离在 fachada 和包装器中。虽然演示是为 ASP.NET 编写的,但 Cfx 是一个 JavaScript 框架,不特定于 ASP.NET。

我希望 JavaScript 类框架能够提高客户端脚本的质量,推广丰富的 Web 界面,减少供应商依赖,并促进可重用 JavaScript 类的集合的构建。

修订历史

  • 版本 1.0 -- 初始版本
  • 版本 1.1 -- 修复了内容错误。
© . All rights reserved.