前言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