求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
使用decj简化Web前端开发
 
作者 黄文海,火龙果软件    发布于 2013-11-07
 

(一):声明式Javascript动态加载和浏览器事件绑定

引言

Web前端开发中,开发人员经常需要处理一些常规问题,如:

1.在页面中引用多个相互存在依赖关系的Javascript文件

2.在页面中引用CSS文件

3.浏览器事件绑定

4.表单的数据填充、数据打包提交、数据校验和格式化

5.页面初始化逻辑

采用传统的命令式编程范式来处理这些问题时,开发人员不得不反复地通过编写代码调用相关API来完成这些常规任务。事实上,开发人员的主要精力应该集中在业务逻辑实现上,而非在这些常规任务上过多消耗时间。声明式编程范式可以帮助开发人员以最小的工作量去快速搞定这些常规任务,从而能够将更多的精力放在业务逻辑的实现上。

decj是一款以声明式编程范式为基础的Javascript开源框架。本文将介绍如何使用decj框架以近乎零编码的高效率方式去搞定这些常规任务。本期将介绍decj的声明式Javascript文件动态按需加载和声明式跨浏览器事件绑定。

decj框架简介

decj的优势及主要特性

decj使得开发人员能够进行模块化的声明式编程,其目标在于简化Web应用开发中常规问题的处理,使得开发人员能够将更多的精力放在业务逻辑处理上。简单来说,decj的优势在于:

声明式编程:使得开发人员能够集中精力在写必须由其编写的代码,提升开发效率。

decj所解决的问题是几乎每个Web应用中都要面对的普遍的问题:如事件绑定、表单数据校验、格式化、表单提交等。

代码即文档(Code is document):采用decj开发的应用,其代码某种程度上就是文档。

decj的优势也就是声明式编程的优势。通过声明式编程,decj使得开发者面对日常工作中经常要处理的问题时能够集中精力在“真正”需要其处理的问题上。

比如,但某个页面上的一个按钮被单击时,一段业务处理逻辑需要被执行。显然,这段被调用的业务逻辑才是开发者真正要集中精力处理的问题,因为业务逻辑是怎么样的只有人才能知道,而任何框架/库是无法得知并为开发人员代劳的。相反,采用命令式编程的框架/库,在处理此类问题时,开发人员往往得首先分心去处理一些非业务逻辑的问题,比如,如何让这个按钮响应单击事件。比如,若使用jQuery来实现,开发人员需要在代码中的恰当位置/时机(如window的onload事件被触发后)调用jQuery的bind方法,才能使按钮被单击后执行一段业务逻辑。如清单1代码所示:

清单 1. 命令式编程:使用jQuery处理事件绑定

$('#aButton').bind('click',function(){
//在此处编写或者调用业务逻辑实现代码
});
});

而采用decj,开发人员无须关心事件处理API以及在何处、何时机调用这些API。可以更加关注业务逻辑。如清单2代码所示:

清单 2. 声明式编程:使用decj处理事件绑定

events:{
"click@aButton":function(){//按钮aButton被单击时执行该函数
//直接在此处编写或者调用业务逻辑实现代码
}
}

可以看出,清单2的代码中并没有关于事件API的调用,开发人员因此可以不必关注这些API以及何时在何地方调用它们。开发人员可以重点关注如何响应相关事件,以实现业务逻辑。另外,decj的应用代码可以充当文档。例如,如清单2的代码所示,对于页面上的某个元素的某个事件,是采用那个事件处理器响应的这个信息一目了然,这有助于问题定位,因为定位问题的人可以快速确认他需要的信息。

decj支持以下几个主要特性:

1.声明式Javascript文件按需动态加载

2.声明式跨浏览器的事件绑定

3.声明式CSS文件按需动态加载

4.声明式HTML表单增强:表单内容自动填充、表单数据自动提交、表单重置增强、表单数据校验、数据格式化

5.声明式页面/模块初始化

6.声明式国际化(I18N)支持:支持多语言和按需加载资源文件

HTML代码/CSS文件/Javascript文件/资源文件并行加载

