学了一段时间Meteor以后,着手作一个APP,关于时间管理的,取名 Next。css
Get things done , and do Nexthtml
同时,把开发过程尽量详细的记录下来,分享给有须要的同窗。前提是你有一些Meteor基础,至少要了解各类基础概念:集合、发布订阅、method、package等。git
若是以前没了解过Meteor,能够快速过一遍meteor教程github
Next 0.0.1版的目标是任务列表,四象限展现,能够新增、修改和删除任务。最后的效果以下图:(后面会慢慢提高她的颜值)shell
新建项目数据库
meteor create next
进入项目目录,并启动api
cd next meteor
打开浏览器,访问 http://localhost:3000,会看到自动生成的demo。浏览器
删除自动生成的文件,并创建项目目录结构app
rm next.css next.html next.js mkdir client public server lib
添加路由包iron:router
;因为后面会用coffeescript写,因此还要加上coffeescript
包框架
meteor add iron:router meteor add coffeescript
基本的骨架都有了,能够开始敲代码了。在client文件夹中新建router.coffee,内容以下:
Router.route('/', -> @render("Home") )
浏览器中显示了一条错误信息:找不到home模板
Couldn't find a template named "Home" or "home". Are you sure you defined it?
接下来定义home模板,在client文件夹中新建templates文件夹,在里面新建home.html,内容以下:
<template name="home"> welcome to home </template>
此时浏览器显示:
welcome to home
在lib文件夹中新建collections文件夹,在里边新建task.coffee,内容以下:
@Task = new Mongo.Collection('task')
Task collection就对应数据库里的一张表,根据需求,初步设计了下面几个字段:
name 任务名称 important 是否重要 urgent 是否紧急 complete 是否完成 create_time 建立时间 complete_time 完成时间
为了方便调试,要制造一些初始数据。在server文件夹下新建init_data.coffee
Meteor.startup(-> if Task.find().count() is 0 Task.insert name: "晚上和妹子去吃饭" important: true urgent: true Task.insert name: "翻译Meteor文档" important: true urgent: false Task.insert name: "看完《悲伤与理智》" important: false urgent: false Task.insert name: "给手机充话费" important: false urgent: true )
解释下上面的代码:每次启动Meteor的时候,查询任务条数,若是条数为零,则插入四条初始数据。
以后打开数据库看看是否插入成功,打开一个新的命令行窗口,切换到项目根目录:启动mongo shell
meteor mongo
查询任务条数:
db.task.find().count() 1
明明插入了四条,为何只查询到一条呢?由于在编码过程当中,Meteor会监测源码的变化并自动从新运行,当刚写完第一条插入语句,Meteor可能就从新运行了,此时任务条数为1,后面的插入就不会再执行了。
接下来须要control+c
中止Meteor进程,重置并重启
meteor reset meteor
再次到mongo shell中查询任务条数:
db.task.find().count() 4
能够经过Helper给模板增长动态数据,在templates文件夹中新建home.coffee,内容以下:
Template.home.helpers taskList: -> Task.find()
修改home.html
<template name="home"> {{#each taskList}} {{name}} {{/each}} </template>
浏览器显示
晚上和妹子去吃饭 翻译Meteor文档 看完《悲伤与理智》 给手机充话费
这里有一个问题须要思考:为何客户端没有进行任何请求,数据就从服务端到了客户端?
这是由于:为了简化开发,每一个新建的Meteor项目都会包含一个autopublish包,这个包会把全部集合里的文档自动发布到每个链接上的客户端。为了可以精确地控制文档的发布,须要移除autopublish,而后手动进行发布与订阅
meteor remove autopublish
此时浏览器中显示页面为空。接下来,在server目录下新建publish.coffee
Meteor.publish('tasks', -> Task.find() )
在client目录下新建subscribe.coffee
Meteor.subscribe('tasks')
这时候浏览器中的页面数据就又都回来了。
项目用到了yahoo的pure css框架:点我下载
在client文件夹下新建style文件夹,将pure-min.css放进去,而后再新建一个todo.css
将home.html 的布局修改成四象限
<template name="home"> <div class="pure-g main-container"> <div class="pure-u-1-2 task-list-wrapper task-list-wrapper-tl"> <div class="task-list-title"> 重要&紧急 </div> <ul class="task-list"></ul> </div> <div class="pure-u-1-2 task-list-wrapper task-list-wrapper-tr"> <div class="task-list-title"> 重要&不紧急 </div> <ul class="task-list"></ul> </div> <div class="pure-u-1-2 task-list-wrapper task-list-wrapper-bl"> <div class="task-list-title"> 不重要&紧急 </div> <ul class="task-list"></ul> </div> <div class="pure-u-1-2 task-list-wrapper task-list-wrapper-br"> <div class="task-list-title"> 不重要&不紧急 </div> <ul class="task-list"></ul> </div> </div> </template>
在todo.css 里增长样式
html, body { height: 100%; } .main-container { height: 100%; } .task-list-wrapper { height: 50%; } .task-list-wrapper-tl { background-color: #ffaeae; } .task-list-wrapper-tr { background-color: #56baec; } .task-list-wrapper-bl { background-color: #ffec94; } .task-list-wrapper-br { background-color: #b4d8e7; }
接下来修改home模板的Helper
Template.home.helpers taskListTL: -> Task.find({important: true, urgent: true}) taskListTR: -> Task.find({important: true, urgent: false}) taskListBL: -> Task.find({important: false, urgent: true}) taskListBR: -> Task.find({important: false, urgent: false})
修改home.html,将对应的Helper展现到对应的板块,例如:
<div class="pure-u-1-2 task-list-wrapper task-list-wrapper-tl"> <div class="task-list-title"> 重要&紧急 </div> <ul class="task-list"> {{#each taskListTL}} <li>{{name}}</li> {{/each}} </ul> </div>
此时效果以下图:
修改home.html,给每一个版块增长一个form表单,用于新增任务
<div class="pure-u-1-2 task-list-wrapper task-list-wrapper-tl"> <div class="task-list-title"> 重要&紧急 </div> <form class="pure-form form-create-task"> <input class="hidden" type="text" name="type" value="tl"/> <input class="pure-input-1" name="name" type="text"/> <button class="hidden" type="submit"></button> </form> <ul class="task-list"> {{#each taskListTL}} <li>{{name}}</li> {{/each}} </ul> </div>
表单里有一个隐藏的输入框,用于标识任务的类别,分别是:tl
,tr
,bl
,br
。
接下来,须要让模板监听表单的提交事件,并作处理。
在home.coffee 中增长:
Template.home.events 'submit .form-create-task': (e)-> e.preventDefault() $form = $(e.currentTarget) task = name: $form.find('input[name=name]').val() create_time: new Date() important: false urgent: false type = $form.find('input[name=type]').val() switch type when 'tl' task.important = true task.urgent = true when 'tr' then task.important = true when 'bl' then task.urgent = true console.log task Task.insert(task) $form.find('input[name=name]').val('')
首先阻止表单的默认提交,而后从表单中提取所需值,构建一个task
对象,经过Task.insert()
插入到数据库,而后清空表单。
在浏览器中测试没有问题,新增任务的功能就完成了。
修改home.html,修改任务列表为:
<ul class="task-list"> {{#each taskListTL}} <li class="task-item" data-task-id="{{_id}}"> <div class="task-name" contenteditable="true">{{name}}</div> </li> {{/each}} </ul>
修改home.coffee,监听.task-name
上的回车事件:
'keypress .task-name': (e)-> $el = $(e.currentTarget) taskId = $el.parent().attr('data-task-id') if e.keyCode is 13 taskName = $el.text() Task.update({_id: taskId}, {$set: {name: taskName}}) $el.blur() e.preventDefault()
浏览器中测试经过。
修改home.html,修改任务列表为:
<ul class="task-list"> {{#each taskListTL}} <li class="task-item" data-task-id="{{_id}}"> <div class="task-name" contenteditable="true">{{name}}</div> <span>×</span> </li> {{/each}} </ul>
修改todo.css,调整样式:
.task-item { position: relative; line-height: 25px; } .delete-task { position: absolute; top: 0px; right: 10px; cursor: pointer; } .delete-task:hover { color: #dd3023; }
修改home.coffee,绑定删除按钮的点击事件:
'click .delete-task': (e)-> $el = $(e.currentTarget) taskId = $el.parent().attr('data-task-id') Task.remove({_id: taskId})
至此,Next 0.0.1 版本的需求就基本完成了。就是样式丑了些,先不要在乎这些细节啦。后面再优化喽。
原文地址:http://zicai.github.io/lessons/2015/06/22/meteor-in-action-next-0.0.1/