emberjs學習一(環境和第一個例子)
博客:http://www.cnblogs.com/xiangbing/p/emberjs-test.html
案例:http://www.lovewebgames.com/emberjs/example/test1/index.html
源碼:https://github.com/tianxiangbing/emberjs-test
准備工作
首頁我們要做的是從網上下載下來emberjs相關的文件,目前在1.x的版本中,ember是要依賴jquery(v1.7.1~2.2.0) 和handlebars(v1.x)的,有一個比較好的方式來得到這些資源,那就是用bower.bower的安裝很簡單:
npm install -g bower
裝完bower就可以使用bower來下載資源了,比如我們要下載jquery 1.9.1版本的,我們可以這樣寫
bower install jquery#1.9.1
它會在當前目錄下建一個bower_components的目錄,把jquery的文件下載到jquery文件目錄下.我們也可以把git上的項目發布到bower上,然后再從bower安裝到本地,具體方法可以看這里http://blog.fens.me/nodejs-bower-intro/
我的案例已經發布在bower上,你可以直接用以下命令獲取
bower install emberjs-test
點開bower_components下的test1目錄,執行
npm install
安裝grunt-watch,方便開發
再下載ember相關的資源
bower.json:
"dependencies": { "jquery": "~1.9.1", "ember": "~1.13.10", "handlebars":"~1.3.0", "ember-data":"~1.13.11" }
執行 bower install
查看資源列表 bower list
如圖所示
開始一個例子
然后我們要根據這些文件做一個簡單的例子,我們新建一個html頁面index.html,引用js文件,代碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>emberjs 初學記要</title> <script type="text/javascript" src="http://localhost:9090/livereload.js"></script> </head> <body> <script type="text/javascript" src="bower_components/jquery/jquery.min.js"></script> <script type="text/javascript" src="bower_components/handlebars/handlebars.min.js"></script> <script type="text/javascript" src="bower_components/ember/ember.min.js"></script> </body> </html>
這里看到我在head里多引入了一個livereload.js
,這個文件是使用grunt watch
時生成的,可以動態的改變頁面,你可以使用chrome的插件livereload.
好了,准備工作做好了之后 ,我們就可以編寫首頁的模板了,在頁面添加如下代碼:
<script type="text/x-handlebars"> 首頁 </script>
然后新建一個js文件,這里命名為app.js,放在js目錄下,引入.
window.App = Ember.Application.create();
這時會發現頁面上什么都沒有,然后在console里還報了一個錯:
Uncaught Error: Cannot call `compile` without the template compiler loaded. Please load `ember-template-compiler.js` prior to calling `compile`.
這個錯誤的大致意思好像是說我沒有ember-template-compiler.js文件,但奇了怪的是,所以解析模板時出錯了;但是在更早期的版本里是不需要的,可能是后期為了移除handlebars所以獨立出來了吧,在bower_components/ember
中還真有這么個文件,好吧,引入它.
<script type="text/javascript" src="bower_components/jquery/jquery.min.js"></script> <script type="text/javascript" src="bower_components/handlebars/handlebars.min.js"></script> <script type="text/javascript" src="bower_components/ember/ember-template-compiler.js"></script> <script type="text/javascript" src="bower_components/ember/ember.min.js"></script> <script type="text/javascript" src="js/app.js"></script>
好了,頁面終於出現內容了,然后我們在模板中加入outlet
,這是一個其他模塊的入口,然后我們在app.js中加入其他的模塊路由.
App.Router.map(function(){ this.resource('add',{path:'add'}); });
這里可以使用resource也可以直接用route
this.route('add')
據說它們間的區別就是resource可以有子路由,但route已經是最小的路由了,所以可以理解為,大的類目時用recource,終極時用route,你開心就好。 然后我們添加add的模板,這里add的模板id要和link-to的參數一致,並且跟resource或route的第一個參數一樣,path參數指的是url里的hash值.
<script type="text/x-handlebars" id="add"> <table> <tr> <td>標題</td> <td><input type="text" /></td> </tr> <tr> <td>內容</td> <td><textarea></textarea></td> </tr> <tr> <td></td> <td><input type="button" value="確認"></td> </tr> </table> </script>
這里有一個操作,所以應該有個Controller,我們先在app.js里加上這個controller.
App.AddController=Ember.Controller.extend({ actions:{ new:function(){ console.log('new') var title = $('#title').val(); var content = $('#content').val(); //do save } } });
它的命名規則是單詞首字母大寫,然后ember會把它注冊到add這個模塊里,這樣你就可以在add模板中使用這個控制器了。把按鈕改掉
<input type="button" value="確認" {{action "new"}}>
由於我們現在還沒有使用localStorage這類本地存儲,所以我們可以使用變量來臨時的保存一下,但實際的應用中,似乎更多的是與服務器的交互。 它義數組var data=[];
然后再action/new
下加入
data.push({title:title,content:content}); this.transitionToRoute('index');
transitionToRoute
的意思就是轉到另一個路由去。我們這里轉到首頁去,然后我們看到一片空白的首頁,還不知道是什么情況,因為還沒有寫代碼讓剛才加入的記錄顯示出來,好,我們在首頁的模板中把記錄each出來.
<script type="text/x-handlebars" id="index"> <ol> {{#each model}} <li>{{title}}</li> {{/each}} </ol> </script>
這里each
的是model
,如果直接each .
會導致不更新。然后我們添加一個IndexRoute來返回一個數據集.
App.IndexRoute = Ember.Route.extend({ model: function() { return data } });
這里的IndexRoute就會默認在路由到index首頁時調用。
我們在添加一個查看的按鈕查看詳情,為了能找到當前記錄,我們給每條記錄加一個index屬性記錄當前索引:
data.push({
title: title,
content: content,
index:data.length
});
<li>{{title}}{{#link-to "info" this}}查看{{/link-to}}</li>
不知道為什么在這里不能直接取@index
索引,所以只能我們在每條記錄里加個唯一值。然后在路由中加上resouce
this.resource('index', { path: '/' }, function() { this.resource('info', { path: 'info/:index' }) })
這里我們把info的路由放在了index的下面,這樣,就可以達到index和info同時存在了。這里要在index的模板中加上一個{{outlet}}
才行。
{{model.title}}
{{model.content}}
同樣的情況出現了,我要加上model才行,不明白的為什么{{title}}
可以取出來content一定要{{model.content}}
才行。在InfoRoute中返回當前的數組值
App.InfoRoute = Ember.Route.extend({ model: function(param) { console.log(data[param.index].content) return data[param.index] } });
在詳情模板中加入編輯按鈕,我們根據一個值來判斷是顯示“編輯”還是“保存”.
<div style="float:left;"> <h1>{{model.title}}</h1> <p> {{model.content}} </p> {{#if isEditing}} <button {{action "save"}}>保存</button> {{else}} <button {{action "edit"}}>編輯</button> {{/if}} </div>
這里的isEditing是在Controller
的action
中新增的一個屬性,在actions
中新增save和edit方法
App.InfoController = Ember.ObjectController.extend({ actions: { isEditing: false, edit: function() { this.set('isEditing',true); }, save:function(){ this.set('isEditing',false); } } });
這里的值都要使用set方法來改變,否則不會導致頁面的刷新模板.然后我們加入一個子模板來顯示編輯的內容。
<script type="text/x-handlebars" id="post/edit"> <table> <tr> <td>標題</td> <td>{{input type="text" value=title}}</td> </tr> <tr> <td>內容</td> <td>{{textarea value=model.content}}</td> </tr> <tr> <td></td> <td><input type="button" value="確認" {{action "save"}}></td> </tr> </table> </script>
這里用的是{{input}}
方式的控件,這樣就可以實現傳說中的雙向綁定了,它是基於Ember.TextField
類的,所以也是可以自定義一個Input控件的。如下官方例子所示input api:
Todos.EditTodoView = Ember.TextField.extend({ didInsertElement: function() { this.$().focus(); } }); Ember.Handlebars.helper('edit-todo', Todos.EditTodoView);
然后就莫名其妙地完成了保存操作,好吧,我以為我還要save一下,官方的例子是使用的model,所以要對先this.get('model).save()
一下才會有用。
最后我們要做的就是刪除了,先加一個action為del的鏈接按鈕:
{{#each model}} <li>{{title}}{{#link-to "info" this}}查看{{/link-to}} <a href="javascript:void(0)" {{action "del" index}}>刪除</a></li> {{/each}}
然后在IndexController中新增del的action
App.IndexController = Ember.ArrayController.extend({ actions: { del: function(index) { var d = this.get('model'); console.log(d) var obj = d.findBy('index',index) d.removeObject(obj) } } });
這里的問題是,我們要對model進行操作,才能實時的反應到頁面上,看了下model的方法,可以使用findBy
找出該元素,再進行removeObject
最終,我們就完成了一整個的增刪改操作了。因為我也是在學習過程中,如果有什么不對的地方,請指出糾正吧!也歡迎加入我的Q群77813547