下面我们详细介绍decj框架的两大基础---声明式编程和Javascript模块化编程。若读者已经熟悉这两基础可以跳过这两部分内容。然后,我们将从Web前端开发中的日常任务入手,探讨这些日常任务的常规实现方法的弊端以及如何利用decj的声明式编程去克服或绕过这些弊端。

声明式编程

多数通用编程语言(如Java语言)都采用命令式编程范式(Imperative)。这种方式下的编程,我们不仅要告诉机器它要做什么,还要告诉它如何去完成。而声明式(Declarative)编程是一种只需要告诉机器要完成什么,而无需说明如何去完成的一种编程范式。声明式编程往往能够减少开发人员的工作量,使代码更加简洁和富有表现力。

声明式编程的一个常见例子是数据库查询语言SQL(Structured Query Language)。如下一个SQL查询语句,它仅仅说明了要查询什么样的数据,而无需说明如何去查询这些数据:

清单 3. 声明式编程的例子---SQL语句

SELECT license FROM frameworks WHERE name=’decj’
; --查询名为decj的框架的许可证信息

Javascript语言所支持的JSON(JavaScript Object Notation)语法非常适合于作为Javascript声明式编程的语法基础。比如,假设某个Javascript UI(User Interface)库提供了一个名为createDialog的函数用于创建基于HTML的网页对话框。该函数接受一个参数,用于配置所要创建的对话框的一些属性和行为。那么,在调用createDialog函数就可以使用JSON语法来声明所要创建的对话框的属性。如清单4所示:

清单 4. JSON作为Javascript声明式编程的基础

createDialog({//创建一个标题为“成功”,宽100像素,高200像素的模态对话框
  width:"100px",
  height:"200px",
  modal:true,
  title:"成功"
});

Javascript模块化编程

声明式编程是decj框架的核心,而模块化编程是其基础。decj框架并不“再造车轮(Re-invent the wheel)”,它默认采用遵循AMD(Asynchronous Module Definition)规范的Javascript库RequireJS来实现模块化编程。

AMD规范定义了一个名为define的函数,通过该函数开发人员可以定义一个Javascript模块。在AMD规范中,一个Javascript模块可以是任何的Javascript对象,如函数、数组和普通Javascript对象。define函数的签名如下:

define(id?,dependencies?,factory);

该函数的各个参数含义如下:

id:可选字符串,表示所要定义的模块的唯一标识(ID)。

dependencies:可选数组,表示当前模块所依赖的其它各个模块的唯一标识。

factory:模块工厂。通常是一个匿名函数,负责返回所要定义的Javascript模块。该函数接受若干个参数,每个参数都与dependencies参数中指定的ID对应的Javascript模块对象一一对应。

如下代码定义了一个Javascript模块,该模块是一个普通的Javascript对象,如清单5所示:

清单 5. 基于AMD规范的Javascript模块化编程

define(['jquery'],function(jquery){
//该模块工厂依赖于jQuery库,故声明ID为jquery的模块为其依赖模块
//返回一个模块对象。该对象包含一个名为fieldValue的方法
return {
fieldValue:function(fieldName){
//返回当前页面中名为fieldName的表单控件的值
return jquery("[name='+fieldName+']").val();
}
//...
};
});

AMD规范定义了另一名为require的函数用于加载指定的Javascript模块。不过,由于decj框架的声明式编程的特性,应用开发者一般无需使用该函数了。因此,本文不详细介绍该函数了。

开始使用decj

首先,从github下载decj框架,并将其部署到你的Web服务器上。

然后,编写Web应用的主页。并在主页中添加一个script标签,使该标签的src属性和data-main属性分别引用RequireJS和decj框架的Javascript文件。如清单6所示:

清单 6. 开始使用decj框架

<html>
<head>
<title>decj startup</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
function decjApp(){
return {
initialModule:'../module/initModule' //定义初始模块的ID
};
}
</script>
<script data-main="../js/lib/decj.js" src="../js/lib/requirejs.js"></script>
</head>
<body>
开始使用decj!
</body>
</html>

