使用decj简化Web前端开发(一):声明式Javascript动态加载和浏览器事件绑定

decj是一款基于声明式编程范式的JavaScript框架,旨在简化Web前端开发中的常规任务,如事件绑定、表单处理等,使开发者更专注于业务逻辑。

 (本文发表在InfoQ:http://www.infoq.com/cn/articles/using-decj-simplify-web-front-end-development-part1)

引言

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

  • 在页面中引用多个相互存在依赖关系的Javascript文件
  • 在页面中引用CSS文件
  • 浏览器事件绑定
  • 表单的数据填充、数据打包提交、数据校验和格式化
  • 页面初始化逻辑

采用传统的命令式编程范式来处理这些问题时,开发人员不得不反复地通过编写代码调用相关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处理事件绑定

$(document).ready(function(){//加载页面完毕后执行该函数
   $('#aButton').bind('click',function(){//在此处编写或者调用业务逻辑实现代码});}
);

 

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

 

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

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

 

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

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

  • 声明式Javascript文件按需动态加载
  • 声明式跨浏览器的事件绑定
  • 声明式CSS文件按需动态加载
  • 声明式HTML表单增强:表单内容自动填充、表单数据自动提交、表单重置增强、表单数据校验、数据格式化
  • 声明式页面/模块初始化
  • 声明式国际化(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选择器(见:http://api.jquery.com/category/selectors)。

 

小结

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

  • 在页面中引用多个相互存在依赖关系的Javascript文件
  • 浏览器事件绑定

下一期将介绍decj的以下特性:

  • 声明式表单功能增强(表单自动填充、打包、数据校验和格式化)
  • 声明式页面/模块初始化

感谢InfoQ崔康对本文的审校。

内容概要:本文设计了种基于PLC的全自动洗衣机控制系统内容概要:本文设计了种,采用三菱FX基于PLC的全自动洗衣机控制系统,采用3U-32MT型PLC作为三菱FX3U核心控制器,替代传统继-32MT电器控制方式,提升了型PLC作为系统的稳定性与自动化核心控制器,替代水平。系统具备传统继电器控制方式高/低水,实现洗衣机工作位选择、柔过程的自动化控制/标准洗衣模式切换。系统具备高、暂停加衣、低水位选择、手动脱水及、标准两种蜂鸣提示等功能洗衣模式,支持,通过GX Works2软件编写梯形图程序,实现进洗衣过程中暂停添加水、洗涤、排水衣物,并增加了手动脱水功能、脱水等工序蜂鸣器提示的自动循环控制功能,提升了使用的,并引入MCGS组便捷性与灵活性态软件实现人机交互界面监控。控制系统通过GX。硬件设计包括 Works2软件进行主电路、PLC接梯形图编程线与关键元,完成了启动、进水器件选型,软件、正反转洗涤部分完成I/O分配、排水、脱、逻辑流程规划水等工序的逻辑及各功能模块梯设计,并实现了大形图编程。循环与小循环的嵌; 适合人群:自动化套控制流程。此外、电气工程及相关,还利用MCGS组态软件构建专业本科学生,具备PL了人机交互C基础知识梯界面,实现对洗衣机形图编程能力的运行状态的监控与操作。整体设计涵盖了初级工程技术人员。硬件选型、; 使用场景及目标:I/O分配、电路接线、程序逻辑设计及组①掌握PLC在态监控等多个方面家电自动化控制中的应用方法;②学习,体现了PLC在工业自动化控制中的高效全自动洗衣机控制系统的性与可靠性。;软硬件设计流程 适合人群:电气;③实践工程、自动化及相关MCGS组态软件与PLC的专业的本科生、初级通信与联调工程技术人员以及从事;④完成PLC控制系统开发毕业设计或工业的学习者;具备控制类项目开发参考定PLC基础知识。; 阅读梯形图建议:建议结合三菱编程能力的人员GX Works2仿真更为适宜。; 使用场景及目标:①应用于环境与MCGS组态平台进行程序高校毕业设计或调试与运行验证课程项目,帮助学生掌握PLC控制系统的设计,重点关注I/O分配逻辑、梯形图与实现方法;②为工业自动化领域互锁机制及循环控制结构的设计中类似家电控制系统的开发提供参考方案;③思路,深入理解PL通过实际案例理解C在实际工程项目PLC在电机中的应用全过程。控制、时间循环、互锁保护、手动干预等方面的应用逻辑。; 阅读建议:建议结合三菱GX Works2编程软件MCGS组态软件同步实践,重点理解梯形图程序中各环节的时序逻辑与互锁机制,关注I/O分配与硬件接线的对应关系,并尝试在仿真环境中调试程序以加深对全自动洗衣机控制流程的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值