Nodejs完成一个待办事项的实例教程
发布于 9 年前 作者 yangfanacc 17498 次浏览 最后一次编辑是 8 年前 来自 分享

这是一个用Node完成的待办事项的Demo,支持手机端和PC浏览器端同时查看。下载地址:https://github.com/yangfanacc/Todo 在线查看效果可以访问这个网址:http://123.56.44.245:3460 效果图如下: xiaoguotu.png 首先介绍一个这个待办事项示例项目的搭建环境:

1.Nodejs版本:v0.10.35
2.Mongodb(使用Mongoose连接Mongodb数据库)
3.前台使用了国内比较好用的开源框架[Amaze](http://amazeui.org/)

项目的结构二级截图如下: 2.png 项目思路 首先,需要一个网址可以用来访问我们的待办事项首页(对数据库的读操作)。然后我们需要有添加和删除待办事项的对数据库的增加和删除(更新)操作。其实,也就这么多了,很简单的是不是?不过这里我们可不是真的删除,因为我们有可能需要保存我们的待办事项历史,大家可以访问这个网址:http://123.56.44.245:3460/all 是的,我们在删除待办事项的时候,是需要一个bool参数在数据库中,只是把数据变为false不在读取,而不是真的删除。这和我们使用腾讯的QQ空间是一样的效果嘛,哈哈:)

第一步 我们需要确定使用那些类库,我们这里使用的类库如下:

1.body-parser  
2.cookie-parser  
3.debug  
4.ejs  
5.express  
6.mongoose  
7.morgan  
8.serve-favicon

大家也看到了,除了第6个是我自己加的以外,其他的都是我们在使用express -e TodoList这个express模板的使用express所需要的。我们我们只是需要添加这个mongoose模块就好了cnpm install mongoose --save。如果上面的添加mongoose模块中的cnpm和–save你还不知道是什么意思,建议你去google一下喽.

第二步 从上面我们可以看到,我们使用的是ejs模板。但是在使用ejs的时候,我很不习惯加上ejs这个后缀,我知道不止我一个人有这样的爱好:)。所以这里我们开始将ejs转换为html的后缀使用。方法大家可以去Google一下,这里贴出了:

var ejs = require('ejs');
app.engine('html', ejs.__express);
app.set('view engine', 'html');

修改app.js文件中的相关代码就可以了:) 然后,就是确定我们需要用到几个html页面了。其实就是上面的网址我们看到的,一个是主页面,还有一个是历史查看页面。这两个页面的差别真的不大啦,其实是可以用一个页面来完成的,但是这里我用的两个页面用一个页面会更方便,我这里当时没有想到。 3.png 然后就是我们需要一个前端的框架,那就是前文提到的Amaze,还不会使用的小伙伴们可以去官网使用一下,很简单的,用一下就会了。 4.png 上面的assets文件夹里面的就是Amaze所必须的相关文件,我们放到public文件夹就好了,这个静态文件目录我们是可以直接读取到的。 之后我们就可以在html页面使用前端的框架了。 index.html文件代码如下:

<!doctype html>
<html class=“no-js”>
<head>
<meta charset=“utf-8”> <meta http-equiv=“X-UA-Compatible” content=“IE=edge”> <meta name=“description” content=""> <meta name=“keywords” content=""> <meta name="viewport" content=“width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no”> <title>随时记事</title>

<!-- Set render engine for 360 browser --> <meta name=“renderer” content=“webkit”>

<!-- No Baidu Siteapp–> <meta http-equiv=“Cache-Control” content=“no-siteapp”/>

<link rel=“icon” type=“image/png” href=“assets/i/favicon.png”>

<!-- Add to homescreen for Chrome on Android --> <meta name=“mobile-web-app-capable” content=“yes”> <link rel=“icon” sizes=“192x192” href=“assets/i/app-icon72x72@2x.png”>