模块化编程是decj的基础。一个Web应用可以包含多个模块,因此基于decj的Web应用需要一段应用启动代码。这段代码会定义Web应用的初始模块(即第一个会被加载的模块)的ID。

应用启动代码是一个名为decjApp的函数,该函数返回一个普通的Javascript对象。该对象的initialModule属性用于指定当前应用第一个要加载的模块(初始模块),如清单6所示。decjApp函数返回值的其它属性还可以用来定义decj的其它属性和行为。

最后,编写decjApp函数指定的初始模块对应的代码,这样一个基本的decj Web应用就可以使用了。清单7显示了一个示例模块代码。

清单 7. 一个decj示例模块

define(['jquery','decj'],function(jQuery,decj){
alert('decj comes into play!');
return {//返回模块对象

};
});

声明式Javascript文件动态按需加载

前文讲到,模块化编程是decj的基础。采用基于AMD规范的Javascript模块化编程的好处不仅仅是降低各个模块的耦合度,一定程度上也可以提高应用的性能。因为各个Javascript模块及其所依赖的其它模块只有当其代码确实要被调用的时候才会由模块加载器去动态加载。

decj默认采用RequireJS作为其模块加载器,因此基于decj框架开发的应用中的各个Javascript文件在运行的时候是被动态按需加载的,而不是页面一加载时就把所有可能用的Javascript都一起加载。事实上,开发人员也可以选择使用其它符合AMD规范的模块加载器。

声明式跨浏览器事件绑定

客户端编程中,事件绑定是一个几乎每天都要处理的一个问题。比如,要使页面上一个ID为chkShowLog的checkbox响应单击事件。当该checkbox被单击时,ID为log的元素会在被显示和隐藏之间来回切换。采用传统的编程范式来实现这样简单的一个功能,即便在采用jQuery这样能够使我们编写简练代码的Javascript库的情况下,开发人员也不得不编写代码来调用浏览器事件处理的相关API,如清单8所示:

清单 8. 使用jQuery实现事件绑定

$(document).ready(function(){//在页面加载完毕后执行调用该函数
$('#chkShowLog').bind('click',function(ele){//ID为chkShowLog的被单击后执行该函数
$('#log').toggle();//显示或隐藏ID为log的元素
});
});

如果不采用任何Javascript库或框架,直接使用Javascript来实现清单8代码的功能,并且还要兼容不同浏览器的话,那么需要编写的代码就更加多和繁琐了。

decj支持声明式的事件绑定。应用代码只需要在模块定义中声明哪个元素(事件目标元素)的哪个事件使用哪个监听器来处理,而无需调用任何与事件绑定有关的浏览器或者框架的API。例如,清单8中的代码使用decj可以改写为清单9所示的代码:

清单 9. 使用decj的声明式事件绑定

define(["decj"],function(decj){
return {
//…
events:{
"click@#chkShowLog":function(){
//使该函数响应ID为chkShowLog的元素的onclick事件
$("#log").toggle();
}
}
//…
};
});

上面的的代码乍一看似乎比清单8中的代码要长。但事实上,清单9中的代码,除了下面清单10中的代码片段,其余的都是定义一个模块所必须的代码,而不属于事件绑定本身。并且,清单9中的代码没有任何API调用,开发人员只需要通过代码告诉框架本身无法知道的信息(即我们要采用哪个函数响应哪个元素的哪个事件)。

清单 10. 使用decj的声明式事件绑定

events:{
"click@#chkShowLog":function(){//使该函数响应ID为chkShowLog的元素的onclick事件
$("#log").toggle();
}
}

decj的声明式事件绑定是跨浏览器兼容的。开发人员只需在模块定义中声明events属性。该属性是一个普通的Javascript对象。在该对象中可以声明多个事件绑定。每个事件绑定遵从如下格式:

“事件名@目标元素对应的CSS选择器”:事件监听器函数

例如,要使名为switchLang的函数响应name属性为lang的元素的onchange事件,只需在模块定义的events属性中声明:

“change@[name=lang]”:switchLang

