摘要:在文件夾內(nèi)創(chuàng)建,內(nèi)容如下創(chuàng)建,內(nèi)容如下使用安裝依賴在的頭部加入調(diào)用命令,同時(shí)在你的默認(rèn)瀏覽器中打開。最后,我們更新下,給每個(gè)報(bào)道添加鏈接修改完畢地后,可以在瀏覽器中直接看到結(jié)果。
編者注:我們發(fā)現(xiàn)了有趣的系列文章《30天學(xué)習(xí)30種新技術(shù)》,正在翻譯,一天一篇更新,年終禮包。下面是第19天的內(nèi)容。
到目前為止,我們這一系列文章涉及了Bower、AngularJS、GruntJS、PhoneGap和MeteorJS 這些JavaScript技術(shù)。今天我打算學(xué)習(xí)一個(gè)名為Ember的框架。本文將介紹如何用Ember創(chuàng)建一個(gè)單頁面的社交化書簽應(yīng)用。本教程將包括兩篇:第1篇介紹客戶端代碼和用HTML 5本地存儲(chǔ)持久保存數(shù)據(jù),第2篇中我們將使用一個(gè)部署在OpenShift上的REST后端。過幾天我會(huì)寫第2篇。
應(yīng)用我們將開發(fā)一個(gè)社交化書簽應(yīng)用,允許用戶提交和分享鏈接。你可以在這里查看這個(gè)應(yīng)用。這個(gè)應(yīng)用可以做到:
當(dāng)用戶訪問/時(shí),他會(huì)看到以提交時(shí)間排序的報(bào)道列表。
當(dāng)用戶訪問某個(gè)書簽時(shí),例如#/stories/d6p88,用戶會(huì)看到關(guān)于這個(gè)報(bào)道的信息,例如是誰提交的,何時(shí)提交的,以及文章的摘要。
最后,當(dāng)用戶通過#/story/new提交新報(bào)道時(shí),內(nèi)容會(huì)存儲(chǔ)在用戶瀏覽器的本地存儲(chǔ)上。
什么是Ember?Ember是一個(gè)客戶端的JavaScript MV* 框架,用來構(gòu)建野心勃勃的web應(yīng)用。它依賴于jQuery和Handlebars庫。如果你曾經(jīng)在Backbone下工作,那么你會(huì)發(fā)現(xiàn)Ember是一個(gè)武斷的Backbone,或者Backbone++。Ember可以為你完成很多事情,如果你遵循它的命名約定的話。Ember.js在這方面很突出。因此,如果我們?cè)趹?yīng)用中加入了url路由和報(bào)道,那么我們就有了這些:
報(bào)道的模板
StoriesRoute
StoriesController
請(qǐng)參考命名約定文檔來理解Ember的命名約定。
Ember核心概念本節(jié)將介紹我們的示例應(yīng)用中將涉及的四個(gè)EmberJS的核心概念:
模型:模型代表我們展示給用戶的應(yīng)用領(lǐng)域內(nèi)的對(duì)象。在上述例子中,一個(gè)報(bào)道就代表一個(gè)模型。報(bào)道,加上它的屬性,包括標(biāo)題、url等,構(gòu)成一個(gè)模型。模型可以通過jQuery加載服務(wù)器端的JSON數(shù)據(jù)的方式來獲取和更新,也可以通過Ember Data來獲取和更新。Ember Data是一個(gè)客戶端的ORM實(shí)現(xiàn),可以利用它方便地對(duì)底層的持久性存儲(chǔ)進(jìn)行CRUD操作。Ember Data提供一個(gè)倉庫接口,可以借助提供的一些適配器配置。Ember Data提供的兩個(gè)核心適配器是RESTAdapter和FixtureAdapter。在本文中,我們將使用LocalStorage適配器,該適配器將數(shù)據(jù)持久化為 HTML 5 的LocalStorage。請(qǐng)參閱此文檔了解詳情。
路由器和路由:路由器指定應(yīng)用的所有路由。路由器將URL映射到路由。例如,當(dāng)一個(gè)用戶訪問/#/story/new的時(shí)候,將渲染newstory模板。該模板展現(xiàn)了一個(gè)HTML表單。用戶可通過創(chuàng)建Ember.Route子類來定制路由。在上述例子中,用戶訪問/#/story/new將渲染一個(gè)基于newstory模板的默認(rèn)模型。NewStoryRoute會(huì)負(fù)責(zé)將默認(rèn)的模型分配給newstory模板。請(qǐng)參閱文檔了解詳情。
控制器:控制器可以做兩件事——首先它裝飾路由返回的模型,接著它監(jiān)聽用戶執(zhí)行的行動(dòng)。例如,當(dāng)用戶提交報(bào)道的時(shí)候,NewStoryController負(fù)責(zé)通過Ember Data API將報(bào)道的數(shù)據(jù)持續(xù)化到存儲(chǔ)層。請(qǐng)參閱文檔了解詳情。
模版:模板向用戶展示應(yīng)用的界面。每個(gè)應(yīng)用都有一個(gè)默認(rèn)的應(yīng)用模板。
Ember的Chrome插件EmberJS提供了一個(gè)Chrome插件,因此調(diào)試ember應(yīng)用很容易。這個(gè)插件可以在 chrome web store 下載安裝。可以查看Ember團(tuán)隊(duì)做的視頻了解chrome插件的詳情。
Github倉庫今天的示例程序的代碼可從github取得。
第一步 下載新手套裝ember提供了一套新手裝備,因此開始使用框架非常簡單。新手套裝包括了需要用到的javascript文件(ember-*.js、jquery-*.js和handlerbars-*.js)以及示例應(yīng)用。下載新手套裝,解壓縮,最后重命名為getbookmarks。
wget https://github.com/emberjs/starter-kit/archive/v1.1.2.zip unzip v1.1.2.zip mv starter-kit-1.1.2/ getbookmarks
在瀏覽器中打開index.html,你會(huì)看到如下頁面:
第二步 啟用GruntJS監(jiān)視這一步是可選的,不過如果你做了這步,那么你的生活質(zhì)量將大大提高。如果你決定跳過這步,那么每次你做了改動(dòng)之后都需要刷新瀏覽器。在第7天的文章,我討論了GruntJS的在線重載功能。我沒有在EmberJS里找到任何自動(dòng)重載的功能,因此我決定使用GruntJS的livereload來提高效率。你需要Node、NPM和Grunt-CLI。請(qǐng)參考我第5天和第7天的文章了解詳情。
在getbookmarks文件夾內(nèi)創(chuàng)建package.json,內(nèi)容如下:
{ "name": "getbookmarks", "version": "0.0.1", "description": "GetBookMarks application", "devDependencies": { "grunt": "~0.4.1", "grunt-contrib-watch": "~0.5.3" } }
創(chuàng)建Gruntfile.js,內(nèi)容如下:
module.exports = function(grunt) { grunt.initConfig({ watch :{ scripts :{ files : ["js/app.js","css/*.css","index.html"], options : { livereload : 9090, } } } }); grunt.loadNpmTasks("grunt-contrib-watch"); grunt.registerTask("default", []); };
使用npm安裝依賴:
npm install grunt --save-dev npm install grunt-contrib-watch --save-dev
在index.html的頭部加入:
調(diào)用grunt watch命令,同時(shí)在你的默認(rèn)瀏覽器中打開index.html。
; grunt watch Running "watch" task Waiting...OK
修改index.html,無需刷新就能看到改變:
第三步 理解新手模板應(yīng)用在新手模板中,除了css之外,有兩個(gè)和應(yīng)用相關(guān)的文件——index.html和app.js。為了理解模板應(yīng)用的作用,我們需要理解app.js。
App = Ember.Application.create(); App.Router.map(function() { // put your routes here }); App.IndexRoute = Ember.Route.extend({ model: function() { return ["red", "yellow", "blue"]; } });
解釋下以上的代碼:
第一行創(chuàng)建了一個(gè)Ember應(yīng)用的實(shí)例。
使用App.Route.map定義應(yīng)用的路由。每個(gè)Ember應(yīng)用都有一個(gè)默認(rèn)路由Index,綁定到/。所以,當(dāng)調(diào)用/路由的時(shí)候,index模板將被渲染。index模板由index.html定義。感覺到了很多“約定大于配置”了吧?
在Ember中,每個(gè)模板都有一個(gè)model作為支持。路由負(fù)責(zé)制定哪個(gè)mobdel支持哪個(gè)模板。在上述app.js中,IndexRoute返回一個(gè)字符串?dāng)?shù)組,作為index模板的model。index模板迭代這個(gè)數(shù)組然后渲染一個(gè)列表。
第四步 移除新手模板代碼移除js/app.js中的代碼,然后用以下內(nèi)容替換:
App = Ember.Application.create(); App.Router.map(function() { // put your routes here });
相應(yīng)地,將index.html的內(nèi)容替換為:
第五步 添加Twitter BootstrapGetBookMarks -- Share your favorite links online
我們將使用twitter bootstrap來給應(yīng)用添加樣式。從官網(wǎng)下載twitter bootstrap包,然后復(fù)制bootstrap.css到css文件夾,同時(shí)復(fù)制字體文件夾。
接著在index.html中加入bootstrap.css,在頁首使用一個(gè)固定位置的導(dǎo)航條。
GetBookMarks -- Share your favorite links online
上述html中,代表我們的應(yīng)用模板。應(yīng)用模板使用{{outlet}}標(biāo)簽為其他模板預(yù)留位置,其內(nèi)容取決于url。
在css/style.css中加入下面的代碼。這會(huì)在正文上方添加一個(gè)40px的空白。這樣才能正確地渲染固定位置的導(dǎo)航條。
body{ padding-top: 40px; }第五步 提交新報(bào)道
我們將開始實(shí)現(xiàn)提交新報(bào)道的功能。Ember建議你圍繞著URL思考。當(dāng)用戶訪問#/story/new的時(shí)候,會(huì)展示一個(gè)表單。
在App.Router.Map中增加一個(gè)綁定#/story/new的新路由:
App.Router.map(function() { this.resource("newstory" , {path : "story/new"}); });
接著我們?cè)?b>index.html中添加一個(gè)渲染表單的newstory模板:
訪問#/story/new即可查看表單:
接著我們?cè)趯?dǎo)航條中添加一個(gè)鏈接,這樣訪問報(bào)道提交表單就很容易。替換一下nav元素:
注意上面我們用{{#link-to}}創(chuàng)建了一個(gè)指向路由的鏈接。請(qǐng)參閱文檔了解詳情。
表單已經(jīng)有了,接下來要添加HTML 5本地存儲(chǔ)的功能。為了添加本地存儲(chǔ)支持,我們需要首先下載Ember Data和Local Storage Adapter JavaScript文件。將這些文件放在js/libs下。接著,在index.html中添加這些script標(biāo)簽。
如前所述,Ember Data是一個(gè)客戶端的ORM實(shí)現(xiàn),它使在底層存儲(chǔ)進(jìn)行CRUD操作很容易。這里我們將使用LSAdapter。在app.js中加入:
App.ApplicationAdapter = DS.LSAdapter.extend({ namespace: "stories" });
接著是定義model。一篇報(bào)道需要有url、title(標(biāo)題)、fullname(提交報(bào)道的用戶的全名)、excerpt(摘要),以及SubmittedOn(日期)信息。在下面的模型中,我們使用了字符串和日期類型。適配器默認(rèn)支持的屬性類型為字符串、數(shù)字、布爾值和日期。
App.Story = DS.Model.extend({ url : DS.attr("string"), tags : DS.attr("string"), fullname : DS.attr("string"), title : DS.attr("string"), excerpt : DS.attr("string"), submittedOn : DS.attr("date") });
接著我們編寫NewstoryController來持久化內(nèi)容:
App.NewstoryController = Ember.ObjectController.extend({ actions :{ save : function(){ var url = $("#url").val(); var tags = $("#tags").val(); var fullname = $("#fullname").val(); var title = $("#title").val(); var excerpt = $("#excerpt").val(); var submittedOn = new Date(); var store = this.get("store"); var story = store.createRecord("story",{ url : url, tags : tags, fullname : fullname, title : title, excerpt : excerpt, submittedOn : submittedOn }); story.save(); this.transitionToRoute("index"); } } });
以上代碼展示了如何從獲取表單中的值,然后使用store API在內(nèi)存中創(chuàng)建記錄。為了在localstorage中存儲(chǔ)記錄,我們需要調(diào)用Story對(duì)象的save方法。最后,我們將用戶重定向到index路由。
接著我們測(cè)試下這個(gè)應(yīng)用,創(chuàng)建一個(gè)新的報(bào)道,接著打開Chrome開發(fā)者工具,在資源區(qū)域你可以查看這則報(bào)道。
第六步 顯示所有報(bào)道接著我們要做的是,當(dāng)用戶訪問首頁的時(shí)候,展示所有報(bào)道。
正如我之前提到的,路由負(fù)責(zé)詢問model。我們將加上IndexRoute,它會(huì)找出本地存儲(chǔ)中保存的所有報(bào)道。
App.IndexRoute = Ember.Route.extend({ model : function(){ var stories = this.get("store").findAll("story"); return stories; } });
每個(gè)路由支持一個(gè)模板。IndexRoute支持index模板,因此我們需要修改index.html:
現(xiàn)在訪問/,我們會(huì)看到一個(gè)報(bào)道的列表:
還有一個(gè)問題,報(bào)道沒有按照時(shí)間順序排列。我們將創(chuàng)建一個(gè)IndexController負(fù)責(zé)排序。我們指定依照submittedOn屬性倒序排列,以確保新的報(bào)道出現(xiàn)在上面。
App.IndexController = Ember.ArrayController.extend({ sortProperties : ["submittedOn"], sortAscending : false });
修改之后,我們會(huì)看到按照submittedOn屬性排序的報(bào)道。
第七步 查看多帶帶的報(bào)道最后要實(shí)現(xiàn)的功能是:用戶點(diǎn)擊某則報(bào)道的時(shí)候會(huì)看到詳細(xì)信息。我們加一個(gè)路由:
App.Router.map(function() { this.resource("index",{path : "/"},function(){ this.resource("story", { path:"/stories/:story_id" }); }); this.resource("newstory" , {path : "story/new"}); });
以上的代碼展示了如何嵌套路由。
:story_id部分叫做動(dòng)態(tài)字段,因?yàn)橄鄳?yīng)的報(bào)道 id會(huì)被注入U(xiǎn)RL。
然后我們添加根據(jù)報(bào)道id獲取報(bào)道的StoryRoute。
App.StoryRoute = Ember.Route.extend({ model : function(params){ var store = this.get("store"); return store.find("story",params.story_id); } });
最后,我們更新下index.html,給每個(gè)報(bào)道添加鏈接:
修改完畢地后,可以在瀏覽器中直接看到結(jié)果。
第八步 為submittedOn日期添加格式Ember下有輔助函數(shù)的概念。所有Handlebars模板都可以調(diào)用輔助函數(shù)。
我們將使用moment.js庫為日期添加格式。將以下代碼加入index.html。
接著我們將定義我們的第一個(gè)輔助函數(shù),該函數(shù)將日期轉(zhuǎn)為人類可讀的形式:
Ember.Handlebars.helper("format-date", function(date){ return moment(date).fromNow(); });
最后我們?cè)趫?bào)道模板中加入format-data輔助函數(shù)。
報(bào)道頁面的效果如下:
今天就到這里了。持續(xù)反饋。
原文 Day 19: Ember--The Missing EmberJS Tutorial
翻譯 SegmentFault
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/77996.html
摘要:攝像拍照,濾鏡中文指南本文出自春哥個(gè)人博客作者黎躍春追時(shí)間的人簡介是推出的一個(gè)天挑戰(zhàn)。完整中文版指南及視頻教程在從零到壹全棧部落。這個(gè)新的對(duì)象表示指定的對(duì)象或?qū)ο蟆? Day19 - 攝像、拍照,濾鏡中文指南 本文出自:春哥個(gè)人博客作者:?黎躍春-追時(shí)間的人簡介:JavaScript30 是 Wes Bos 推出的一個(gè) 30 天挑戰(zhàn)。項(xiàng)目免費(fèi)提供了 30 個(gè)視頻教程、30 個(gè)挑戰(zhàn)的起始文...
摘要:中文指南二作者簡介是推出的一個(gè)天挑戰(zhàn)。完整中文版指南及視頻教程在從零到壹全棧部落。第七天的練習(xí)是接著之前中文指南一的練習(xí),繼續(xù)熟練數(shù)組的方法,依舊沒有頁面顯示效果,所以請(qǐng)打開瀏覽器的面板進(jìn)行調(diào)試運(yùn)行。 Day07 - Array Cardio 中文指南二 作者:?liyuechun 簡介:JavaScript30 是 Wes Bos 推出的一個(gè) 30 天挑戰(zhàn)。項(xiàng)目免費(fèi)提供了 30 個(gè)...
摘要:實(shí)現(xiàn)可伸縮的圖片墻中文指南作者簡介是推出的一個(gè)天挑戰(zhàn)。現(xiàn)在你看到的是這系列指南的第篇。完整指南在從零到壹全棧部落。實(shí)現(xiàn)效果點(diǎn)擊任意一張圖片,圖片展開,同時(shí)從圖片上下兩方分別移入文字。 Day05 - Flex 實(shí)現(xiàn)可伸縮的圖片墻 中文指南 作者:?liyuechun 簡介:JavaScript30 是 Wes Bos 推出的一個(gè) 30 天挑戰(zhàn)。項(xiàng)目免費(fèi)提供了 30 個(gè)視頻教程、30 ...
閱讀 2299·2021-09-30 09:47
閱讀 2218·2021-09-26 09:55
閱讀 2945·2021-09-24 10:27
閱讀 1539·2019-08-27 10:54
閱讀 966·2019-08-26 13:40
閱讀 2493·2019-08-26 13:24
閱讀 2418·2019-08-26 13:22
閱讀 1726·2019-08-23 18:38