<!-- Add to homescreen for Safari on iOS --> <meta name=“apple-mobile-web-app-capable” content=“yes”> <meta name=“apple-mobile-web-app-status-bar-style” content=“black”> <meta name=“apple-mobile-web-app-title” content=“Amaze UI”/> <link rel=“apple-touch-icon-precomposed” href=“assets/i/app-icon72x72@2x.png”>

<!-- Tile icon for Win8 (144x144 + tile color) --> <meta name=“msapplication-TileImage” content=“assets/i/app-icon72x72@2x.png”> <meta name=“msapplication-TileColor” content="#0e90d2">

<link rel=“stylesheet” href=“assets/css/amazeui.min.css”> <link rel=“stylesheet” href=“assets/css/app.css”> </head>
<body>

<header data-am-widget=“header” class=“am-header am-header-default”>
<h1 class=“am-header-title”> <a href="#title-link" class="">For Adron</a> </h1> </header>

<!–在这里编写你的代码–>
<ul id=“contentUl” class=“am-list am-list-static am-list-border am-list-striped”>
<% allContent.forEach(function(todo, index){ %> <li ><%= todo.content %> <button onclick=“deleteContent(’<%= todo.id %>’, this)” style=“float:right;” type=“button” class=“am-close”>×</button></li> <% }) %> </ul>
<div class=“am-u-lg-6”>
<div class=“am-input-group”> <input id=“content” type=“text” class=“am-form-field”> <span class=“am-input-group-btn”> <button class=“am-btn am-btn-default” type=“button” onclick=“addContent()”>添加</button> </span> </div> </div>

<script>
var xmlhttp; if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// code for IE6, IE5 xmlhttp=new ActiveXObject(“Microsoft.XMLHTTP”); } function addContent() { // var content = document.getElementById(“content”).value; var content = $("#content").val(); xmlhttp.open(“GET”,"/add?content="+content,false); xmlhttp.send(); if (xmlhttp.status == 200) { var contentUl=document.getElementById(‘contentUl’); var li = document.createElement(“li”); var id = “’” + xmlhttp.responseText + “’”; var onclickStr = ‘<button onclick="deleteContent(’ + id + ', this)" style=“float:right;” type=“button” class=“am-close”>×</button>' li.innerHTML = content + onclickStr; contentUl.insertBefore(li,contentUl.childNodes[0]); $("#content").val(""); } }

function deleteContent(id, obj) {
    $(obj).parent().remove();
    xmlhttp.open("GET","/delete?id="+id,true);
    xmlhttp.send();
    if (xmlhttp.status == 200) {
    }
}

</script>

<!–[if (gte IE 9)|!(IE)]><!–>
<script src=“assets/js/jquery.min.js”></script>
<script src=“assets/js/amazeui.min.js”></script>
<!–<![endif]–>
<!–[if lte IE 8 ]>
<script src=“http://libs.baidu.com/jquery/1.11.1/jquery.min.js”></script>
<![endif]–>
</body>
</html>
大家可以先看开头和结尾,使用了css和js的部分,其他的后面会说:)

对数据库的增删读改操作 对数据库的操作文件如下图: 5.png 我们mkdir models文件夹 首先,我们建立一个对数据库的文件配置操作:mongodb.js

