zl程序教程

您现在的位置是:首页 >  前端

当前栏目

前端轻量级MVC框架CanJS详解

框架前端MVC 详解 轻量级
2023-06-13 09:15:46 时间

选择正确的库

创建一个JSAPP没有好的工具是很有难度的,jQuery只是操作DOM的库,没有提供任何创建APP的基础,这就是为什么我们要一个类似CanJS的专门的库。

CanJS是一个轻量级的MVC库,提供你创建一个JSAPP所需的工具。

CanJS是一个轻量级的MVC库,提供你创建一个JSAPP所需的工具。它提供有MVC(Model-View-Control)模式的基本框架,模板动态绑定,route的支持且内存安全。同时支持jQuery,Zepto,Mootools,YUI,Dojo,有丰富的扩展和插件。

第一部分你将学到:
创建Control控制层和View视图层(UI模板)来显示联系人
用Model模型层来表示数据
使用fixtures插件模拟ajax返回数据
你肯定激动了!我们开始码代码吧。
建立好你的文件夹和HTML
你先给你的APP创建一个文件夹,目录下再建立4个子文件夹:css,js,views和img。如下:
contacts_manager
css
js
views
img

保存以下的代码为index.html:

复制代码代码如下:


<!doctypehtml>
<htmllang="en">
 <head>
   <metacharset="utf-8">
   <title>CanJSContactsManager</title>
   <linkrel="stylesheet"href="css/bootstrap.min.css">
   <linkrel="stylesheet"href="css/contacts.css">
 </head>
 <body>
   <divclass="container">
     <divclass="row">
       <divclass="span12">
         <h1>ContactsManager</h1>
       </div>
     </div>
     <divclass="row">
       <divclass="span3">
         <divclass="well">
           <navid="filter"></nav>
         </div>
       </div>
       <divclass="span9">
         <divid="create"></div>
         <divid="contacts"></div>
       </div>
     </div>
   </div>
   <scriptsrc="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
   <scriptsrc="js/can.jquery.min.js"></script>
   <scriptsrc="js/can.fixture.js"></script>
   <scriptsrc="js/contacts.js"></script>
 </body>
</html>

在页面的底部你加载所需的JS(包括你的APP:contacts.js)。
教程中用到的CSS和图片文件可以下载。

用View来打造你的UI

View是用来渲染你APP的UI模板。CanJS支持多种模板引擎,本文用EJS,CanJS包含有而且支持动态绑定。
EJS模板的标签与HTML很像,支持包含JS代码,三种常用标签如下:
<%CODE%>执行JS
<%=CODE%>执行JS,并将非转义的结果写入当前位置的HTML
<%==CODE%> 执行JS,并将转义的结果写入当前位置的HTML(用于子模板).
模板可以从文件或者script标签中加载得到,本教程从EJS文件加载。

显示联系人

要创建联系人,你得先建立一个EJS模板,保存以下代码为contactsList.ejs进你的views文件夹:

复制代码代码如下:


<ulclass="clearfix">
 <%list(contacts,function(contact){%>
   <liclass="contactspan8"<%=(el)->el.data("contact",contact)%>>
     <%==can.view.render("views/contactView.ejs",{
       contact:contact,categories:categories
     })%>
   </li>
 <%})%>
</ul>

contactLists.ejs会渲染一个联系人列表,我们分析一下此模板:

