探索Emberjs制作一個(gè)簡(jiǎn)單的Todo應(yīng)用
更新時(shí)間:2012年11月07日 11:08:10 作者:
使用Emberjs制作一個(gè)簡(jiǎn)單的Todo應(yīng)用,需要的朋友可以參考下
目標(biāo)
使用Emberjs制作一個(gè)簡(jiǎn)單的Todo應(yīng)用,實(shí)現(xiàn)這樣一個(gè)效果:通過(guò)在文本框輸入文本,創(chuàng)建一條代辦事項(xiàng),代辦事項(xiàng)可以選擇優(yōu)先級(jí),完成的事項(xiàng)可以刪除。
準(zhǔn)備
完成這個(gè)應(yīng)用,需要做點(diǎn)準(zhǔn)備:
1、創(chuàng)建一個(gè)html頁(yè)面,暫時(shí)不管樣式;
2、腳本:emberjs,handlebars、jQuery。這三個(gè)腳本可以從網(wǎng)上獲得,我們將把他們加入到head標(biāo)簽里去。
制作
創(chuàng)建頁(yè)面,加入腳本,就可以開(kāi)始制作應(yīng)用。html代碼如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Ember--第一個(gè)應(yīng)用</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/wycats/handlebars.js/handlebars-1.0.rc.1.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/emberjs/ember.js/ember-1.0.0-pre.2.min.js"></script>
</head>
<body>
</body>
</html>
按照ember的要求,需要用Ember.Application.create()先創(chuàng)建應(yīng)用實(shí)例,這也作為應(yīng)用的命名空間。這個(gè)create方法可以傳遞一個(gè)對(duì)象屬性ready,屬性值是一個(gè)函數(shù),在應(yīng)用準(zhǔn)備就緒時(shí)調(diào)用。Ember還可以使用縮寫Em來(lái)代替。
在Ember中有一個(gè)Em.Logger對(duì)象,相當(dāng)于window.console,可以用來(lái)調(diào)試。我們可以在這個(gè)ready加入一個(gè)消息,顯示在控制臺(tái)中。
現(xiàn)在,在head標(biāo)簽里再增加一個(gè)script標(biāo)簽來(lái)寫應(yīng)用的腳本,實(shí)例化一個(gè)ember應(yīng)用,順便把MVC各模塊的區(qū)域也加上。腳本代碼如下:
/********************
application
********************/
window.App = Ember.Application.create(
{
ready:function(){
Em.Logger.info('歡迎使用待辦事項(xiàng)應(yīng)用');
}
}
);
/********************
model
********************/
/********************
view
********************/
/********************
controlle
********************/
然后,我們需要一個(gè)輸入框來(lái)輸入代辦事項(xiàng),需要?jiǎng)?chuàng)建一個(gè)ember文本框視圖。ember視圖可以用Ember.View類來(lái)創(chuàng)建(使用create方法)或擴(kuò)展(使用extend方法)一個(gè)新的視圖類。不過(guò)對(duì)于文本框視圖,ember提供了更直接的方式——Ember.TextField類,我們可以先使用這個(gè)類來(lái)擴(kuò)展一個(gè)自定義的視圖,然后再實(shí)例化添加到頁(yè)面上。我們將這個(gè)文本框視圖類命名AddItemView 。
在腳本代碼里的view區(qū)域添加上文本框視圖代碼:
App.AddItemView = Ember.TextField.extend({
});
可以給它加個(gè)提示語(yǔ),html5支持placeholder,可以拿來(lái)用。還需要在按下回車時(shí)將內(nèi)容添加到代表事項(xiàng)列表,這里需要用到一個(gè)屬性:insertNewline,在按下回車時(shí)會(huì)調(diào)用相應(yīng)的函數(shù)。加入后的代碼如下:
App.AddItemView = Ember.TextField.extend({
placeholder:'輸入待辦事項(xiàng)',
insertNewline:function(){}
});
由于現(xiàn)在還沒(méi)確定具體添加方法,函數(shù)體暫時(shí)先不寫。
用戶在按下回車時(shí)增加一條代辦事項(xiàng),需要一個(gè)列表來(lái)顯示,在ember中可以創(chuàng)建CollectionView來(lái)存放列表項(xiàng)目視圖,對(duì)于CollectionView,默認(rèn)會(huì)有一個(gè)content屬性用于存放列表項(xiàng)目對(duì)象,其屬性值是一個(gè)數(shù)組。為了讓其列表顯示為ul列表,需要定義CollectionView的標(biāo)簽名(tagName)為“ul”。我們給這個(gè)列表視圖命名為L(zhǎng)istView,并增加到文本框視圖的下方。最后代碼如下:
App.ListView = Ember.CollectionView.extend({
content:[],
tagName:'ul'
});
現(xiàn)在如果打開(kāi)頁(yè)面,是沒(méi)顯示任何內(nèi)容的,因?yàn)橐晥D還沒(méi)被渲染,要將視圖顯示出來(lái),需要handlebar模板的支持。
現(xiàn)在來(lái)修改html頁(yè)面的body塊,加入剛創(chuàng)建的兩個(gè)視圖,看看效果。
添加handlebar模板的方法是<script type="text/x-handlebars">/*視圖助手*/</script>,還可以指定模板名稱,在data-template-name屬性里定義,待會(huì)我們添加列表項(xiàng)目時(shí)會(huì)需要用到。
在模板里需要通過(guò)視圖助手(helper)來(lái)添加視圖,語(yǔ)法也很簡(jiǎn)單,用兩個(gè)花括號(hào)對(duì)包裹,里面通過(guò)模板關(guān)鍵字來(lái)指定要顯示的視圖,如:{{view App.AddItemView}}。其他模板助手可以在handlebar網(wǎng)站查到:http://handlebarsjs.com/。
現(xiàn)在先把文本框跟列表視圖添加到頁(yè)面上,修改后的body代碼如下:
<body>
<script type="text/x-handlebars">
<span>請(qǐng)輸入待辦事項(xiàng):</span>{{view App.AddItemView}}<br/>
{{view App.ListView}}
</script>
</body>
現(xiàn)在刷新頁(yè)面,會(huì)顯示一句“請(qǐng)輸入代辦事項(xiàng)”跟一個(gè)文本框,列表由于沒(méi)有內(nèi)容,不會(huì)顯示。
這個(gè)時(shí)候我們可以在content里添加點(diǎn)內(nèi)容,比如content:['a','b','c'],然后刷新頁(yè)面,你會(huì)發(fā)現(xiàn)列表區(qū)域只有三個(gè)小黑點(diǎn)(如果你沒(méi)重置列表樣式的話)。因?yàn)槟阍赾ontent里添加了三項(xiàng),但列表項(xiàng)還沒(méi)有指定一個(gè)顯示的模板,所以,顯示為空。為了讓你看到效果,我們來(lái)給列表項(xiàng)定義個(gè)顯示的模板吧。這里需要處理兩個(gè)地方,第一是在頁(yè)面加指定名稱的模板,第二是在列表視圖里定義列表項(xiàng)目的屬性。
定義列表項(xiàng)目,需要用到itemViewClass,它會(huì)將每個(gè)content項(xiàng)傳遞進(jìn)去并用指定的模板顯示。先來(lái)修改列表視圖ListView 吧,給它增加itemViewClass屬性,這也是一種視圖,所以需要用Ember.View來(lái)創(chuàng)建,在創(chuàng)建時(shí)同時(shí)指定用來(lái)顯示的模板名稱為itemTemplate,這個(gè)名稱同時(shí)將為出現(xiàn)在html的handlebar模板名稱里。修改后的代碼如下:
App.ListView = Ember.CollectionView.extend({
content:['a','b','c'],
tagName:'ul',
itemViewClass: Ember.View.extend({
templateName:'itemTemplate',
})
});
還差一步就完成了,現(xiàn)在來(lái)修改html,我們需要在body里再新建一個(gè)handlebar模板,并且會(huì)用到上面給出的模板名稱,代碼如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
</script>
接著同樣是添加模板助手,要把每一個(gè)content項(xiàng)傳遞給助手,會(huì)用到view.content。添加如下代碼:
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content}}
</script>
完成后,刷新頁(yè)面,現(xiàn)在終于把content里的內(nèi)容顯示出來(lái)了,而且,模板會(huì)自動(dòng)加上li標(biāo)簽。
繼續(xù)完善我們的應(yīng)用。我們總不能把content的內(nèi)容寫成固定的吧,這樣用戶還怎么添加呢。所以,現(xiàn)在考慮把用戶要添加的項(xiàng)目保存到一個(gè)數(shù)組里,然后content自己去取這個(gè)數(shù)組的內(nèi)容。同時(shí),ember框架支持雙向綁定,當(dāng)數(shù)組內(nèi)容修改時(shí),通過(guò)綁定的content也會(huì)同時(shí)改變,反之亦然。現(xiàn)在,就創(chuàng)建一個(gè)ember數(shù)組,然后跟content綁定吧。
ember數(shù)組可以通過(guò)ArrayController類來(lái)創(chuàng)建,它會(huì)把你傳進(jìn)去的普通javascript轉(zhuǎn)變?yōu)橐粋€(gè)新的ember數(shù)組對(duì)象,我們把用來(lái)管理項(xiàng)目的數(shù)組命名為todoStore,放到html頁(yè)面的controller區(qū)域,創(chuàng)建的代碼如下:
App.todoStore = Ember.ArrayController.create({
content:[]
});
現(xiàn)在可以把ListView 里的content數(shù)組放到這個(gè)todoStore 的數(shù)組里,然后綁定ListView 里的content到todoStore 上,這兩個(gè)對(duì)象將修改為如下所示:
App.ListView = Ember.CollectionView.extend({
contentBinding:'App.todoStore',
tagName:'ul',
itemViewClass: Ember.View.extend({
templateName:'itemTemplate'
})
});
/********************
controlle
********************/
App.todoStore = Ember.ArrayController.create({
content:['a','b','c']
});
Binding是個(gè)后綴,表示綁定,屬性值是綁定的對(duì)象,默認(rèn)取該對(duì)象的content屬性。修改完成后刷新頁(yè)面,如果你看到的頁(yè)面跟修改之前的一樣,說(shuō)明修改成功了。接著,是時(shí)候去掉content里的值了,我們需要的數(shù)據(jù)將由用戶在文本框里輸入。
考慮現(xiàn)在的交互過(guò)程,用戶在文本框輸入內(nèi)容,按下回車,程序獲取到該事件,調(diào)用一個(gè)方法創(chuàng)建一個(gè)新對(duì)象,再把這個(gè)新對(duì)象送給todoStore ,由于綁定作用,列表會(huì)自動(dòng)增加一項(xiàng)。
是時(shí)候改造下文本框視圖了,還記得insertNewline嗎?我們可以在這里創(chuàng)建新的項(xiàng)目。我們會(huì)用到三個(gè)方法:set()設(shè)置屬性值、get()獲取屬性值、pushObject()添加數(shù)據(jù),修改AddItemView 后的代碼如下:
App.AddItemView = Ember.TextField.extend({
placeholder:'輸入待辦事項(xiàng)',
insertNewline:function(){
var item = this.get('value');
App.todoStore.pushObject(item);
this.set('value','');
}
});
現(xiàn)在刷新頁(yè)面,然后輸入內(nèi)容,按回車,列表會(huì)添加輸入的內(nèi)容,說(shuō)明修改成功,如果你沒(méi)把todoStore 的content屬性里的內(nèi)容清空的話,現(xiàn)在會(huì)有4個(gè)列表項(xiàng)了。
距離我們的目標(biāo)還有一半啊,我們還缺少兩個(gè)功能:選擇優(yōu)先級(jí)跟刪除完成的項(xiàng)目。
要增加下拉列表,可以使用另一個(gè)方便的視圖:Ember.Select。我們可以直接在模板里直接創(chuàng)建一個(gè),同樣通過(guò)綁定,把下拉列表視圖的content綁定到另一個(gè)ember對(duì)象上,然后設(shè)置默認(rèn)選中的優(yōu)先級(jí)。優(yōu)先級(jí)也需要用到綁定,這樣在頁(yè)面上選擇的時(shí)候,才會(huì)同時(shí)修改對(duì)應(yīng)的ember對(duì)象里的內(nèi)容。先來(lái)創(chuàng)建這個(gè)ember對(duì)象,自定義該對(duì)象的selected屬性表示選中的值,其他名稱也行,這段代碼會(huì)加到todoStore對(duì)象的下面,命名為selectController,代碼如下:
App.selectController = Ember.Object.create({
selected:'低',
content:['高','中','低']
});
然后增加一個(gè)模板助手,并綁定selectController 里對(duì)應(yīng)的屬性,選中項(xiàng)的綁定需要用到selectionBinding,順便給個(gè)文字提示,然后添加到文本框模板的下面,修改后的代碼如下:
<script type="text/x-handlebars">
<span>請(qǐng)輸入待辦事項(xiàng):</span>{{view App.AddItemView}}<br/>
<span>請(qǐng)選擇優(yōu)先級(jí):</span>{{view Ember.Select contentBinding="App.selectController.content" selectionBinding="App.selectController.selected"}}
{{view App.ListView}}
</script>
現(xiàn)在刷新頁(yè)面就會(huì)出現(xiàn)下拉列表了。
要想讓列表項(xiàng)也出現(xiàn)這個(gè)優(yōu)先級(jí),還得花點(diǎn)功夫啊。是時(shí)候用model了,我們來(lái)創(chuàng)建一個(gè)model類,當(dāng)按下回車時(shí),從這個(gè)類創(chuàng)建一個(gè)實(shí)例,再把實(shí)例扔到todoStore里就可以了,另外,模板也要跟著修改,文本框視圖的創(chuàng)建方法也得改。這次改動(dòng)比較多了點(diǎn)。另外,還會(huì)用到一個(gè)計(jì)算屬性的功能,當(dāng)依賴的屬性變化時(shí),自動(dòng)更新。把這個(gè)model命名為TodoModel,放到model區(qū)域,創(chuàng)建代碼如下:
/********************
model
********************/
App.TodoModel = Em.Object.extend({
status:'',
value:'',
title:function(){
return '['+this.get('status')+']'+this.get('value');
}.property('status','value')
});
status表示選擇的優(yōu)先級(jí),value表示文本框里的值,title表示列表項(xiàng)目要顯示的內(nèi)容,這些屬性名都是自定義的。其中title不需要提供,因?yàn)樗O(shè)置為計(jì)算屬性,依賴于status跟value屬性,自動(dòng)計(jì)算獲取,property()方法就是ember函數(shù)轉(zhuǎn)變?yōu)橛?jì)算屬性的方法,后面的參數(shù)表示title依賴的屬性,當(dāng)status或value變化時(shí),就會(huì)自動(dòng)給出。
接著修改AddItemView的insertNewline屬性,需要取到兩個(gè)數(shù)據(jù),一個(gè)是文本框里的內(nèi)容,一個(gè)是下拉列表里選中的項(xiàng)目。文本框的值已經(jīng)知道怎么獲取了,下拉列表的值呢?別忘了我們已經(jīng)將選中項(xiàng)綁定到selectController里的selected屬性了,直接從那里取就可以了。修改后的AddItemView代碼如下:
App.AddItemView = Ember.TextField.extend({
placeholder:'輸入待辦事項(xiàng)',
elementId:'add',
insertNewline:function(){
var item = App.TodoModel.create({
status:App.selectController.get('selected'),
value:this.get('value')
});
App.todoStore.pushObject(item);
this.set('value','');
}
});
現(xiàn)在可以通過(guò)TodoModel類來(lái)實(shí)例化一個(gè)待辦項(xiàng)目并添加到todoStore里了,最后是修改項(xiàng)目列表的模板itemTemplate來(lái)顯示,在模板里需要取到當(dāng)前項(xiàng)目的title值來(lái)顯示,代碼如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content.title}}
</script>
現(xiàn)在添加的新待辦事項(xiàng)會(huì)顯示優(yōu)先級(jí)了。
好了,最后一個(gè)功能,刪除。跟添加pushObject相反,刪除用到的是removeObject。因?yàn)樗秋@示在每個(gè)列表項(xiàng)目里的,所以,需要修改itemViewClass跟itemTemplate模板,我們?cè)趇temViewClass里添加一個(gè)方法,當(dāng)用戶點(diǎn)擊時(shí)調(diào)用,把該方法命名為removeItem,代碼如下:
App.ListView = Ember.CollectionView.extend({
contentBinding:'App.todoStore',
tagName:'ul',
itemViewClass: Ember.View.extend({
templateName:'itemTemplate',
removeItem:function(){this.getPath( 'contentView.content' ).removeObject(this.get( 'content' ));}
})
});
最后是在itemTemplate模板里增加一個(gè)接受點(diǎn)擊的鏈接,用到的是action助手,第一個(gè)參數(shù)是方法名,target屬性用來(lái)指定對(duì)象,點(diǎn)擊時(shí)調(diào)用指定對(duì)象下的方法。修改后的itemTemplate代碼如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content.title}} <a href="#" {{action removeItem target="this"}} >X</a>
</script>
現(xiàn)在新增加的項(xiàng)目都會(huì)有個(gè)叉在右邊,點(diǎn)擊時(shí)就把當(dāng)前項(xiàng)目刪除。
最后還可以做點(diǎn)改進(jìn),當(dāng)鼠標(biāo)移動(dòng)到項(xiàng)目上時(shí)才顯示刪除鏈接,完成這個(gè)功能,需要修改itemViewClass以及在模板里增加邏輯判斷助手{{#if}}。你可以自己試著去做,也可以看看最后完整的代碼。
full code
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Ember--第一個(gè)應(yīng)用</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/wycats/handlebars.js/handlebars-1.0.rc.1.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/emberjs/ember.js/ember-1.0.0-pre.2.min.js"></script>
<script>
/********************
application
********************/
window.App = Ember.Application.create(
{
ready:function(){
Em.Logger.info('歡迎使用待辦事項(xiàng)應(yīng)用');
}
}
);
/********************
model
********************/
App.TodoModel = Em.Object.extend({
status:'',
value:'',
title:function(){
return '['+this.get('status')+']'+this.get('value');
}.property('status','value')
});
/********************
view
********************/
App.AddItemView = Ember.TextField.extend({
placeholder:'輸入待辦事項(xiàng)',
elementId:'add',
insertNewline:function(){
var item = App.TodoModel.create({
status:App.selectController.get('selected'),
value:this.get('value')
});
App.todoStore.pushObject(item);
this.set('value','');
}
});
App.ListView = Ember.CollectionView.extend({
contentBinding:'App.todoStore',
tagName:'ul',
itemViewClass: Ember.View.extend({
templateName:'itemTemplate',
removeItem:function(){this.getPath( 'contentView.content' ).removeObject(this.get( 'content' ));},
mouseEnter:function(){this.set('hover',true);},
mouseLeave:function(){this.set('hover',false);}
})
});
/********************
controlle
********************/
App.todoStore = Ember.ArrayController.create({
content:[]
});
App.selectController = Ember.Object.create({
selected:'低',
content:['高','中','低']
});
</script>
</head>
<body>
<script type="text/x-handlebars">
<span>請(qǐng)輸入待辦事項(xiàng):</span>{{view App.AddItemView}}<br/>
<span>請(qǐng)選擇優(yōu)先級(jí):</span>{{view Ember.Select contentBinding="App.selectController.content"
selectionBinding="App.selectController.selected"}}
{{view App.ListView}}
</script>
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content.title}} {{#if view.hover}}<a href="#" {{action removeItem target="this"}} >X</a>{{/if}}
</script>
</body>
</html>
使用Emberjs制作一個(gè)簡(jiǎn)單的Todo應(yīng)用,實(shí)現(xiàn)這樣一個(gè)效果:通過(guò)在文本框輸入文本,創(chuàng)建一條代辦事項(xiàng),代辦事項(xiàng)可以選擇優(yōu)先級(jí),完成的事項(xiàng)可以刪除。
準(zhǔn)備
完成這個(gè)應(yīng)用,需要做點(diǎn)準(zhǔn)備:
1、創(chuàng)建一個(gè)html頁(yè)面,暫時(shí)不管樣式;
2、腳本:emberjs,handlebars、jQuery。這三個(gè)腳本可以從網(wǎng)上獲得,我們將把他們加入到head標(biāo)簽里去。
制作
創(chuàng)建頁(yè)面,加入腳本,就可以開(kāi)始制作應(yīng)用。html代碼如下:
復(fù)制代碼 代碼如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Ember--第一個(gè)應(yīng)用</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/wycats/handlebars.js/handlebars-1.0.rc.1.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/emberjs/ember.js/ember-1.0.0-pre.2.min.js"></script>
</head>
<body>
</body>
</html>
按照ember的要求,需要用Ember.Application.create()先創(chuàng)建應(yīng)用實(shí)例,這也作為應(yīng)用的命名空間。這個(gè)create方法可以傳遞一個(gè)對(duì)象屬性ready,屬性值是一個(gè)函數(shù),在應(yīng)用準(zhǔn)備就緒時(shí)調(diào)用。Ember還可以使用縮寫Em來(lái)代替。
在Ember中有一個(gè)Em.Logger對(duì)象,相當(dāng)于window.console,可以用來(lái)調(diào)試。我們可以在這個(gè)ready加入一個(gè)消息,顯示在控制臺(tái)中。
現(xiàn)在,在head標(biāo)簽里再增加一個(gè)script標(biāo)簽來(lái)寫應(yīng)用的腳本,實(shí)例化一個(gè)ember應(yīng)用,順便把MVC各模塊的區(qū)域也加上。腳本代碼如下:
復(fù)制代碼 代碼如下:
/********************
application
********************/
window.App = Ember.Application.create(
{
ready:function(){
Em.Logger.info('歡迎使用待辦事項(xiàng)應(yīng)用');
}
}
);
/********************
model
********************/
/********************
view
********************/
/********************
controlle
********************/
然后,我們需要一個(gè)輸入框來(lái)輸入代辦事項(xiàng),需要?jiǎng)?chuàng)建一個(gè)ember文本框視圖。ember視圖可以用Ember.View類來(lái)創(chuàng)建(使用create方法)或擴(kuò)展(使用extend方法)一個(gè)新的視圖類。不過(guò)對(duì)于文本框視圖,ember提供了更直接的方式——Ember.TextField類,我們可以先使用這個(gè)類來(lái)擴(kuò)展一個(gè)自定義的視圖,然后再實(shí)例化添加到頁(yè)面上。我們將這個(gè)文本框視圖類命名AddItemView 。
在腳本代碼里的view區(qū)域添加上文本框視圖代碼:
復(fù)制代碼 代碼如下:
App.AddItemView = Ember.TextField.extend({
});
可以給它加個(gè)提示語(yǔ),html5支持placeholder,可以拿來(lái)用。還需要在按下回車時(shí)將內(nèi)容添加到代表事項(xiàng)列表,這里需要用到一個(gè)屬性:insertNewline,在按下回車時(shí)會(huì)調(diào)用相應(yīng)的函數(shù)。加入后的代碼如下:
復(fù)制代碼 代碼如下:
App.AddItemView = Ember.TextField.extend({
placeholder:'輸入待辦事項(xiàng)',
insertNewline:function(){}
});
由于現(xiàn)在還沒(méi)確定具體添加方法,函數(shù)體暫時(shí)先不寫。
用戶在按下回車時(shí)增加一條代辦事項(xiàng),需要一個(gè)列表來(lái)顯示,在ember中可以創(chuàng)建CollectionView來(lái)存放列表項(xiàng)目視圖,對(duì)于CollectionView,默認(rèn)會(huì)有一個(gè)content屬性用于存放列表項(xiàng)目對(duì)象,其屬性值是一個(gè)數(shù)組。為了讓其列表顯示為ul列表,需要定義CollectionView的標(biāo)簽名(tagName)為“ul”。我們給這個(gè)列表視圖命名為L(zhǎng)istView,并增加到文本框視圖的下方。最后代碼如下:
復(fù)制代碼 代碼如下:
App.ListView = Ember.CollectionView.extend({
content:[],
tagName:'ul'
});
現(xiàn)在如果打開(kāi)頁(yè)面,是沒(méi)顯示任何內(nèi)容的,因?yàn)橐晥D還沒(méi)被渲染,要將視圖顯示出來(lái),需要handlebar模板的支持。
現(xiàn)在來(lái)修改html頁(yè)面的body塊,加入剛創(chuàng)建的兩個(gè)視圖,看看效果。
添加handlebar模板的方法是<script type="text/x-handlebars">/*視圖助手*/</script>,還可以指定模板名稱,在data-template-name屬性里定義,待會(huì)我們添加列表項(xiàng)目時(shí)會(huì)需要用到。
在模板里需要通過(guò)視圖助手(helper)來(lái)添加視圖,語(yǔ)法也很簡(jiǎn)單,用兩個(gè)花括號(hào)對(duì)包裹,里面通過(guò)模板關(guān)鍵字來(lái)指定要顯示的視圖,如:{{view App.AddItemView}}。其他模板助手可以在handlebar網(wǎng)站查到:http://handlebarsjs.com/。
現(xiàn)在先把文本框跟列表視圖添加到頁(yè)面上,修改后的body代碼如下:
復(fù)制代碼 代碼如下:
<body>
<script type="text/x-handlebars">
<span>請(qǐng)輸入待辦事項(xiàng):</span>{{view App.AddItemView}}<br/>
{{view App.ListView}}
</script>
</body>
現(xiàn)在刷新頁(yè)面,會(huì)顯示一句“請(qǐng)輸入代辦事項(xiàng)”跟一個(gè)文本框,列表由于沒(méi)有內(nèi)容,不會(huì)顯示。
這個(gè)時(shí)候我們可以在content里添加點(diǎn)內(nèi)容,比如content:['a','b','c'],然后刷新頁(yè)面,你會(huì)發(fā)現(xiàn)列表區(qū)域只有三個(gè)小黑點(diǎn)(如果你沒(méi)重置列表樣式的話)。因?yàn)槟阍赾ontent里添加了三項(xiàng),但列表項(xiàng)還沒(méi)有指定一個(gè)顯示的模板,所以,顯示為空。為了讓你看到效果,我們來(lái)給列表項(xiàng)定義個(gè)顯示的模板吧。這里需要處理兩個(gè)地方,第一是在頁(yè)面加指定名稱的模板,第二是在列表視圖里定義列表項(xiàng)目的屬性。
定義列表項(xiàng)目,需要用到itemViewClass,它會(huì)將每個(gè)content項(xiàng)傳遞進(jìn)去并用指定的模板顯示。先來(lái)修改列表視圖ListView 吧,給它增加itemViewClass屬性,這也是一種視圖,所以需要用Ember.View來(lái)創(chuàng)建,在創(chuàng)建時(shí)同時(shí)指定用來(lái)顯示的模板名稱為itemTemplate,這個(gè)名稱同時(shí)將為出現(xiàn)在html的handlebar模板名稱里。修改后的代碼如下:
復(fù)制代碼 代碼如下:
App.ListView = Ember.CollectionView.extend({
content:['a','b','c'],
tagName:'ul',
itemViewClass: Ember.View.extend({
templateName:'itemTemplate',
})
});
還差一步就完成了,現(xiàn)在來(lái)修改html,我們需要在body里再新建一個(gè)handlebar模板,并且會(huì)用到上面給出的模板名稱,代碼如下:
復(fù)制代碼 代碼如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
</script>
接著同樣是添加模板助手,要把每一個(gè)content項(xiàng)傳遞給助手,會(huì)用到view.content。添加如下代碼:
復(fù)制代碼 代碼如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content}}
</script>
完成后,刷新頁(yè)面,現(xiàn)在終于把content里的內(nèi)容顯示出來(lái)了,而且,模板會(huì)自動(dòng)加上li標(biāo)簽。
繼續(xù)完善我們的應(yīng)用。我們總不能把content的內(nèi)容寫成固定的吧,這樣用戶還怎么添加呢。所以,現(xiàn)在考慮把用戶要添加的項(xiàng)目保存到一個(gè)數(shù)組里,然后content自己去取這個(gè)數(shù)組的內(nèi)容。同時(shí),ember框架支持雙向綁定,當(dāng)數(shù)組內(nèi)容修改時(shí),通過(guò)綁定的content也會(huì)同時(shí)改變,反之亦然。現(xiàn)在,就創(chuàng)建一個(gè)ember數(shù)組,然后跟content綁定吧。
ember數(shù)組可以通過(guò)ArrayController類來(lái)創(chuàng)建,它會(huì)把你傳進(jìn)去的普通javascript轉(zhuǎn)變?yōu)橐粋€(gè)新的ember數(shù)組對(duì)象,我們把用來(lái)管理項(xiàng)目的數(shù)組命名為todoStore,放到html頁(yè)面的controller區(qū)域,創(chuàng)建的代碼如下:
復(fù)制代碼 代碼如下:
App.todoStore = Ember.ArrayController.create({
content:[]
});
現(xiàn)在可以把ListView 里的content數(shù)組放到這個(gè)todoStore 的數(shù)組里,然后綁定ListView 里的content到todoStore 上,這兩個(gè)對(duì)象將修改為如下所示:
復(fù)制代碼 代碼如下:
App.ListView = Ember.CollectionView.extend({
contentBinding:'App.todoStore',
tagName:'ul',
itemViewClass: Ember.View.extend({
templateName:'itemTemplate'
})
});
/********************
controlle
********************/
App.todoStore = Ember.ArrayController.create({
content:['a','b','c']
});
Binding是個(gè)后綴,表示綁定,屬性值是綁定的對(duì)象,默認(rèn)取該對(duì)象的content屬性。修改完成后刷新頁(yè)面,如果你看到的頁(yè)面跟修改之前的一樣,說(shuō)明修改成功了。接著,是時(shí)候去掉content里的值了,我們需要的數(shù)據(jù)將由用戶在文本框里輸入。
考慮現(xiàn)在的交互過(guò)程,用戶在文本框輸入內(nèi)容,按下回車,程序獲取到該事件,調(diào)用一個(gè)方法創(chuàng)建一個(gè)新對(duì)象,再把這個(gè)新對(duì)象送給todoStore ,由于綁定作用,列表會(huì)自動(dòng)增加一項(xiàng)。
是時(shí)候改造下文本框視圖了,還記得insertNewline嗎?我們可以在這里創(chuàng)建新的項(xiàng)目。我們會(huì)用到三個(gè)方法:set()設(shè)置屬性值、get()獲取屬性值、pushObject()添加數(shù)據(jù),修改AddItemView 后的代碼如下:
復(fù)制代碼 代碼如下:
App.AddItemView = Ember.TextField.extend({
placeholder:'輸入待辦事項(xiàng)',
insertNewline:function(){
var item = this.get('value');
App.todoStore.pushObject(item);
this.set('value','');
}
});
現(xiàn)在刷新頁(yè)面,然后輸入內(nèi)容,按回車,列表會(huì)添加輸入的內(nèi)容,說(shuō)明修改成功,如果你沒(méi)把todoStore 的content屬性里的內(nèi)容清空的話,現(xiàn)在會(huì)有4個(gè)列表項(xiàng)了。
距離我們的目標(biāo)還有一半啊,我們還缺少兩個(gè)功能:選擇優(yōu)先級(jí)跟刪除完成的項(xiàng)目。
要增加下拉列表,可以使用另一個(gè)方便的視圖:Ember.Select。我們可以直接在模板里直接創(chuàng)建一個(gè),同樣通過(guò)綁定,把下拉列表視圖的content綁定到另一個(gè)ember對(duì)象上,然后設(shè)置默認(rèn)選中的優(yōu)先級(jí)。優(yōu)先級(jí)也需要用到綁定,這樣在頁(yè)面上選擇的時(shí)候,才會(huì)同時(shí)修改對(duì)應(yīng)的ember對(duì)象里的內(nèi)容。先來(lái)創(chuàng)建這個(gè)ember對(duì)象,自定義該對(duì)象的selected屬性表示選中的值,其他名稱也行,這段代碼會(huì)加到todoStore對(duì)象的下面,命名為selectController,代碼如下:
復(fù)制代碼 代碼如下:
App.selectController = Ember.Object.create({
selected:'低',
content:['高','中','低']
});
然后增加一個(gè)模板助手,并綁定selectController 里對(duì)應(yīng)的屬性,選中項(xiàng)的綁定需要用到selectionBinding,順便給個(gè)文字提示,然后添加到文本框模板的下面,修改后的代碼如下:
復(fù)制代碼 代碼如下:
<script type="text/x-handlebars">
<span>請(qǐng)輸入待辦事項(xiàng):</span>{{view App.AddItemView}}<br/>
<span>請(qǐng)選擇優(yōu)先級(jí):</span>{{view Ember.Select contentBinding="App.selectController.content" selectionBinding="App.selectController.selected"}}
{{view App.ListView}}
</script>
現(xiàn)在刷新頁(yè)面就會(huì)出現(xiàn)下拉列表了。
要想讓列表項(xiàng)也出現(xiàn)這個(gè)優(yōu)先級(jí),還得花點(diǎn)功夫啊。是時(shí)候用model了,我們來(lái)創(chuàng)建一個(gè)model類,當(dāng)按下回車時(shí),從這個(gè)類創(chuàng)建一個(gè)實(shí)例,再把實(shí)例扔到todoStore里就可以了,另外,模板也要跟著修改,文本框視圖的創(chuàng)建方法也得改。這次改動(dòng)比較多了點(diǎn)。另外,還會(huì)用到一個(gè)計(jì)算屬性的功能,當(dāng)依賴的屬性變化時(shí),自動(dòng)更新。把這個(gè)model命名為TodoModel,放到model區(qū)域,創(chuàng)建代碼如下:
復(fù)制代碼 代碼如下:
/********************
model
********************/
App.TodoModel = Em.Object.extend({
status:'',
value:'',
title:function(){
return '['+this.get('status')+']'+this.get('value');
}.property('status','value')
});
status表示選擇的優(yōu)先級(jí),value表示文本框里的值,title表示列表項(xiàng)目要顯示的內(nèi)容,這些屬性名都是自定義的。其中title不需要提供,因?yàn)樗O(shè)置為計(jì)算屬性,依賴于status跟value屬性,自動(dòng)計(jì)算獲取,property()方法就是ember函數(shù)轉(zhuǎn)變?yōu)橛?jì)算屬性的方法,后面的參數(shù)表示title依賴的屬性,當(dāng)status或value變化時(shí),就會(huì)自動(dòng)給出。
接著修改AddItemView的insertNewline屬性,需要取到兩個(gè)數(shù)據(jù),一個(gè)是文本框里的內(nèi)容,一個(gè)是下拉列表里選中的項(xiàng)目。文本框的值已經(jīng)知道怎么獲取了,下拉列表的值呢?別忘了我們已經(jīng)將選中項(xiàng)綁定到selectController里的selected屬性了,直接從那里取就可以了。修改后的AddItemView代碼如下:
復(fù)制代碼 代碼如下:
App.AddItemView = Ember.TextField.extend({
placeholder:'輸入待辦事項(xiàng)',
elementId:'add',
insertNewline:function(){
var item = App.TodoModel.create({
status:App.selectController.get('selected'),
value:this.get('value')
});
App.todoStore.pushObject(item);
this.set('value','');
}
});
現(xiàn)在可以通過(guò)TodoModel類來(lái)實(shí)例化一個(gè)待辦項(xiàng)目并添加到todoStore里了,最后是修改項(xiàng)目列表的模板itemTemplate來(lái)顯示,在模板里需要取到當(dāng)前項(xiàng)目的title值來(lái)顯示,代碼如下:
復(fù)制代碼 代碼如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content.title}}
</script>
現(xiàn)在添加的新待辦事項(xiàng)會(huì)顯示優(yōu)先級(jí)了。
好了,最后一個(gè)功能,刪除。跟添加pushObject相反,刪除用到的是removeObject。因?yàn)樗秋@示在每個(gè)列表項(xiàng)目里的,所以,需要修改itemViewClass跟itemTemplate模板,我們?cè)趇temViewClass里添加一個(gè)方法,當(dāng)用戶點(diǎn)擊時(shí)調(diào)用,把該方法命名為removeItem,代碼如下:
復(fù)制代碼 代碼如下:
App.ListView = Ember.CollectionView.extend({
contentBinding:'App.todoStore',
tagName:'ul',
itemViewClass: Ember.View.extend({
templateName:'itemTemplate',
removeItem:function(){this.getPath( 'contentView.content' ).removeObject(this.get( 'content' ));}
})
});
最后是在itemTemplate模板里增加一個(gè)接受點(diǎn)擊的鏈接,用到的是action助手,第一個(gè)參數(shù)是方法名,target屬性用來(lái)指定對(duì)象,點(diǎn)擊時(shí)調(diào)用指定對(duì)象下的方法。修改后的itemTemplate代碼如下:
復(fù)制代碼 代碼如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content.title}} <a href="#" {{action removeItem target="this"}} >X</a>
</script>
現(xiàn)在新增加的項(xiàng)目都會(huì)有個(gè)叉在右邊,點(diǎn)擊時(shí)就把當(dāng)前項(xiàng)目刪除。
最后還可以做點(diǎn)改進(jìn),當(dāng)鼠標(biāo)移動(dòng)到項(xiàng)目上時(shí)才顯示刪除鏈接,完成這個(gè)功能,需要修改itemViewClass以及在模板里增加邏輯判斷助手{{#if}}。你可以自己試著去做,也可以看看最后完整的代碼。
復(fù)制代碼 代碼如下:
full code
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Ember--第一個(gè)應(yīng)用</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/wycats/handlebars.js/handlebars-1.0.rc.1.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/emberjs/ember.js/ember-1.0.0-pre.2.min.js"></script>
<script>
/********************
application
********************/
window.App = Ember.Application.create(
{
ready:function(){
Em.Logger.info('歡迎使用待辦事項(xiàng)應(yīng)用');
}
}
);
/********************
model
********************/
App.TodoModel = Em.Object.extend({
status:'',
value:'',
title:function(){
return '['+this.get('status')+']'+this.get('value');
}.property('status','value')
});
/********************
view
********************/
App.AddItemView = Ember.TextField.extend({
placeholder:'輸入待辦事項(xiàng)',
elementId:'add',
insertNewline:function(){
var item = App.TodoModel.create({
status:App.selectController.get('selected'),
value:this.get('value')
});
App.todoStore.pushObject(item);
this.set('value','');
}
});
App.ListView = Ember.CollectionView.extend({
contentBinding:'App.todoStore',
tagName:'ul',
itemViewClass: Ember.View.extend({
templateName:'itemTemplate',
removeItem:function(){this.getPath( 'contentView.content' ).removeObject(this.get( 'content' ));},
mouseEnter:function(){this.set('hover',true);},
mouseLeave:function(){this.set('hover',false);}
})
});
/********************
controlle
********************/
App.todoStore = Ember.ArrayController.create({
content:[]
});
App.selectController = Ember.Object.create({
selected:'低',
content:['高','中','低']
});
</script>
</head>
<body>
<script type="text/x-handlebars">
<span>請(qǐng)輸入待辦事項(xiàng):</span>{{view App.AddItemView}}<br/>
<span>請(qǐng)選擇優(yōu)先級(jí):</span>{{view Ember.Select contentBinding="App.selectController.content"
selectionBinding="App.selectController.selected"}}
{{view App.ListView}}
</script>
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content.title}} {{#if view.hover}}<a href="#" {{action removeItem target="this"}} >X</a>{{/if}}
</script>
</body>
</html>
相關(guān)文章
非html5實(shí)現(xiàn)js版彈球游戲示例代碼
彈球游戲,一般都是使用html5來(lái)實(shí)現(xiàn)的,其實(shí)不然,使用js也可以實(shí)現(xiàn)類似的效果,下面有個(gè)不錯(cuò)的示例,感興趣的朋友可以參考下,希望對(duì)大家有所幫助2013-09-09JS實(shí)現(xiàn)的系統(tǒng)調(diào)色板完整實(shí)例
這篇文章主要介紹了JS實(shí)現(xiàn)的系統(tǒng)調(diào)色板,結(jié)合完整實(shí)例形式分析了js實(shí)現(xiàn)調(diào)色板效果的具體步驟與實(shí)現(xiàn)技巧,涉及js數(shù)值計(jì)算與頁(yè)面元素操作的方法,需要的朋友可以參考下2016-12-12HTML頁(yè)面登錄時(shí)的JS驗(yàn)證方法
這篇文章主要介紹了HTML界面登錄時(shí)的JS驗(yàn)證方法,需要的朋友可以參考下2014-05-05js+canvas實(shí)現(xiàn)網(wǎng)站背景鼠標(biāo)吸附線條動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了js+canvas實(shí)現(xiàn)網(wǎng)站背景鼠標(biāo)吸附線條動(dòng)畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07Cpage.js給組件綁定事件的實(shí)現(xiàn)代碼
Cpage.js是一款輕量級(jí)的Mvvm框架,使用TypeScript(JavaScript的超集)開(kāi)發(fā)。下面通過(guò)本文給大家分享Cpage.js給組件綁定事件的實(shí)現(xiàn)代碼,需要的的朋友參考下吧2017-08-08Javascript this 的一些學(xué)習(xí)總結(jié)
相信有C++、C#或Java等編程經(jīng)驗(yàn)的各位,對(duì)于this關(guān)鍵字再熟悉不過(guò)了。由于Javascript是一種面向?qū)ο蟮木幊陶Z(yǔ)言,它和C++、C#或Java一樣都包含this關(guān)鍵字,接下來(lái)我們將向大家介紹Javascript中的this關(guān)鍵字2012-08-08