事件绑定声明中“@“后面的CSS选择器遵从jQuery所支持的各个CSS选择器

小结

本期介绍了decj的优势及主要特性,并详细介绍了decj的“声明式Javascript文件动态加载”和”声明式跨浏览器事件绑定“这两个特性如何解决Web前端开发中以下常规问题:

1.在页面中引用多个相互存在依赖关系的Javascript文件

2.浏览器事件绑定

(二):声明式表单增强和页面初始化

引言

表单(Form)是Web应用中数据展现和收集常用的HTML元素。开发人员经常需要处理表单的数据填充、数据校验和格式化以及数据打包。另外,页面在加载完毕后往往需要执行一段初始化逻辑。本期将介绍decj对HTML表单的声明式增强和声明式页面/模块初始化这2个特性。

声明式表单功能增强

decj以声明式编程的方式对表单数据展现和收集功能进行增强。在数据展现方面,decj支持根据指定的数据自动将数据填充到表单中、对表单字段值进行自动格式化。在数据收集方面,decj支持对表单字段值进行自动校验、对表单数据自动打包提交。同时,decj支持对表单的Reset按钮的功能进行增强。

模块业务对象元数据

decj的表单增强功能依赖于模块的业务对象元数据。从MVC(Model-View-Control)设计模式的角度来看,表单本身属于View,其所展现和收集的数据属于Model。decj称呼每个Model的实例为一个业务对象(Business Object,简称BO)。一个页面中可以有多个表单,这些表单对应各自的业务对象。模块的业务对象元数据则用于描述一个模块所涉及的各个业务对象的信息,包括业务对象的名称、别名和类型。业务对象类型则描述了该类型的业务对象包含哪些字段以及每个字段的名称、别名、字段类型、数据校验规则以及格式化要求。

模块的业务对象元数据是一个普通Javascript对象,可以使用JSON进行声明。其格式化如下:

{"boMetaData":{
"BO类型名称":{
//字段声明
}
},
"bo":{"BO名称":{"type":"BO类型名称","alias":"BO别名"}}
}

上述JSON对象中,属性“bo”的值声明了模块使用了哪些BO,并声明了各个BO的名称、别名以及BO类型名。BO的别名默认为BO名称本身,它对应于表单的name属性值。每个BO类型的声明包含了若干个字段声明。每个字段声明的格式如下:

"字段名称":{
"stereoType": "字段类型名称",
"alias":"字段别名",
"typeParam":{},//声明字段类型参数
"validation": {
"数据校验规则": {}//声明数据校验规则
}
}

字段声明描述了每个字段的类型名称(stereoType)、字段别名(alias)、字段类型参数(typeParam)及数据校验规则(validation)。其中字段别名默认为字段名本身,它对应表单控件的name属性值。

假设某IT社交网站要实现一个会员信息编辑的功能,会员信息包括会员的姓名、性别、技能专长领域等,如图1所示:

图1. 虚构的某IT社交网站的会员信息页面

针对这个例子,开发人员可能创建如清单11所示的业务对象元数据:

清单 11. 虚构的某IT社交网站的业务对象(会员信息)元数据

{"boMetaData":{
"decj.demo.MemberInfo":{//声明业务对象类型,其名称为decj.demo.MemberInfo
"firstName": {//声明业务对象类型中名为firstName的字段信息
"alias":"fn",//字段别名为fn
"typeParam":{"min":4,"max":15}
},
"lastName": {
"alias":"lastname",
"typeParam":{"min":4,"max":15}
},
"passwd": {
"stereoType": "String",
"typeParam":{"min":6,"max":10}
},
"gender": {
"validation": {
//声明该字段的数据校验规则包括NotNull,即该字段不允许为空
"NotNull": {}
}
},
"birthdate":{
"stereoType": "Date",//声明该字段是个日期型数据
"typeParam":{"format":"yyyy-MM-dd"},
//声明字段的类型参数,其中说明该字段格式为yyyy-MM-dd
"validation": {
"NotNull": {}
}
},
"prefLang":{
"alias":"preferred-lang",
"validation": {
"NotNull": {}
}
},
"expertise":{
"stereoType": "String[]",
"validation": {
"NotNull": {}
}
},
"email":{
"typeParam":{"min":15,"max":40}
},
"mobilephone":{
"typeParam":{"min":11,"max":11}
},
"notification":{
"stereoType": "String[]",
"typeParam":{"min":0,"max":10}
},
"intro":{
"typeParam":{"min":0,"max":450}
},
"mgmtExpr":{
"stereoType": "Decimal",
"typeParam":{"locale":"cn","fraction":2}
}
}
},
"bo":{"memberInfo":{"type":"decj.demo.MemberInfo"}}
//声明模块包含一个名为memberInfo的业务对象,其类型为decj.demo.MemberInfo
}