复制代码代码如下:
<%list(contacts,function(contact){%>

list()方法里的回调方法如果配合配置有观察者的list使用时,一旦list的数据发生改变就运用动态绑定重复调用。

复制代码代码如下:
<liclass="contactspan8"<%=(el)->el.data("contact",contact)%>>

以上代码通过元素的回调方法生成一个有联系人数据的<li>。箭头后的方法执行后将el对象的数据设置给对应的元素。

复制代码代码如下:
<%==can.view.render("views/contactView.ejs",{
 contact:contact,categories:categories
})%>

以上代码将子模板contactView.ejs渲染成一个联系人。can.view.render()以模板和数据为参数返回HTML。

渲染单个联系人

子模板是一个将view组织成可管理块的好办法。同时也使你的模板简单和易于重用。教程后面将会用到此模板来创建联系人,将下面的代码保存为contactView.ejs进views文件夹:

复制代码代码如下:
<ahref="javascript://"class="remove"><iclass="icon-remove"></i></a>
<form>
<divclass="row">
 <divclass="span2">
   <imgsrc="img/contact.png"width="100"height="100">
 </div>
 <divclass="span3">
   <inputtype="text"name="name"placeholder="AddName"
     <%=contact.attr("name")?"value=""+contact.name+""":"class="empty""%>>
   <selectname="category">
     <%$.each(categories,function(i,category){%>
       <optionvalue="<%=category.data%>"<%=contact.category===category.data?"selected":""%>>
         <%=category.name%>
       </option>
     <%})%>
   </select>
 </div>
 <divclass="span3">
   <label>Address</label>
   <inputtype="text"name="address"
     <%=contact.attr("address")?"value=""+contact.address+""":"class="empty""%>>
   <label>Phone</label>
   <inputtype="text"name="phone"
     <%=contact.attr("phone")?"value=""+contact.phone+""":"class="empty""%>>
   <label>Email</label>
   <inputtype="text"name="email"
     <%=contact.attr("email")?"value=""+contact.email+""":"class="empty""%>>
 </div>
</div>
</form>

联系人的属性都放入了<input>标签里,这就可以编辑更新用户的资料。

活化你的View(好文艺。。)

EJS处理模板过程中如果有用到attr(),它周围的代码将会交由事件处理器管理,监听对应属性的变化,当属性发生变化,APP中关联的UI将会被更新。这功能利益于模板动态绑定机制,EJS的动态绑定是有选择性的,只有使用了attr()时才会为对应的属性开启。
我们通过contactView.ejs中一个<input>标签来了解它的用法:

复制代码代码如下:
<inputtype="text"name="name"placeholder="AddName"
 <%=contact.attr("name")?"value=""+contact.name+""":"class="empty""%>>

特殊标记里的代码将转变成事件绑定到此联系人的name属性上。当name属性发生变化,事件将被触发同时HTML结构会被更新。

使用can.Control来处理业务逻辑

can.Control创建了一个可组织,内在无泄漏,全权控制器,能用来创建widget或者处理业务逻辑。你通过所需要数据为一个DOM元素创建一个Control实例,可以在你的Control中定义方法绑定事件。
当Control所关联的元素从DOM被删除时,Contol会自去销毁自己,同时清除所绑定的方法。
要创建一个Control,通过传入你定义的包含有函数的对象给can.Control()来实现继承。接下来事件也给传进去了。
每个Contol实例都有几个重要的值和方法规范:
this? Control实例的引用
this.element?实例中你所创建的DOM元素
this.options?创建实例所需要的参数对象
init()?当实例创建成功时被调用

管理联系人

将以下代码片段添加到contacts.js文件来创建管理联系人的Control:

复制代码代码如下:
Contacts=can.Control({
 init:function(){
   this.element.html(can.view("views/contactsList.ejs",{
     contacts:this.options.contacts,
     categories:this.options.categories
   }));
 }
})

当Contacts的实例被创建时,init()会做两件事:
使用can.view()来渲染联系人。can.view()接收两个参数:包含有模板和数据的文件或者stript标签;将返回一个documentFragment(一个管理DOM元素的轻量容器)。
使用jQuery.html()将can.view()的documentFragment插入Control的元素

使用Model来表现数据

Model是APP数据的抽象层。本APP用到两个Model:一个对应联系人,一个对应类别。将以下代码添加到contacts.js:

复制代码代码如下:
Contact=can.Model({
 findAll:"GET/contacts",
 create :"POST/contacts",
 update :"PUT/contacts/{id}",
 destroy:"DELETE/contacts/{id}"
},{});
 
Category=can.Model({
 findAll:"GET/categories"
},{});

一个model有5个方法可能定义来CRUD数据,分别是findAll,findOne,create,update和destroy。你可重写这几个方法,不过最好的办法是使用REST服务(RepresentationalStateTransfer表述性状态转移)。正如上面的代码,你放心的忽略APP中不会用到的静态方法了。

这里要重点指出的是,model实例其实是源自CanJS的‘observables"。can.Observe提供对象的观察者模式can.Observe.List提供数组的观察模式。这意味着你可以通过attr()来get和set数据,同时监听数据的变动。
findAll()方法返回一个Model.list,就是当元素被添加或者移除时can.Observe.List所触发的事件。

使用Fixture来模仿Rest

Fixture拦截AJAX请求并通过文件或者方法来模拟应答。这对测试,或者后端还没有就绪时是非常有用的。Fixture就是APP的model模拟REST所需要的。
首先,你要准备一些数据给fixture,添加以下代码到:

复制代码代码如下:
varCONTACTS=[
 {
   id:1,
   name:"William",
   address:"1CanJSWay",
   email:"william@husker.com",
   phone:"0123456789",
   category:"co-workers"
 },
 {
   id:2,
   name:"Laura",
   address:"1CanJSWay",
   email:"laura@starbuck.com",
   phone:"0123456789",
   category:"friends"
 },
 {
   id:3,
   name:"Lee",
   address:"1CanJSWay",
   email:"lee@apollo.com",
   phone:"0123456789",
   category:"family"
 }
];
 
varCATEGORIES=[
 {
   id:1,
   name:"Family",
   data:"family"
 },
 {
   id:2,
   name:"Friends",
   data:"friends"
 },
 {
   id:3,
   name:"Co-workers",
   data:"co-workers"
 }
];

有了数据,要将其连接到fixture来模拟REST。can.fixture()接收两个参数。我们要拦截的URL和我们应答用的文件和方法。通常你要拦截的URL都是动态且遵循一个模式的。在需要在URL里添加以{}括起的通配符即可。

添加以下代码到contacts.js:

复制代码代码如下:
can.fixture("GET/contacts",function(){
return[CONTACTS];
});
 
varid=4;
can.fixture("POST/contacts",function(){
return{id:(id++)}
});
 
can.fixture("PUT/contacts/{id}",function(){
return{};
});
 
can.fixture("DELETE/contacts/{id}",function(){
return{};
});
 
can.fixture("GET/categories",function(){
return[CATEGORIES];
});

前4个fixture模拟Contactmodel的GET,POST,PUT和DELETE应答,第5个模拟Categorymodel的GET应答。

启动APP

你的APP有管理数据的Model,渲染联系人的View,将这一切组织起来的的Control。现在要做的就是启动APP了。Nowyouneedtokickstarttheapplication!
将以下代码添加到contacts.js:

复制代码代码如下:
$(document).ready(function(){
 $.when(Category.findAll(),Contact.findAll()).then(
   function(categoryResponse,contactResponse){
     varcategories=categoryResponse[0],
       contacts=contactResponse[0];
 
     newContacts("#contacts",{
       contacts:contacts,
       categories:categories
     });
 });
});

我们来分析一下这段代码:

复制代码代码如下:
$(document).ready(function(){

使用jQuery.ready方法监听DOM的ready。

复制代码代码如下:
$.when(Category.findAll(),Contact.findAll()).then(
 function(categoryResponse,contactResponse){

调用两个Model的findAll()方法来获取全部联系人的类型,由于findAll()有延时,$.when()则确保两个请求同时完成后才执行回调方法。

复制代码代码如下:
varcategories=categoryResponse[0],
 contacts=contactResponse[0];

从两个findAll()方法中获取对应Model实例的数据集。是应答所返回的数组的第一个元素。

复制代码代码如下:
newContacts("#contacts",{
 contacts:contacts,
 categories:categories
});

为#contacts元素创建Contact的Control。联系人和类型数据集传进Control。
用浏览器打开你的APP,你将看到如下的联系人列表:

总结

这是第教程系列的第一篇,你已经了解了CanJS的核心:
Models你的APP数据的抽象层
Views将数据转换成HTML的模板
Controls组织关联一切