选择正确的库
创建一个js app没有好的工具是很有难度的,jquery只是操作dom的库,没有提供任何创建app的基础,这就是为什么我们要一个类似canjs的专门的库。
canjs 是一个轻量级的mvc库,提供你创建一个js app所需的工具。
canjs 是一个轻量级的mvc库,提供你创建一个js app所需的工具。 它提供有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:
复制代码 代码如下:
canjs contacts manager
contacts manager
>http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js>>
在页面的底部你加载所需的js(包括你的app:contacts.js)。
教程中用到的css和图片文件可以下载。
用view来打造你的ui
view是用来渲染你app的ui模板。canjs 支持多种模板引擎,本文用ejs ,canjs包含有而且支持动态绑定。
ejs 模板的标签与html很像,支持包含js代码,三种常用标签如下:
执行js
执行js,并将非转义的结果写入当前位置的html
执行js,并将转义的结果写入当前位置的html(用于子模板).
模板可以从文件或者script标签中加载得到,本教程从 ejs 文件加载。
显示联系人
要创建联系人,你得先建立一个ejs 模板,保存以下代码为contactslist.ejs 进你的views 文件夹:
复制代码 代码如下:
el.data('contact', contact) %>>
contact: contact, categories: categories
}) %>
contactlists.ejs 会渲染一个联系人列表,我们分析一下此模板:
复制代码 代码如下:
list()方法里的回调方法如果配合配置有观察者的list使用时,一旦list的数据发生改变就运用动态绑定重复调用。
复制代码 代码如下:
el.data('contact', contact) %>>
以上代码通过元素的回调方法生成 一个有联系人数据的
。 箭头后的方法执行后将el对象的数据设置给对应的元素。
复制代码 代码如下:
contact: contact, categories: categories
}) %>
以上代码将子模板contactview.ejs 渲染成一个联系人。 can.view.render() 以模板和数据为参数返回html。
渲染单个联系人
子模板是一个将view组织成可管理块的好办法。 同时也使你的模板简单和易于重用。教程后面将会用到此模板来创建联系人,将下面的代码保存为contactview.ejs 进 views 文件夹:
复制代码 代码如下:
>
>
address
>
phone
>
email
>
联系人的属性都放入了 标签里,这就可以编辑更新用户的资料。
活化你的view(好文艺。。)
ejs 处理模板过程中如果有用到attr() ,它周围的代码将会交由事件处理器管理,监听对应属性的变化,当属性发生变化,app中关联的ui将会被更新。这功能利益于模板动态绑定机制,ejs的动态绑定是有选择性的,只有使用了attr()时才会为对应的属性开启。
我们通过 contactview.ejs 中一个标签来了解它的用法:
复制代码 代码如下:
>
特殊标记里的代码将转变成事件绑定到此联系人的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 服务(representational state transfer表述性状态转移)。正如上面的代码,你放心的忽略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,添加以下代码到:
复制代码 代码如下:
var contacts = [
{
id: 1,
name: 'william',
address: '1 canjs way',
email: 'william@husker.com',
phone: '0123456789',
category: 'co-workers'
},
{
id: 2,
name: 'laura',
address: '1 canjs way',
email: 'laura@starbuck.com',
phone: '0123456789',
category: 'friends'
},
{
id: 3,
name: 'lee',
address: '1 canjs way',
email: 'lee@apollo.com',
phone: '0123456789',
category: 'family'
}
];
var categories = [
{
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];
});
var id= 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模拟 contact model的get, post, put 和 delete 应答,第5个模拟 category model的get应答。
启动app
你的app有管理数据的model,渲染联系人的 view,将这一切组织起来的的control。现在要做的就是启动app了。 now you need to kickstart the application!
将以下代码添加到contacts.js :
复制代码 代码如下:
$(document).ready(function(){
$.when(category.findall(), contact.findall()).then(
function(categoryresponse, contactresponse){
var categories = categoryresponse[0],
contacts = contactresponse[0];
new contacts('#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()则确保两个请求同时完成后才执行回调方法。
复制代码 代码如下:
var categories = categoryresponse[0],
contacts = contactresponse[0];
从两个 findall() 方法中获取对应model实例的数据集。 是应答所返回的数组的第一个元素。
复制代码 代码如下:
new contacts('#contacts', {
contacts: contacts,
categories: categories
});
为 #contacts 元素创建contact 的control 。联系人和类型数据集传进control。
用浏览器打开你的app,你将看到如下的联系人列表:
总结
这是第教程系列的第一篇,你已经了解了canjs的核心:
models 你的app数据的抽象层
views 将数据转换成html的模板
controls 组织关联一切