- Day 1: Bower - 管理你的客户端依赖关系
- Day 2: AngularJS - 对 AngularJS 的初步认识
- Day 3: Flask - 使用 Python 和 OpenShift 进行即时 Web 开发
- Day 4:PredictionIO - 如何创建一个博客推荐器
- Day 5: GruntJS - 重复乏味的工作总会有人做(反正我不做)
- Day 6:在 Java 虚拟机上使用 Grails 进行快速 Web 开发
- Day 7: GruntJS 在线重载 提升生产率至新境界
- Day 8: Harp.JS - 现代静态 web 服务器
- Day 9: TextBlob - 对文本进行情感分析
- Day 10: PhoneGap - 开发手机应用如此简单
- Day 11: AeroGear 推送服务器:使应用的通知推送变得简单
- Day 12: OpenCV - Java 开发者的人脸检测
- Day 13: Dropwizard - 非常棒的 Java REST 服务器栈
- Day14:使用斯坦福 NER 软件包实现你自己的命名实体识别器(Named Entity Recognition,NER)
- Day 15:Meteor - 从零开始创建一个 Web 应用
- Day 16: Goose Extractor - 好用的文章提取工具
- Day 17: 使用 JBoss Forge 和 OpenShift 构建部署 JAVA EE 6 应用
- Day 18: BoilerPipe - Java 开发者的文章提取工具
- Day 19: EmberJS 入门指南
- Day 20: 斯坦福 CoreNLP - 用 Java 给 Twitter 进行情感分析
- Day 21:Docker 入门教程
- Day 22: 使用 Spring、MongoDB 和 AngularJS 开发单页面应用
- Day 23:使用 TimelineJS 构建精美的时间轴
- Day 24: 使用 Yeoman 自动构建 Ember 项目
- Day 25: 联合 Tornado、MongoDB 和 AngularJS 进行应用开发
- Day 26: TogetherJS - 让我们一起来编程!
- Day 27: Restify - 在 Node.js 中构建正确的 REST Web 服务
- Day 28: OpenShift 的 Eclipse 集成
- Day 29:编写你的第一个 Google Chrome 扩展程序
- Day 30: Play Framework - Java 开发者的梦想框架
Day 15:Meteor - 从零开始创建一个 Web 应用
到目前为止我们讨论了 Bower 、 AngularJS 、 GruntJS 和 PhoneGap 等 JavaScript 技术。今天是 “30 天学习 30 种新技术” 挑战的第 15 天,我决定重返 JavaScript,学习 Meteor 框架。虽然 Meteor 的文档相当好,但是它缺少为初学者准备的教程。我觉得教程的学习效果更好,因为教程可以帮助你快速上手一种技术。本文将介绍如何利用 Meteor 框架构建一个 epoll 应用。
Meteor 是什么?
Meteor 是新一代的开发即时 web 应用的开源框架,它能帮助你在最少的时间内完成开发。它的理念和 AngularJS、BackboneJS 等框架大不相同。当我们在 backbone 和 angular 上工作时,客户端(Angular 或 Backbone)和 REST 后端通讯。我们可以用任何技术写 REST 后端,例如 Java、NodeJS、PHP。
Meteor 使用 DDP(分布式数据协议) 在客户端和服务器间传送数据。客户端 JavaScript 开发者需要解决的首要问题是:向后端的数据库发起查询,发送数据到客户端,当数据库变动时,推送变动到客户端。DDP 是解决这一问题的标准做法。
Meteor 应用的后端基于 Node 和 MongoDB。前端和后端的应用同时使用 Meteor 的 API。未来开发者可以选择 MongoDB 之外的其他数据库。
为什么使用 Meteor?
请阅读 Meteor 的七大原则 。
应用案例
本文中我们将搭建一个 epoll 应用,该应用允许用户发布问题并投票。这个应用可以做到:
- 当用户访问
/
时,会看到一个问题列表。用户需要通过 Twitter 登录,以便投票或发布新问题。如下图所示,由于未登录,投票按钮不可用。 - 当用户点击
Sign in with Twitter
之后,他将授权 epoll 应用使用他的账号。授权成功之后,用户可以投票或发布新问题。
GitHub 仓库
今天的示例应用的代码可以从 GitHub 取得。
安装 Meteor
开始使用 Meteor 很容易。如果你使用 Mac 或 Linux,只需输入如下命令:
curl https://install.meteor.com | /bin/sh
Windows 用户请参阅 文档
创建 Meteor 应用
创建 Meteor 应用很容易。安装之后,运行 create
命令即可。
meteor create epoll
这将创建 epoll 目录,该目录下有一些模板文件。项目结构如下所示:
让我们解释下这个结构:
- meteor 文件夹下保存 meteor 特定的文件。
.gitignore
忽略存储 MongoDB 数据库文件和应用文件的local
文件夹。packages
指明本应用所需的包。你可以把它们看成是 npm 包。Meteor 以包的形式提供功能。本文中会使用一些包。release
保存了 meteor 版本。本文使用的版本是0.6.6.3
。 epoll.css
决定应用的 CSS 样式。epoll.html
是应用的 HTML 标记。目前 meteor 只支持 handlebars 模板引擎,不过 未来可能支持其他模板引擎 。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.isServer
和 Meteor.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 add
和 meteor 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
。
如果我们不想将服务器端的特有代码发送到客户端,我们可以使用 client
和 server
目录来分隔代码。
cd epoll
mkdir client server
在两个目录下分别创建 epollclient.js
和 epollserver.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 = "";
}
});
以上代码中:
- 我们首先将点击
input
事件绑定到add-question
类。 - 接着我们阻止默认的点击事件,从 DOM 中获取问题文本。
- 然后我们调用 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);
}
}
});
上面的代码实现了:
- 绑定点击事件到问题模板。点击任意问题的时,在
session
中设置 questionId。 session 提供了一个客户端的全局对象,你可以在里面存储任意的键值对。 - 当用户点击 Yes 按钮时,我们会从
session
中取得选中的questionId
,然后在服务器端调用incrementYesVotes
方法。我们使用Meteor.userId()
来确保用户已经登录了。 - 当用户点击 No 按钮时,我们在服务器端调用
incrementNoVotes
函数。
最后我们在 server/epollserver.js
加入 incrementYesVotes
和 incrementNoVotes
函数。我们使用 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/ 访问。
今天就是这些了。欢迎继续反馈。
原文: Day 15: Meteor - Building a Web App From Scratch in Meteor
翻译整理: Segmentfault
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论