前端輕量級(jí)MVC框架CanJS詳解
選擇正確的庫(kù)
創(chuàng)建一個(gè)JS APP沒(méi)有好的工具是很有難度的,jQuery只是操作DOM的庫(kù),沒(méi)有提供任何創(chuàng)建APP的基礎(chǔ),這就是為什么我們要一個(gè)類(lèi)似CanJS的專(zhuān)門(mén)的庫(kù)。
CanJS 是一個(gè)輕量級(jí)的MVC庫(kù),提供你創(chuàng)建一個(gè)JS APP所需的工具。
CanJS 是一個(gè)輕量級(jí)的MVC庫(kù),提供你創(chuàng)建一個(gè)JS APP所需的工具。 它提供有MVC (Model-View-Control) 模式的基本框架,模板動(dòng)態(tài)綁定, route的支持且 內(nèi)存安全。同時(shí)支持 jQuery, Zepto, Mootools, YUI, Dojo,有豐富的擴(kuò)展和插件。
第一部分你將學(xué)到:
創(chuàng)建Control控制層 和 View 視圖層(UI模板) 來(lái)顯示聯(lián)系人
用Model模型層來(lái)表示數(shù)據(jù)
使用 fixtures 插件模擬ajax返回?cái)?shù)據(jù)
你肯定激動(dòng)了!我們開(kāi)始碼代碼吧。
建立好你的文件夾和HTML
你先給你的APP創(chuàng)建一個(gè)文件夾,目錄下再建立4個(gè)子文件夾:css, js,views 和 img。如下:
contacts_manager
css
js
views
img
保存以下的代碼為 index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CanJS Contacts Manager</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/contacts.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="span12">
<h1>Contacts Manager</h1>
</div>
</div>
<div class="row">
<div class="span3">
<div class="well">
<nav id="filter"></nav>
</div>
</div>
<div class="span9">
<div id="create"></div>
<div id="contacts"></div>
</div>
</div>
</div>
<script src=">
<script src="js/can.jquery.min.js"></script>
<script src="js/can.fixture.js"></script>
<script src="js/contacts.js"></script>
</body>
</html>
在頁(yè)面的底部你加載所需的JS(包括你的APP:contacts.js)。
教程中用到的CSS和圖片文件可以下載。
用View來(lái)打造你的UI
View是用來(lái)渲染你APP的UI模板。CanJS 支持多種模板引擎,本文用EJS ,CanJS包含有而且支持動(dòng)態(tài)綁定。
EJS 模板的標(biāo)簽與HTML很像,支持包含JS代碼,三種常用標(biāo)簽如下:
<% CODE %> 執(zhí)行JS
<%= CODE %> 執(zhí)行JS,并將非轉(zhuǎn)義的結(jié)果寫(xiě)入當(dāng)前位置的HTML
<%== CODE %> 執(zhí)行JS,并將轉(zhuǎn)義的結(jié)果寫(xiě)入當(dāng)前位置的HTML(用于子模板).
模板可以從文件或者script標(biāo)簽中加載得到,本教程從 EJS 文件加載。
顯示聯(lián)系人
要?jiǎng)?chuàng)建聯(lián)系人,你得先建立一個(gè)EJS 模板,保存以下代碼為contactsList.ejs 進(jìn)你的views 文件夾:
<ul class="clearfix">
<% list(contacts, function(contact){ %>
<li class="contact span8" <%= (el)-> el.data('contact', contact) %>>
<%== can.view.render('views/contactView.ejs', {
contact: contact, categories: categories
}) %>
</li>
<% }) %>
</ul>
contactLists.ejs 會(huì)渲染一個(gè)聯(lián)系人列表,我們分析一下此模板:
<% list(contacts, function(contact){ %>
list()方法里的回調(diào)方法如果配合配置有觀察者的list使用時(shí),一旦list的數(shù)據(jù)發(fā)生改變就運(yùn)用動(dòng)態(tài)綁定重復(fù)調(diào)用。
<li class="contact span8" <%= (el)-> el.data('contact', contact) %>>
以上代碼通過(guò)元素的回調(diào)方法生成 一個(gè)有聯(lián)系人數(shù)據(jù)的<li>。 箭頭后的方法執(zhí)行后將el對(duì)象的數(shù)據(jù)設(shè)置給對(duì)應(yīng)的元素。
<%== can.view.render('views/contactView.ejs', {
contact: contact, categories: categories
}) %>
以上代碼將子模板contactView.ejs 渲染成一個(gè)聯(lián)系人。 can.view.render() 以模板和數(shù)據(jù)為參數(shù)返回HTML。
渲染單個(gè)聯(lián)系人
子模板是一個(gè)將view組織成可管理塊的好辦法。 同時(shí)也使你的模板簡(jiǎn)單和易于重用。教程后面將會(huì)用到此模板來(lái)創(chuàng)建聯(lián)系人,將下面的代碼保存為contactView.ejs 進(jìn) views 文件夾:
<a href="javascript://" class="remove"><i class="icon-remove"></i></a>
<form>
<div class="row">
<div class="span2">
<img src="img/contact.png" width="100" height="100">
</div>
<div class="span3">
<input type="text" name="name" placeholder="Add Name"
<%= contact.attr('name') ? "value='" + contact.name + "'" : "class='empty'" %>>
<select name="category">
<% $.each(categories, function(i, category){ %>
<option value="<%= category.data %>" <%= contact.category === category.data ? "selected" : "" %>>
<%= category.name %>
</option>
<% }) %>
</select>
</div>
<div class="span3">
<label>Address</label>
<input type="text" name="address"
<%= contact.attr('address') ? "value='" + contact.address + "'" : "class='empty'" %>>
<label>Phone</label>
<input type="text" name="phone"
<%= contact.attr('phone') ? "value='" + contact.phone + "'" : "class='empty'" %>>
<label>Email</label>
<input type="text" name="email"
<%= contact.attr('email') ? "value='" + contact.email + "'" : "class='empty'" %>>
</div>
</div>
</form>
聯(lián)系人的屬性都放入了 <input> 標(biāo)簽里,這就可以編輯更新用戶(hù)的資料。
活化你的View(好文藝。。)
EJS 處理模板過(guò)程中如果有用到attr() ,它周?chē)拇a將會(huì)交由事件處理器管理,監(jiān)聽(tīng)對(duì)應(yīng)屬性的變化,當(dāng)屬性發(fā)生變化,APP中關(guān)聯(lián)的UI將會(huì)被更新。這功能利益于模板動(dòng)態(tài)綁定機(jī)制,EJS的動(dòng)態(tài)綁定是有選擇性的,只有使用了attr()時(shí)才會(huì)為對(duì)應(yīng)的屬性開(kāi)啟。
我們通過(guò) contactView.ejs 中一個(gè)<input>標(biāo)簽來(lái)了解它的用法:
<input type="text" name="name" placeholder="Add Name"
<%= contact.attr('name') ? "value='" + contact.name + "'" : "class='empty'" %>>
特殊標(biāo)記里的代碼將轉(zhuǎn)變成事件綁定到此聯(lián)系人的name屬性上。當(dāng)name屬性發(fā)生變化,事件將被觸發(fā)同時(shí)HTML結(jié)構(gòu)會(huì)被更新。
使用can.Control來(lái)處理業(yè)務(wù)邏輯
can.Control 創(chuàng)建了一個(gè)可組織,內(nèi)在無(wú)泄漏,全權(quán)控制器,能用來(lái)創(chuàng)建widget或者處理業(yè)務(wù)邏輯。你通過(guò)所需要數(shù)據(jù)為一個(gè)DOM元素創(chuàng)建一個(gè)Control實(shí)例,可以在你的Control中定義方法綁定事件。
當(dāng) Control 所關(guān)聯(lián)的元素從DOM被刪除時(shí),Contol會(huì)自去銷(xiāo)毀自己,同時(shí)清除所綁定的方法。
要?jiǎng)?chuàng)建一個(gè) Control,通過(guò)傳入你定義的包含有函數(shù)的對(duì)象給 can.Control() 來(lái)實(shí)現(xiàn)繼承。接下來(lái)事件也給傳進(jìn)去了。
每個(gè)Contol實(shí)例都有幾個(gè)重要的值和方法規(guī)范:
this – Control 實(shí)例的引用
this.element – 實(shí)例中你所創(chuàng)建的DOM 元素
this.options – 創(chuàng)建實(shí)例所需要的參數(shù)對(duì)象
init() – 當(dāng)實(shí)例創(chuàng)建成功時(shí)被調(diào)用
管理聯(lián)系人
將以下代碼片段添加到contacts.js 文件來(lái)創(chuàng)建管理聯(lián)系人的Control:
Contacts = can.Control({
init: function(){
this.element.html(can.view('views/contactsList.ejs', {
contacts: this.options.contacts,
categories: this.options.categories
}));
}
})
當(dāng) Contacts 的實(shí)例被創(chuàng)建時(shí), init() 會(huì)做兩件事:
使用can.view() 來(lái)渲染聯(lián)系人。 can.view() 接收兩個(gè)參數(shù):包含有模板和數(shù)據(jù)的文件或者stript標(biāo)簽;將返回一個(gè)documentFragment (一個(gè)管理DOM元素的輕量容器)。
使用jQuery.html()將can.view() 的documentFragment 插入Control的元素
使用Model來(lái)表現(xiàn)數(shù)據(jù)
Model 是APP數(shù)據(jù)的抽象層。本APP用到兩個(gè)Model:一個(gè)對(duì)應(yīng)聯(lián)系人,一個(gè)對(duì)應(yīng)類(lèi)別。將以下代碼添加到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'
},{});
一個(gè)model 有5個(gè)方法可能定義來(lái)CRUD數(shù)據(jù), 分別是findAll, findOne, create, update 和 destroy。你可重寫(xiě)這幾個(gè)方法,不過(guò)最好的辦法是使用 REST 服務(wù)(Representational State Transfer表述性狀態(tài)轉(zhuǎn)移)。正如上面的代碼,你放心的忽略APP中不會(huì)用到的靜態(tài)方法了。
這里要重點(diǎn)指出的是,model實(shí)例其實(shí)是源自 CanJS 的‘observables'。can.Observe 提供對(duì)象的觀察者模式can.Observe.List 提供數(shù)組的觀察模式。這意味著你可以通過(guò)attr()來(lái)get和set數(shù)據(jù),同時(shí)監(jiān)聽(tīng)數(shù)據(jù)的變動(dòng)。
findAll() 方法返回一個(gè) Model.list,就是當(dāng)元素被添加或者移除時(shí) can.Observe.List 所觸發(fā)的事件。
使用Fixture來(lái)模仿Rest
Fixture攔截 AJAX 請(qǐng)求并通過(guò)文件或者方法來(lái)模擬應(yīng)答。這對(duì)測(cè)試,或者后端還沒(méi)有就緒時(shí)是非常有用的。Fixture就是APP的model模擬REST所需要的。
首先,你要準(zhǔn)備一些數(shù)據(jù)給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'
}
];
有了數(shù)據(jù),要將其連接到fixture來(lái)模擬REST 。can.fixture()接收兩個(gè)參數(shù)。 我們要攔截的URL和我們應(yīng)答用的文件和方法。通常你要攔截的URL都是動(dòng)態(tài)且遵循一個(gè)模式的。在需要在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個(gè) fixture模擬 Contact model的GET, POST, PUT 和 DELETE 應(yīng)答,第5個(gè)模擬 Category model的GET應(yīng)答。
啟動(dòng)APP
你的APP有管理數(shù)據(jù)的Model,渲染聯(lián)系人的 View,將這一切組織起來(lái)的的Control?,F(xiàn)在要做的就是啟動(dòng)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
});
});
});
我們來(lái)分析一下這段代碼:
$(document).ready(function(){
使用 jQuery.ready 方法監(jiān)聽(tīng)DOM的ready。
$.when(Category.findAll(), Contact.findAll()).then(
function(categoryResponse, contactResponse){
調(diào)用兩個(gè)Model的 findAll() 方法來(lái)獲取全部聯(lián)系人的類(lèi)型,由于findAll() 有延時(shí), $.when()則確保兩個(gè)請(qǐng)求同時(shí)完成后才執(zhí)行回調(diào)方法。
var categories = categoryResponse[0],
contacts = contactResponse[0];
從兩個(gè) findAll() 方法中獲取對(duì)應(yīng)Model實(shí)例的數(shù)據(jù)集。 是應(yīng)答所返回的數(shù)組的第一個(gè)元素。
new Contacts('#contacts', {
contacts: contacts,
categories: categories
});
為 #contacts 元素創(chuàng)建Contact 的Control 。聯(lián)系人和類(lèi)型數(shù)據(jù)集傳進(jìn)Control。
用瀏覽器打開(kāi)你的APP,你將看到如下的聯(lián)系人列表:
總結(jié)
這是第教程系列的第一篇,你已經(jīng)了解了CanJS的核心:
Models 你的APP數(shù)據(jù)的抽象層
Views 將數(shù)據(jù)轉(zhuǎn)換成HTML的模板
Controls 組織關(guān)聯(lián)一切
- Extjs4.1.x 框架搭建 采用Application動(dòng)態(tài)按需加載MVC各模塊完美實(shí)現(xiàn)
- Javascript MVC框架Backbone.js詳解
- 超級(jí)簡(jiǎn)單實(shí)現(xiàn)JavaScript MVC 樣式框架
- 12種JavaScript常用的MVC框架比較分析
- 講解JavaScript的Backbone.js框架的MVC結(jié)構(gòu)設(shè)計(jì)理念
- 使用jQuery.form.js/springmvc框架實(shí)現(xiàn)文件上傳功能
- Angularjs中的事件廣播 —全面解析$broadcast,$emit,$on
- AngularJs解決跨域問(wèn)題案例詳解(簡(jiǎn)單方法)
- jquery.form.js框架實(shí)現(xiàn)文件上傳功能案例解析(springmvc)
- indexedDB bootstrap angularjs之 MVC DOMO (應(yīng)用示例)
- AngularJs Javascript MVC 框架
相關(guān)文章
TypeScript數(shù)組實(shí)現(xiàn)棧與對(duì)象實(shí)現(xiàn)棧的區(qū)別詳解
這篇文章主要為大家介紹了TypeScript數(shù)組實(shí)現(xiàn)棧與對(duì)象實(shí)現(xiàn)棧的區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09typescript類(lèi)型體操及關(guān)鍵字使用示例詳解
這篇文章主要為大家介紹了typescript類(lèi)型體操及關(guān)鍵字使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11FastAdmin表單驗(yàn)證data-rule插件—Nice-validator的使用方法
FastAdmin的表單驗(yàn)證data-rule非常方便,也很炫酷,采用的Nice-validator是一款非常強(qiáng)大的表單驗(yàn)證插件,通過(guò)簡(jiǎn)單在元素上配置規(guī)則,即可達(dá)到驗(yàn)證的效果,怎么使用Nice-validator插件呢2023-09-09前端構(gòu)建 Less入門(mén)(CSS預(yù)處理器)
眾多CSS預(yù)處理器中Less的語(yǔ)法最接近原生CSS,因此相對(duì)來(lái)說(shuō)更容易上手,假如有JS、C#等編程經(jīng)驗(yàn)的話,其實(shí)上述的幾種預(yù)處理器的學(xué)習(xí)成本也不會(huì)特別高。下面是我們這陣子的學(xué)習(xí)筆記,以便日后查閱2017-03-03