《30天学习30种新技术》-Day 15:Meteor —— 从零开始建立一个 Web 应用

目录:https://segmentfault.com/a/1190000000349384javascript

原文: https://segmentfault.com/a/1190000000361440css

到目前为止咱们讨论了BowerAngularJSGruntJSPhoneGap等JavaScript技术。今天是“30天学习30种新技术”挑战的第15天,我决定重返JavaScript,学习Meteor框架。虽然Meteor的文档至关好,可是它缺乏为初学者准备的教程。我以为教程的学习效果更好,由于教程能够帮助你快速上手一种技术。本文将介绍如何利用 Meteor 框架构建一个epoll应用。
html

Meteor是什么?

Meteor是新一代的开发即时web应用的开源框架,它能帮助你在最少的时间内完成开发。它的理念和AngularJS、BackboneJS等框架大不相同。当咱们在backbone 和 angular 上工做时,客户端(Angular或Backbone)和REST后端通信。咱们能够用任何技术写 REST 后端,例如 Java、NodeJS、PHP。前端

Meteor使用DDP(分布式数据协议)在客户端和服务器间传送数据。客户端JavaScript开发者须要解决的首要问题是:向后端的数据库发起查询,发送数据到客户端,当数据库变更时,推送变更到客户端。DDP是解决这一问题的标准作法。java

Meteor应用的后端基于Node和MongoDB。前端和后端的应用同时使用Meteor的API。将来开发者能够选择 MongoDB 以外的其余数据库。nginx

为何使用Meteor?

请阅读Meteor的七大原则git

应用案例

本文中咱们将搭建一个 epoll 应用,该应用容许用户发布问题并投票。这个应用能够作到:github

  • 当用户访问/时,会看到一个问题列表。用户须要经过Twitter登陆,以便投票或发布新问题。以下图所示,因为未登陆,投票按钮不可用。
    web

  • 当用户点击Sign in with Twitter以后,他将受权 epoll 应用使用他的帐号。受权成功以后,用户能够投票或发布新问题。
    sql

GitHub仓库

今天的示例应用的代码能够从GitHub取得。

安装Meteor

开始使用Meteor很容易。若是你使用Mac或Linux,只需输入以下命令:

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

Windows用户请参阅文档

建立Meteor应用

建立Meteor应用很容易。安装以后,运行create命令便可。

meteor create epoll 

这将建立epoll目录,该目录下有一些模板文件。项目结构以下所示:

让咱们解释下这个结构:

  1. meteor文件夹下保存meteor特定的文件。.gitignore忽略存储MongoDB数据库文件和应用文件的local文件夹。packages指明本应用所需的包。你能够把它们当作是npm包。Meteor以包的形式提供功能。本文中会使用一些包。release保存了meteor版本。本文使用的版本是0.6.6.3

  2. epoll.css决定应用的CSS样式。

  3. epoll.html是应用的HTML标记。目前meteor只支持handlebars模板引擎,不过将来可能支持其余模板引擎

  4. epoll.js是meteor应用的核心。epoll.js同时部署在服务器段和客户端。这容许开发者一次编写、两端使用。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 }); } 

Meteor.isServerMeteor.isClient区分了服务器端和客户端的代码。

meteor命令能够运行应用:

cd epoll meteor 

能够经过 http://localhost:3000 访问应用。点击按钮后,在chrome developer tools中你能够看到You pressed the button.信息。

修改epoll.js的欢迎部分:

Template.hello.greeting = function () { return "The Missing Meteor Tutorial!!!"; }; 

变更会自动应用,页面也会自动刷新。

MongoDB在哪?

前面提到Meteor使用MongoDB来存储数据。当咱们安装meteor的时候,它同时会下载最新版的MongoDB。咱们能够看到,MongoDB安装在<user.home>/.meteor目录。使用ps -ef能够找到MongoDB的安装位置。

; 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端口,以免和其余默认运行于27017端口的MongoDB冲突。

智能的Meteor包管理

前面提到Meteor以包的形式实现功能。这些包在浏览器和服务器上都能使用。运行如下命令能够得知Meteor支持的全部包:

meteor list 

使用meteor addmeteor remove命令来添加删除包。

添加Twitter Bootstrap包

咱们将使用Twitter Bootstrap做为用户界面的风格。

meteor add bootstrap 

注意,Meteor包不必定是最新版。

添加Twitter受权包

在咱们的应用中,用户须要首先经过Twitter受权才能投票或添加问题。Meteor提供了accounts-ui包,能够为咱们的应用添加登陆组件:

meteor add accounts-ui 

而后咱们添加受权提供者。在这个应用中,咱们使用Twitter,不过咱们其实也可使用facebook、github、google、weibo或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登陆了。

受权以后咱们能够登陆应用。使用完毕以后,咱们能够登出。

MongoDB会在用户集合内建立新用户。咱们可使用mongo命令链接数据库查看:

; ~/.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建立的模板应用有一个问题,客户端和服务器段的epoll.js代码是同样的。任何人的均可以使用浏览器的开发工具查看epoll.js

若是咱们不想将服务器端的特有代码发送到客户端,咱们可使用clientserver目录来分隔代码。

cd epoll mkdir client server 

在两个目录下分别建立epollclient.jsepollserver.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`: ```sh rm -f epoll.js 

移除insecure

每个Meteor应用预装了insecure包。这个应用让用户端能够在数据库上实施一切操做。对于原型开发这颇有用,可是一般不适合生产环境。

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> 

仅当用户登陆的时候才会渲染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 = ""; } }); 

以上代码中:

  1. 咱们首先将点击input事件绑定到add-question类。

  2. 接着咱们阻止默认的点击事件,从DOM中获取问题文本。

  3. 而后咱们调用Meteor服务器的方法addQuestion。由服务器负责插入、更新、删除数据等有风险的操做。客户端看不到实现,也没法私自修改数据。

如今咱们须要修改server/epollserver.js。咱们首先定义一个名为Questions的新集合。而后咱们会操做这个集合。Meteor使用minimongo做为API接口。参阅Meteor.Collection.documentation查看minimongo支持的全部操做。

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

问题列表

咱们接下来要实现的功能是问题列表。用户不需登陆,就能够看到全部问题的列表。

main div中加入:

{{> questions}}

而后添加问题模板:

<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 css。

为了获取全部问题,咱们须要在客户端使用Question集合来获取全部文本。在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); } } }); 

上面的代码实现了:

  1. 绑定点击事件到问题模板。点击任意问题的时,在session中设置questionId。session提供了一个客户端的全局对象,你能够在里面存储任意的键值对。

  2. 当用户点击Yes按钮时,咱们会从session中取得选中的questionId,而后在服务器端调用incrementYesVotes方法。咱们使用Meteor.userId()来确保用户已经登陆了。

  3. 当用户点击No按钮时,咱们在服务器端调用incrementNoVotes函数。

最后咱们在server/epollserver.js加入incrementYesVotesincrementNoVotes函数。咱们使用Meteor的集合更新功能来增长计数器。

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按钮以后,计数器会更新。你能够访问 http://localhost:3000 试验一番。

部署Meteor应用

部署Meteor应用有不少种方法。咱们能够在Meteor提供的测试服务器上部署,也能够部署到OpenShift。

若是你打算部署到OpenShift上,请参阅Ryan这篇博客

运行如下命令能够部署到Meteor测试服务器:

meteor deploy epoll 

应用能够经过 http://epoll.meteor.com/ 访问。

今天就是这些了。欢迎继续反馈。

相关文章
相关标签/搜索