[譯] 第十五天:Meteor - 用Meteor的Scratch開發Web App

前言css

目前爲止,這個系列咱們討論了Bower, AngularJS, GruntJSPhoneGap JavaScript技術。今天,決定回到JavaScript上學習一個叫Meteor的框架。雖然Meteor有很好的介紹文檔,不過沒有入門指導,我更傾向入門指導由於可讓咱們快速開始一項技術。這篇博客,咱們來學習怎樣用Meteor框架開發一個投票程序。html

Meteor是什麼?

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程序基於NodeMongoDB, 客戶端和服務器端的程序都用Meteor API開發,之後,開發者能夠有除了MongoDB以外的其餘數據庫選擇。 web

爲何學習Meteor?

若是你想說服本身爲何要學Meteor, 看看這七條核心準則 mongodb

程序用例

這篇博客,咱們來開發一個投票程序,容許用戶對問題發表和投票,程序能夠作如下事:shell

  1. 當用戶到程序的'/' url,他能夠看到問題列表。用戶用Twitter登陸後能夠提新問題或者對已有問題投票,以下圖所示,咱們能夠看到YesNo按鈕是不能使用的,由於用戶沒有登陸。

           

  1. 用戶點擊Sign in with Twitter,他就有權限使用投票程序,受權後,用戶能夠新加投票問題或者對現有問題投票。

           

  1. 最後,用戶能夠新增問題或者投票現有問題。

Github倉庫

今天的demo放在github: day15-epoll-meteor-demo.數據庫

安裝Meteor

Meteor很容易上手,若是你用的Mac或者Linux,打開終端輸入如下命令。npm

$ curl https://install.meteor.com | /bin/sh

 

Windows用戶,請參照文檔 編程

建立Meteor程序

建立Meteor程序很簡單,裝好Meteor後,只需運行建立命令。

$ meteor create epoll

 

它會在你機器上建立一個epoll的目錄,再放一些模板文件,項目結構如圖。

咱們來一個個看看這些文件:

  1. .meteor文件夾用來存放 meteor指定文件,它還包含了一個.gitignore文件夾用來忽視本地文件夾,本地文件夾存放MongoDB數據庫文件和程序編譯文件。.meteor下的packages文件指定了程序所用的全部包,你能夠想象成npm包,Meteor提供一些功能如包,咱們在後面會用到幾個包。release文件提供meteor版本,這裏,咱們用的最新版本0.6.6.3.
  2. Epoll.css用來指定程序的CSS樣式。
  3. Epoll.html是程序的HTML語言,Meteor框架當前使用handlebars最爲默認模板引擎,根據文檔介紹,meteor之後可能也會支持其餘模板引擎。
  4. Epoll.jsmeteor程序的核心,epoll.js      JavaScript文件在服務器和客戶端都有部署,這使得開發者只需對功能編程一次就能夠在服務器和客戶端都運行。meteor建立的epoll.js模板以下:
    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
      });
    }
View Code

           以上代碼中,Meteor.isServerMeteor.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!!!";
             };
View Code

改動會自動更新而後加載頁面。

MongoDB在哪?

以前提到過,MeteorMongoDB存儲數據,當咱們裝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
View Code

 

在我機器上,MongoDB運行在端口3002, 這避免了已有的MongoDB的默認端口27017, 數據庫目錄指向程序目錄的.meteor文件夾。

Meteor智能包

前面提到Meteor以包的形式實現功能,這些包在瀏覽器和服務器上都能工做,要查看Meteor支持的全部包,運行如下命令:

$ meteor list

 

添加包用Meteor add移除用meteor remove.

添加Twittter Bootstrap

咱們用Twitter Bootstrap顯示頁面格式,要添加Bootstrap,輸入如下命令。

$ meteor add bootstrap

 

Twitter Bootrap包僅有的提示是這個不是最新版本,Meteor包支持的版本是2.3.2.

添加Twitter Authentication

在這個投票應用中咱們用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>
View Code

同時在epoll.css添加格式。

/* CSS declarations go here */
.login-display-name{color: white }
.login-button{background-color: white}
 #main {
    padding-top:20px;
}
View Code

程序會自動更新,你能夠看到如圖頁面:

點擊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"
    }
}

> 
View Code

定義程序佈局

Meteor建立的模板沒有遵循定義給Meteor程序佈局的最好體驗,epoll.js對客戶端和服務器共享,任何人均可以經過瀏覽器開發工具查看epoll.js. 

 

不少時候咱們不想把客戶端和服務器端之間的全部東西都共享,好比若是咱們有些特定的服務器端的代碼,咱們不想Meteor發送給客戶端。用Meteor,咱們能夠用clientserver目錄區分客戶端和服務器端,在epoll文件夾下建立clientserver目錄。

$ 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");
    }
});
View Code

 

一樣,移動服務器端代碼到server/epollserver.js

Meteor.startup(function () {
    // code to run on server at startup
 });
View Code

 

再刪除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>
View Code

 

以上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 = "";
 
    }
});
View Code

 

以上代碼:

  1. 首先綁定點擊事件到'add-question'類的輸入類型。
  2. 而後組織默認點擊事件,從dom得到問題。
  3. 接下來調用Meteor服務端addQuestion方法,服務器會對數據的任意危險操做如增刪改給出響應,客戶端不會看到這些實現,也不能私自更改數據,服務器來作全部的操做。 

 

如今來添加服務端代碼,先定義個新的Questions集合接口,而後對他操做,Meteorminimongo做爲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;
  }
});
View Code

 

如今到程序用戶界面,提交新問題。

也能夠看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"
}
View Code

列出全部問題

接下來要實現的功能是列出全部問題,沒有登陸應用的用戶一樣也應該看到全部的問題。 

 

在主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>
View Code

 

以上代碼很清晰,惟一須要提醒的是在問題模板裏的unless控制結構的用法,它確保了若是用戶沒有登陸,那就用disabled 類。 

 

要獲得全部的問題,須要用客戶端的Questions集合接口來獲取全部文檔,在client/epollclient.js添加如下代碼:

Questions = new Meteor.Collection("questions");
 
Template.questions.items = function(){
    return Questions.find({},{sort:{'submittedOn':-1}});
};
View Code

實現投票

最後一個須要實現的功能是容許登陸的用戶投票,不須要對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);
      }
    }
 });
View Code

 

以上代碼:

  1. 綁定點擊事件到問題模板,當咱們點擊任何問題時,它都會在會話裏設置questionId, 會話(session)在客戶端提供一個全局對象,使得你能夠用來存儲任意一對kay-value值。
  2. 用戶點擊'Yes'標籤後,咱們能夠從會話裏得到選擇的questionId, 而後從服務器調用incrementYesVotes方法,一樣也會用Meteor.userId()方法檢查用戶應該在投票計算前登陸應用。
  3. 當用戶點擊'No'標籤後,從服務端調用incrementNoVotes方法。 

 

最後,在server/epollserver.js添加incrementYesVotesincrementNoVotes, Meteorcollection更新功能來計算增長量。

incrementYesVotes : function(questionId){
    console.log(questionId);
    Questions.update(questionId,{$inc : {'yes':1}});
  },
 
incrementNoVotes : function(questionId){
    console.log(questionId);
    Questions.update(questionId,{$inc : {'no':1}});
}
View Code

 

因此每次用戶點擊yes或者no時,count都會更新,你能夠經過http://localhost:3000試試應用。

發佈Meteor應用

有幾種方式能夠發佈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

相關文章
相關標籤/搜索