模块业务对象元数据可以在Javascript代码中直接声明,也可以采用服务端代码生成。若采用服务代码生成,需要在模块定义中声明一个名为metaDataURL的属性,其值提供业务对象元数据的URL。如清单12所示:

清单 12. 在模块定义中声明业务对象元数据提供者的URL

metaDataURL:'handler.jsp?src=metaData.json'

MVC是被普通采用的设计模式。许多Web应用的服务端代码也是采用了MVC,因此我们可以利用服务端代码自动根据服务端代码中的业务对象生成模块的业务对象元数据。这样既可以减少代码编写量,又可以使客户端和服务端在Model层保持同步。比如,在Java平台中,开发人员可以使用Java的反射(Reflection)API及JSON API自动生成相关BO的元数据。

表单内容自动填充

Web应用经常需要将服务端的数据填充到表单中,以便对数据进行查看、编辑。该功能多数是通过服务端代码(如JSP)或者调用客户端封装好的代码来实现。decj框架则支持根据指定的业务对象元数据自动对表单进行内容填充,而无需开发人员编写代码调用任何API。

下面以上一节中提到的虚构的某IT社交网站的会员信息编辑功能为例,讲解decj的表单内容自动填充功能。在给定会员信息相应数据的情况下,要实现该表单的自动填充,开发人员只需要为decj提供好相关的业务对象元数据(如清单11所示),并编写好表单的HTML代码即可,如清单13所示。

清单 13. 表单的HTML代码

<form action="handler.jsp?src=test.jsp" name="memberInfo" title="form.title">
<label>
<label class="res-replace">firstname</label>
<input name="fn" type="text" value="firstname" title="firstname"/>
</label><br />
<label>
<label class="res-replace">lastname</label>
<input name="lastname" type="text" value="lastname" title="lastname"/>
</label><br />
<!-- ... -->
<label>
<label class="res-replace">expertise-area</label><br />
<select multiple="true" name="expertise">
<option value="java">Java</option>
<option value="cpp">C++</option>
<option value="Javascript">Javascript</option>
<option value="design-pattern">Design Pattern</option>
<option value="oracedb">Oracle Database</option>
<option value="css">CSS</option>
<option value="html">html</option>
</select>
</label><br />
<!-- ... -->
<input name="reset" type="reset" value="Reset" />
<input name="btnSubmit" type="submit" value="update"/>
</form>

编写表单的HTML代码的时候,要注意表单元素的name属性值以及表单中各个控件的name属性值与表单所在模块的业务对象元数据中声明的业务对象别名、字段别名要分别相同。decj正是根据这种对应关系将业务数据显示到相应表单的对应控件上。

填充表单所需的业务对象数据,可以由服务端代码生成或者直接在Javascript代码中指定。清单14的代码展示了在decj应用启动代码中声明初始模块所要加载的服务端数据。

清单 14. 声明初始模块所要加载的服务端数据

function decjApp(){
return {
//...
initialModule:['module/UpdateRegInfoStatic',{
httpRequest:{
url:'dataProvider.jsp?src=userInfoData.json'
}
}
]
//...
};
}

清单15展示了清单14中所示的URL提供的服务端数据。

清单 15. 虚构的某IT社交网站的某会员信息

