首页 > 代码库 > Nodejs完成一个待办事项的实例教程

Nodejs完成一个待办事项的实例教程

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

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

项目的结构二级截图如下:技术分享

项目思路

首先,需要一个网址可以用来访问我们的待办事项首页(对数据库的读操作)。然后我们需要有添加和删除待办事项的对数据库的增加和删除(更新)操作。其实,也就这么多了,很简单的是不是?不过这里我们可不是真的删除,因为我们有可能需要保存我们的待办事项历史,大家可以访问这个网址: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页面了。其实就是上面的网址我们看到的,一个是主页面,还有一个是历史查看页面。这两个页面的差别真的不大啦,其实是可以用一个页面来完成的,但是这里我用的两个页面用一个页面会更方便,我这里当时没有想到。技术分享然后就是我们需要一个前端的框架,那就是前文提到的Amaze,还不会使用的小伙伴们可以去官网使用一下,很简单的,用一下就会了。技术分享上面的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">&times;</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">&times;</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://www.mamicode.com/"http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>  >  
</body>  
</html>  

大家可以先看开头和结尾,使用了css和js的部分,其他的后面会说:)

对数据库的增删读改操作

对数据库的操作文件如下图:技术分享我们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">&times;</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">&times;</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">&times;</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)哦 :)

Nodejs完成一个待办事项的实例教程