var mongoose = require(‘mongoose’);
mongoose.connect(‘mongodb://127.0.0.1/MorePersonTodo’);
exports.mongoose = mongoose;
这里我们配置了数据库的名称MorePersonTodo。当然,对如何使用mongoose还不熟悉的朋友们,建议Google一下相关的使用方法。 Todo.js文件就是具体的操作了,代码如下:

[yangfan-23:37-~/TodoForMorePerson/models-49]cat Todo.js var mongodb = require(’./mongodb.js’);
var Schema = mongodb.mongoose.Schema;
var TodoSchema = new Schema({
content: String, show: Boolean }); var TodoModel = mongodb.mongoose.model(“Todo”, TodoSchema);

function Todo(content, show) {
this.content = content; this.show = show; };

Todo.prototype.save = function(todo, callback) {
var todo = { content: todo.content, show: todo.show };

var newTodo = new TodoModel(todo);

newTodo.save(function (err, todo) { if (err) { return callback(err); } callback(null, todo); }); };

Todo.prototype.get = function(callback) {
TodoModel.find({‘show’:true}, function (err, todos) { if (err) { return callback(err); } callback(null, todos); }); };

Todo.prototype.getAll = function(callback) {
TodoModel.find(function (err, todos) { if (err) { return callback(err); } callback(null, todos); }); };

Todo.prototype.delete = function(id, callback) {
TodoModel.update({’_id’:id}, {‘show’:false}, function(err) { if (err) { return callback(err); } callback(null); }); };

module.exports = Todo;
详细说明如下: 首先我们建立了一个Schema和Model

var mongodb = require(’./mongodb.js’);
var Schema = mongodb.mongoose.Schema;
var TodoSchema = new Schema({
content: String, show: Boolean }); var TodoModel = mongodb.mongoose.model(“Todo”, TodoSchema);

function Todo(content, show) {
this.content = content; this.show = show; }; 然后是写入操作:

Todo.prototype.save = function(todo, callback) {
var todo = { content: todo.content, show: todo.show };

var newTodo = new TodoModel(todo);

newTodo.save(function (err, todo) { if (err) { return callback(err); } callback(null, todo); }); }; 然后是查询操作:

Todo.prototype.get = function(callback) {
TodoModel.find({‘show’:true}, function (err, todos) { if (err) { return callback(err); } callback(null, todos); }); }; 注意这里我们添加了查询条件是{‘show’:true}我们查询的是标志位true的记录。 然后是得到所有操作,这里我们可以看到历史记录:

Todo.prototype.getAll = function(callback) {
TodoModel.find(function (err, todos) { if (err) { return callback(err); } callback(null, todos); }); }; 然后就是我们的删除记录操作,当然我们是修改show的参数,而不是真的删除:

Todo.prototype.delete = function(id, callback) {
TodoModel.update({’_id’:id}, {‘show’:false}, function(err) { if (err) { return callback(err); } callback(null); }); }; 最后,我们把整个Todo导出供其他js文件调用:

module.exports = Todo;
这样,我们的对数据库的操作就完成了:)

路由转发 下面,我们就开始对我们在不同操作下,路由的转发以对数据库进行不同条件下的操作了。 我们的代码在routes/index.js文件中:

[yangfan-23:46-~/TodoForMorePerson/routes-55]cat index.js var express = require(‘express’);
var Todo = require("…/models/Todo.js");
var router = express.Router();

/* GET home page. */ router.get(’/’, function(req, res) {
var todo = new Todo(); todo.get(function(err, todoBack){ res.render(‘index’, { allContent: todoBack.reverse() }); }); });

router.get(’/add’, function(req, res) {
var content = req.query.content; var todo = new Todo(content, true); todo.save(todo, function(err, todoBack){ if (err) { res.writeHead(500); } else { res.writeHead(200); } res.write(todoBack.id); res.end(); }); });

router.get(’/delete’, function(req, res) {
var id = req.query.id; var todo = new Todo(); todo.delete(id, function(err){ if (err) { res.writeHead(500); } else { res.writeHead(200); } res.end(); }); });

router.get(’/all’, function(req, res) {
var todo = new Todo(); todo.getAll(function(err, todoBack){ res.render(‘all’, { allContent: todoBack.reverse() }); }); });

module.exports = router;
这里我就不详细说明了,我想大家看到代码的意思就是懂得了:)

Ajax的使用 我们知道,Ajax是划时代的产物,通过javascript实现这个不刷新网页就可以更新页面的技术真的很好。 1.获取到我们需要的待办事项到我们的主页面中: index.js:

/* GET home page. */ router.get(’/’, function(req, res) {
var todo = new Todo(); todo.get(function(err, todoBack){ res.render(‘index’, { allContent: todoBack.reverse() }); }); }); index.html:

