前言css
目前爲止,這個系列咱們討論了Bower, AngularJS, GruntJS和PhoneGap JavaScript技術。今天,決定回到JavaScript上學習一個叫Meteor的框架。雖然Meteor有很好的介紹文檔,不過沒有入門指導,我更傾向入門指導由於可讓咱們快速開始一項技術。這篇博客,咱們來學習怎樣用Meteor框架開發一個投票程序。html
Meteor是下一代開源平臺,用於在最短期內開發實時Web Apps. 它有一套和現存JavaScript框架如AngularJS, BackboneJS等很是不一樣的體系。通常的,當咱們用backbone或者anular,客戶端(Angular或者Backbone)與REST後端通訊,咱們能夠用Java, NodeJS, PHP等寫REST後端。git
Meteor裏, DDP(Distributed Data Protocol)協議用來傳輸客戶端和服務器間的數據。DDP是用來解決客戶端JavaScipt開發者面對的最大問題的一種標準方法:查詢服務器端的數據庫,而後發送結果給客戶端,再把數據庫的全部更新推送到客戶端。github
服務器端的Meteor程序基於Node和MongoDB, 客戶端和服務器端的程序都用Meteor API開發,之後,開發者能夠有除了MongoDB以外的其餘數據庫選擇。 web
若是你想說服本身爲何要學Meteor, 看看這七條核心準則。 mongodb
這篇博客,咱們來開發一個投票程序,容許用戶對問題發表和投票,程序能夠作如下事:shell
今天的demo放在github: day15-epoll-meteor-demo.數據庫
Meteor很容易上手,若是你用的Mac或者Linux,打開終端輸入如下命令。npm
$ curl https://install.meteor.com | /bin/sh
Windows用戶,請參照文檔。 編程
建立Meteor程序很簡單,裝好Meteor後,只需運行建立命令。
$ meteor create epoll
它會在你機器上建立一個epoll的目錄,再放一些模板文件,項目結構如圖。
咱們來一個個看看這些文件:
if (Meteor.isClient) { Template.hello.greeting = function () { return "Welcome to epoll."; }; Template.hello.events({ 'click input' : function () { // template data, if any, is available in 'this' if (typeof console !== 'undefined') console.log("You pressed the button"); } }); } if (Meteor.isServer) { Meteor.startup(function () { // code to run on server at startup }); }
以上代碼中,Meteor.isServer和Meteor.isClient標籤用來區分服務器代碼和客戶端代碼。
要運行程序,文件目錄改到epoll輸入如下命令:
$ cd epoll
$ meteor
程序運行在http://localhost:3000. 點擊click按鈕,咱們能夠從谷歌開發工具中看到消息You pressed the button.
在epoll.js裏對greeting作如下改動:
Template.hello.greeting = function () { return "The Missing Meteor Tutorial!!!"; };
改動會自動更新而後加載頁面。
以前提到過,Meteor用MongoDB存儲數據,當咱們裝Meteor包時,它會自動下載最新MongoDB,能夠看到MongoDB安裝在<user.home>/.meteor目錄下,我花了些時間分析MongoDB在哪運行,用ps -ef命令找到了安裝路徑。
$ ps -ef|grep mongo 501 1704 1687 0 2:22PM ttys001 0:09.28 /Users/shekhargulati/.meteor/tools/0b2f28e18b/mongodb/bin/mongod --bind_ip 127.0.0.1 --smallfiles --nohttpinterface --port 3002 --dbpath /Users/shekhargulati/day15/epoll/.meteor/local/db
在我機器上,MongoDB運行在端口3002, 這避免了已有的MongoDB的默認端口27017, 數據庫目錄指向程序目錄的.meteor文件夾。
前面提到Meteor以包的形式實現功能,這些包在瀏覽器和服務器上都能工做,要查看Meteor支持的全部包,運行如下命令:
$ meteor list
添加包用Meteor add移除用meteor remove.
咱們用Twitter Bootstrap顯示頁面格式,要添加Bootstrap,輸入如下命令。
$ meteor add bootstrap
對Twitter Bootrap包僅有的提示是這個不是最新版本,Meteor包支持的版本是2.3.2.
在這個投票應用中咱們用Twitter Authentication來確保功能,一個用戶要先被Twitter受權,才能投票或者新增提問。
Meteor提供accounts-ui包來給程序添加登錄插件,要添加這個包,運行如下命令:
$ meteor add accounts-ui
如今添加受權方給程序,這個程序咱們用的是Twitter,不過也用facebook, github, google, webo或者meetup.
$ meteor add accounts-twitter
添加這個包後,須要更新epoll.html來顯示Twitter登錄按鈕,更新以下:
<head> <title>Epoll : Share your opinion online, anywhere, anytime</title> </head> <body> <div class="navbar navbar-static-top navbar-inverse"> <div class="navbar-inner"> <div class="container"> <a class="brand" href="/">Epoll</a> <ul class="nav pull-right"> <li> {{loginButtons}} </li> </ul> </div> </div> </div> <div class="container" id="main"> {{> banner}} </div> </body> <template name="banner"> <div class="container"> <div class="row"> <div class="span6"> <div class="well"> <h4>Sign in using Twitter to submit new questions or to vote on existing questions.</h4> {{loginButtons}} </div> </div> </div> </div> </template>
同時在epoll.css添加格式。
/* CSS declarations go here */
.login-display-name{color: white }
.login-button{background-color: white}
#main {
padding-top:20px;
}
程序會自動更新,你能夠看到如圖頁面:
點擊Configure Twitter Login, 會被要求輸入登陸twitter的用戶名和密碼。
要獲得配置信息,須要新建twitter程序而後保存配置,保存以後,就能夠用twitter登陸。
受權後本身的帳號後,能夠登錄程序,完成後能夠退出。
新增用戶會在MongoDB的用戶集合裏建立,要查看用戶,用mongo客戶端鏈接MongoDB數據庫。
$ ~/.meteor/tools/0b2f28e18b/mongodb/bin/mongo --port 3002 MongoDB shell version: 2.4.6 connecting to: 127.0.0.1:3002/test > show dbs local 0.03125GB meteor 0.0625GB > use meteor switched to db meteor > show collections meteor_accounts_loginServiceConfiguration system.indexes users > db.meteor_accounts_loginServiceConfiguration.find() { "service" : "twitter", "consumerKey" : "xxx", "secret" : "xxx", "_id" : "xxx" } > > > db.users.find().pretty() { "createdAt" : ISODate("2013-11-11T18:03:23.488Z"), "_id" : "xx", "services" : { "twitter" : { "id" : "66993334", "screenName" : "shekhargulati", "accessToken" : "xxx-xxx", "accessTokenSecret" : "xxx", "profile_image_url" : "http://pbs.twimg.com/profile_images/378800000254412405/e4adcf8fb7800c3e5f8141c561cb57e4_normal.jpeg", "profile_image_url_https" : "https://pbs.twimg.com/profile_images/378800000254412405/e4adcf8fb7800c3e5f8141c561cb57e4_normal.jpeg", "lang" : "en" }, "resume" : { "loginTokens" : [ { "token" : "xxx", "when" : ISODate("2013-11-11T18:03:23.489Z") } ] } }, "profile" : { "name" : "Shekhar Gulati" } } >
Meteor建立的模板沒有遵循定義給Meteor程序佈局的最好體驗,epoll.js對客戶端和服務器共享,任何人均可以經過瀏覽器開發工具查看epoll.js.
不少時候咱們不想把客戶端和服務器端之間的全部東西都共享,好比若是咱們有些特定的服務器端的代碼,咱們不想Meteor發送給客戶端。用Meteor,咱們能夠用client和server目錄區分客戶端和服務器端,在epoll文件夾下建立client和server目錄。
$ cd epoll
$ mkdir client server
如今在client下建立epollclient.js, server下建立epollserver.js.
$ touch client/epollclient.js $ touch server/epollserver.js
把客戶端代碼從epoll.js移到client/epollclient.js.
Template.hello.greeting = function () { return "The Missing Meteor Tutorial!!!"; }; Template.hello.events({ 'click input' : function () { // template data, if any, is available in 'this' if (typeof console !== 'undefined') console.log("You pressed the button"); } });
一樣,移動服務器端代碼到server/epollserver.js
Meteor.startup(function () { // code to run on server at startup });
再刪除epoll.js文件。
$ rm -f epoll.js
全部的Meteor程序都安裝了一個特殊的包insecure, 這個包給客戶端權限去數據庫操做,這應該從程序裏移除,Meteor文檔一樣也建議移除它。
默認的,一個新meteor程序包含自動推送和不安全的包,他們共同使得客戶端對服務器端的數據庫有全部讀/寫權限。他們是頗有用的原型工具,但顯然對產品應用不合適。
要移除不安全的包,輸入如下命令。
$ meteor remove insecure
如今咱們來添加給登陸用戶提交新問題的功能。
<head> <title>Epoll : Share your opinion online, anywhere, anytime</title> </head> <body> <div class="navbar navbar-static-top navbar-inverse"> <div class="navbar-inner"> <div class="container"> <a class="brand" href="/">Epoll</a> <ul class="nav pull-right"> <li> {{loginButtons}} </li> </ul> </div> </div> </div> <div class="container" id="main"> {{#if currentUser}} {{> addquestion}} {{/if}} {{#unless currentUser}} {{> banner}} {{/unless}} </div> </body> <template name="banner"> <div class="container"> <div class="row"> <div class="span6"> <div class="well"> <h4>Sign in using Twitter to submit new questions or to vote on existing questions.</h4> {{loginButtons}} </div> </div> </div> </div> </template> <template name="addquestion"> <textarea rows="3" class="input-xxlarge" name="questionText" id="questionText" placeholder="Add Your Question"></textarea> <br/> <input type="button" class="btn-info add-question" value="Add Question"/> </template>
以上html只有在用戶已經登陸到應用後纔會加載addQuestion模板,若是退出應用,也不能看到新加問題的模塊。
要實現這個功能須要更新客戶端和服務器端代碼。
在client/epollclient.js添加以下代碼:
Template.addquestion.events({ 'click input.add-question' : function(event){ event.preventDefault(); var questionText = document.getElementById("questionText").value; Meteor.call("addQuestion",questionText,function(error , questionId){ console.log('added question with Id .. '+questionId); }); document.getElementById("questionText").value = ""; } });
以上代碼:
如今來添加服務端代碼,先定義個新的Questions集合接口,而後對他操做,Meteor用minimongo做爲API接口,要查看minimongo支持的全部操做,查看Meteor.Collection文檔。
Questions = new Meteor.Collection("questions"); Meteor.startup(function () { // code to run on server at startup }); Meteor.methods({ addQuestion : function(questionText){ console.log('Adding Question'); var questionId = Questions.insert({ 'questionText' : questionText, 'submittedOn': new Date(), 'submittedBy' : Meteor.userId() }); return questionId; } });
如今到程序用戶界面,提交新問題。
也能夠看MongoDB裏的數據。
> db.questions.find().pretty() { "questionText" : "Is Sachin Tendulkar the greatest batsman of all time?", "submittedOn" : ISODate("2013-11-11T18:23:02.541Z"), "submittedBy" : "Jnu6oXoAZ2um57rZ8", "_id" : "nhqvgDcZqgZgLdDB7" }
接下來要實現的功能是列出全部問題,沒有登陸應用的用戶一樣也應該看到全部的問題。
在主div下添加以下代碼。
{{> questions}}
而後,添加問題模板到epoll.html.
<template name="questions"> <h2>All Questions</h2> {{#each items}} {{> question}} {{/each}} </template> <template name="question"> <div> <p class="lead"> {{questionText}} <a class="btn btn-small btn-success yes {{#unless currentUser}}disabled{{/unless}}" href="#"><i class="icon-thumbs-up"></i> Yes {{yes}}</a> <a class="btn btn-small btn-danger no {{#unless currentUser}}disabled{{/unless}}" href="#"><i class="icon-thumbs-down"></i> No {{no}}</a> </p> </div> </template>
以上代碼很清晰,惟一須要提醒的是在問題模板裏的unless控制結構的用法,它確保了若是用戶沒有登陸,那就用disabled 類。
要獲得全部的問題,須要用客戶端的Questions集合接口來獲取全部文檔,在client/epollclient.js添加如下代碼:
Questions = new Meteor.Collection("questions"); Template.questions.items = function(){ return Questions.find({},{sort:{'submittedOn':-1}}); };
最後一個須要實現的功能是容許登陸的用戶投票,不須要對html作任何更改,由於都已經加到模板裏了。
在client/epollclient.js添加如下代碼:
Template.question.events({ 'click': function () { Session.set("selected_question", this._id); }, 'click a.yes' : function (event) { event.preventDefault(); if(Meteor.userId()){ var questionId = Session.get('selected_question'); console.log('updating yes count for questionId '+questionId); Meteor.call("incrementYesVotes",questionId); } }, 'click a.no': function(){ event.preventDefault(); if(Meteor.userId()){ var questionId = Session.get('selected_question'); console.log('updating no count for questionId '+questionId); Meteor.call("incrementNoVotes",questionId); } } });
以上代碼:
最後,在server/epollserver.js添加incrementYesVotes和incrementNoVotes, 用Meteor的collection更新功能來計算增長量。
incrementYesVotes : function(questionId){ console.log(questionId); Questions.update(questionId,{$inc : {'yes':1}}); }, incrementNoVotes : function(questionId){ console.log(questionId); Questions.update(questionId,{$inc : {'no':1}}); }
因此每次用戶點擊yes或者no時,count都會更新,你能夠經過http://localhost:3000試試應用。
有幾種方式能夠發佈Meteor應用,能夠發佈到Meteor提供的測試服務器上,也能夠到OpenShift上,要發佈到OpenShift上,請參考Ryan的博客。
要發佈到Meteor測試服務器上,運行如下命令:
$ meteor deploy epoll
這個應用運行在http://epoll.meteor.com/
這就是今天的內容,繼續給反饋吧。
原文:https://www.openshift.com/blogs/day-15-meteor-building-a-web-app-from-scratch-in-meteor