{
"memberInfo":{
"lastName":"Framework",
"firstName":"decj",
"gender":"Male",
"email":"decj@viscenthuang.info",
"birthdate":318268800000,
"prefLang":"English",
"expertise":["html","oracedb","Javascript","java"],
"notification":["SMS","email"],
"mobilephone":"13612345678",
"intro":"decj is a lightweight javascript framework. By taking advantages of JSON
and AMD,it enables solving common issues elegantly in the client-side web development
in a declarative and modular way.Declarative programming means
we can achieve the same thing or even more with less code compared with imperative
programming.All features supported by the framework do NOT require you write
imperative code,you just declare what you need to do.",
"mgmtExpr":1032.56
}
}

表单自动填充的效果如图2所示:

图2. decj自动表单填充示例效果

表单数据校验、数据格式化

decj框架可以根据业务对象元数据对自动填充的表单中的字段进行自动数据校验、格式化。开发人员无需编写任何代码(除非要进行扩展和定制)。

decj的表单数据校验分两种。一种基于业务对象元数据中声明的数据类型(stereoType属性),另一种基于业务对象元数据中声明的数据校验规则(validation属性)。前者可以根据字段的数据类型对其值进行校验。比如Number型的字段,当输入值包含非数字字符时,decj就会提示数据校验不通过。后者可以根据指定的规则名对应的校验规则对字段的输入值进行校验。比如,String型字段默认包含了一个名为“Size”的校验规则,该规则会指示decj对相应字段的值的长度进行校验。若字段值长度不符合要求,则decj会提示数据校验不通过。

例如,上述例子中字段“Management expierence“的元数据声明如下:

"mgmtExpr":{
"stereoType": "Decimal",
"typeParam":{"locale":"cn","fraction":2}
}

说明名为“mgmtExpr”的字段其类型为数字型,其类型参数中声明了其数据格式化采用的Locale为“cn”(中国),小数点为2位。那么,当该字段的输入值包含无效的非数字字符时,decj就会提示数据校验未通过。如图3所示:

图3. decj基于字段类型的数据校验——校验失败

若“Management expierence“的字段值为”1032.56”,则decj的数据校验会通过,并且该字段值会被自动按照中国的数字格式化规则进行格式化,如图4所示:

图4. decj自动数据格式化

上述例子中字段“Last name“的元数据声明如下:

"lastName": {
"alias":"lastname",
"typeParam":{"min":4,"max":15}
}

这说明,名为“lastName”的字段的类型是默认类型(即String型)。由于String型的字段蕴含着一个名为“Size”的数据校验规则,且该字段的类型参数中设定min属性为4、max属性为15,则decj会根据上述声明自动对该字段值的长度进行校验,若字段值的长度不在4~15个字符之间,则数据校验未能通过。如图5所示:

图5. decj基于规则名的数据校验——校验失败

开发人员也可对decj进行扩展和定制,建立自己的数据类型和数据校验规则、数据格式化。限于篇幅,本文不详述。

表单数据自动提交

越来越多Web应用开始支持JSON格式的数据,将表单的数据以JSON格式打包提交给服务端程序进行处理已经不稀奇。采用传统的编程方式,这需要编写代码来调用相关API实现。而采用decj,开发人员只需要提供模块的业务对象元数据即可实现自动将表单的数据以JSON格式提交到服务端。

decj默认会以JSON格式对表单数据进行打包。和传统的开发方式相同的是,要提交表单,开发人员需要设置表单的action属性(指定服务端接收程序的URL)以及在表单中添加submit按钮。

所不同的是,传统方式下表单提交数据时只能采用HTTP的POST或GET方法。而decj则支持以任何HTTP方法提交数据,包括PUT、POST、GET等。这使得decj开发的客户端代码可以访问REST(Representational State Transfer) Web服务。

decj默认采用POST方法提交表单数据。若要以其它HTTP方法提交表单数据,可以在模块定义中声明decj表单描述符(Form Descriptor)的method属性。表单描述符是decj模块的一个名为forms的属性。forms属性的值是一个普通Javascript对象,该对象的各个属性的名字与模块页面中的各个表单的name属性一一对应。