<ul id=“contentUl” class=“am-list am-list-static am-list-border am-list-striped”>
<% allContent.forEach(function(todo, index){ %> <li ><%= todo.content %> <button onclick=“deleteContent(’<%= todo.id %>’, this)” style=“float:right;” type=“button” class=“am-close”>×</button></li> <% }) %> </ul>
这样我们就将所有的结果输出到页面了。大家可能注意到<button>xxx</button>这个位置的代码了,我们下面会说。 2.增加我们的待办事项 index.js:

router.get(’/add’, function(req, res) {
var content = req.query.content; var todo = new Todo(content, true); todo.save(todo, function(err, todoBack){ if (err) { res.writeHead(500); } else { res.writeHead(200); } res.write(todoBack.id); res.end(); }); }); index.html:

<script>
var xmlhttp; if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// code for IE6, IE5 xmlhttp=new ActiveXObject(“Microsoft.XMLHTTP”); } function addContent() { // var content = document.getElementById(“content”).value; var content = $("#content").val(); xmlhttp.open(“GET”,"/add?content="+content,false); xmlhttp.send(); if (xmlhttp.status == 200) { var contentUl=document.getElementById(‘contentUl’); var li = document.createElement(“li”); var id = “’” + xmlhttp.responseText + “’”; var onclickStr = ‘<button onclick="deleteContent(’ + id + ', this)" style=“float:right;” type=“button” class=“am-close”>×</button>' li.innerHTML = content + onclickStr; contentUl.insertBefore(li,contentUl.childNodes[0]); $("#content").val(""); } }

function deleteContent(id, obj) {
    $(obj).parent().remove();
    xmlhttp.open("GET","/delete?id="+id,true);
    xmlhttp.send();
    if (xmlhttp.status == 200) {
    }
}

</script>
我们使用了Ajax。当我们点击“添加”按钮的使用,就触发了javascript中“addContent”函数。这里不对如何使用Ajax进行介绍,如果您还不会,还是Google的说。这里需要注意的是,如果我们添加成功的话,会返回200,这时我们已经获取到添加事项在数据库中的唯一id。我们把这个id放在button中,是为了在删除这个事项的时候唯一确定该事项使用的。 然后,我们通过javascript代码:

var contentUl=document.getElementById(‘contentUl’);
var li = document.createElement(“li”); var id = “’” + xmlhttp.responseText + “’”; var onclickStr = ‘<button onclick="deleteContent(’ + id + ', this)" style=“float:right;” type=“button” class=“am-close”>×</button>' li.innerHTML = content + onclickStr; contentUl.insertBefore(li,contentUl.childNodes[0]); 把这条记录放置在li列表的第一个位置:) 3.删除一条事项记录 index.js:

router.get(’/delete’, function(req, res) {
var id = req.query.id; var todo = new Todo(); todo.delete(id, function(err){ if (err) { res.writeHead(500); } else { res.writeHead(200); } res.end(); }); }); index.html:

function deleteContent(id, obj) {
    $(obj).parent().remove();
    xmlhttp.open("GET","/delete?id="+id,true);
    xmlhttp.send();
    if (xmlhttp.status == 200) {
    }
}

我们还是使用Ajax,我们为了速度,是先把这条已经已经li删除了$(obj).parent().remove();:),然后开始执行数据库操作。注意我们删除只是把show参数变为false以不在读取,不是真的删除。 4.读取所有历史记录: index.js

router.get(’/all’, function(req, res) {
var todo = new Todo(); todo.getAll(function(err, todoBack){ res.render(‘all’, { allContent: todoBack.reverse() }); }); }); 我们访问xxxx/all就可以看到所有的历史记录了:) 代码下载地址:https://github.com/yangfanacc/Todo 这里谢谢大家给个星星(Star)哦 :)

1 回复

这里代码排版还是比较乱,是我黏贴的问题,大家可以看这个:http://www.livyfeel.com/nodejsfortodo/或者:http://blog.csdn.net/yangfanacc/article/details/43386465

回到顶部