例如,要更改一个名为memberInfo的表单的提交方法为PUT,只需要在表单描述符中设置method属性为PUT即可,代码如清单16所示。

清单 16.更改表单的提交方法

//指定名为memberInfo的表单的提交方法为PUT
forms:{//表单描述符
"memberInfo":{//表单名称
//...
method:'PUT'//声明表单的提交方法为PUT
//...
}
}

表单提交时decj发送给服务端代码的HTTP请求如图6所示:

图6. decj以JSON格式提交表单效果示意(使用Chrome浏览器的Developer Tools查看)

decj也支持以传统的URI-Encode格式(即以name/value对的方式编码表单各个字段)提交表单数据。若要以URI-Encode格式提交表单数据,开发人员需要将表单的描述符的encodingType属性值设置为“application/x-www-form-urlencoded”,或者给表单元素添加一个名为“_enctype”的自定义属性,设置其值为“application/x-www-form-urlencoded”。此时,表单提交时decj发送给服务端代码的HTTP请求如图7所示:

图7. decj以URI-Encode格式提交表单效果示意(使用Chrome浏览器的Developer Tools查看)

声明式页面/模块初始化

许多页面、模块往往需要在页面、模块刚被加载完毕后执行一些初始化的代码。采用传统的编程方式,这需要我们侦听window对象的onload事件,然后在相应的事件监听器中编写初始化代码。采用这种方式,即便使用jQuery库,应用也需要调用jQuery的相关API,如清单17代码所示:

清单 17. 使用jQuery编写页面初始化代码

$(document).ready(function(){//页面加载完毕后执行该函数
alert('通知:\n\r 。。。');
});

而采用decj框架,应用代码则无需调用任何与事件绑定有关的API,而是直接声明所需要的初始化操作即可。代码如清单18所示:

清单 18. 使用decj的声明式页面、模块初始化

define(['jquery','decj'],function(jQuery,decj){
//…
return {
//…
init:function(){//直接在该函数中编写模块初始化代码
alert('通知:\n\r 。。。');
}
//…
};
});

可见,采用decj框架,应用代码只需在模块定义中声明init属性即可,而无需调用任何API。init属性的值是一个函数,该函数会在当前模块被加载完毕后被执行。因此,页面、模块的初始化代码可以写在该函数内。

另外,decj中初始化代码被执行的时机与传统编程范式有些区别。传统的编程范式是通过侦听window对象的onload事件来执行初始化代码。而window的onload事件是在当前加载的页面及其引用的所有资源(包括CSS文件、Javascript文件和图片文件等)都被加载完毕才会被触发。而decj框架会在其加载完当前模块所需的Javascript文件、HTML文件(并将其内容附加到当前HTML DOM树上)以及国际化资源文件就执行初始化代码。并且,decj是以并行的方式加载模块所需的Javascript文件、HTML文件以及国际化资源文件的。因此,采用decj框架时,模块、页面的初始化代码可以更加早地被执行,从而提高了页面就绪的速度。

小结

本期介绍了decj的“声明式表单功能增强”及“声明式模块初始化”这几个特性如何解决Web前端开发中如下常规问题:

1.表单的数据填充、数据打包提交、数据校验和格式化

2.页面初始化逻辑。

 
相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
 
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
 
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程
 
分享到
 
 


使用decj简化Web前端开发
Web开发框架形成之旅
更有效率的使用Visual Studio
MVP+WCF+三层结构搭建框架
ASP.NET运行机制浅析【图解】
编写更好的C#代码
10个Visual Studio开发调试技巧
更多...   


.NET框架与分布式应用架构设计
.NET & WPF & WCF应用开发
UML&.Net架构设计
COM组件开发
.Net应用开发
InstallShield


日照港 .NET Framework & WCF应用开发
神华信息 .NET单元测试
北京 .Net应用软件系统架构
台达电子 .NET程序设计与开发
赛门铁克 C#与.NET架构设计
广东核电 .Net应用系统架构
更多...