一、前言
暑假期间,为了更好的学习一些后台的技术,我们团队一起做了用 Node.js、基于 Node.js 平台的 web 应用开发框架 Express、Node.js 模板引擎 Swig、MongoDB、MVC 框架等开发技术实现“新思路团队 CMS 内容管理系统”这个项目。老师分配给我的任务是首页、分页、搜索。
二、准备
安装 Node.js、MongoDB、Git。
三、学习
- MongoDB
 - Node.js
 - 基于 Node.js 平台的 web 应用开发框架 Express
 - Node.js 模板引擎 swig
 - 了解 MVC 框架
 
四、流程
- 1、将路由请求写在 routes.js 文件里
 - 2、路由处理的回调函数分离开来,写在 controls 文件夹里的某个文件里
 - 3、写 controls 的时候对数据库的操作,并用 res.render 渲染到模版里
 - 4、在 views 文件夹里写好模版
 - 5、将模版要用到的 js 和 css 文件以及图片都写到 publics 里面
 - 6、表单上传的文件存到 uploads 文件夹里
 
五、代码
说明:以下首页、分页、搜索的实现并不是最终版。如果你想看我的整个项目,请访问 cms-blog。
5.1 首页和首页分页
1)home.html
| 
                       1 
                        2 
                        3 
                        4 
                        5 
                        6 
                        7 
                        8 
                        9 
                        10 
                        11 
                        12 
                        13 
                        14 
                        15 
                        16 
                        17 
                        18 
                        19 
                        20 
                        21 
                        22 
                        23 
                        24 
                        25 
                        26 
                        27 
                        28 
                        29 
                        30 
                        31 
                        32 
                        33 
                        34 
                        35 
                        36 
                        37 
                        38 
                        39 
                        40 
                        41 
                        42 
                       | 
                    {% extends './layouts/web.html' %} {% block content %} <div class="main">     <section class="articles">     {% if posts.length %}         {% for post in posts -%}         <article class="article">             <a href="/article/{{post.id}}"><img src="/files/article.jpg"></a>             <section>                 <h1><a href="/article/{{post.id}}">{{post.title}}</a></h1>                 <span>{{post.time}} / <a href="/personal/{{post.author}}">{{post.author}}</a> / <a href="/{{post.classes}}">{{post.classes}}</a> / <a href="/article/{{post.id}}/#respond">{{post.comments.users.length + post.comments.visitor.length}} Comments</a></span>                 <p>{{post.content}}<a href="/article/{{post.id}}"> 阅读全文</a></p>                 <span class="article-tag">{% for tag in post.tag -%}<a href="/tag/{{tag}}">{{tag}}</a>{%- endfor %}</span>             </section>         </article>         {%- endfor %}     {% else %}         <article class="article">             <a href="#"><img src="/files/article.jpg"></a>             <section>                 <h1>对不起</h1>                 <p>{{ '还没有相关的内容' }}</p>             </section>         </article>     {% endif %}         <div class="pagenav">         {% if perpagenum < total %}             {% for page in pages -%}             {% if loop.index == current_page %}<span class="current-page">{{page}}</span>{% else %}<a href="/{{category}}/page/{{page}}">{{page}}</a>{% endif %}             {%- endfor %}             <span>共{{pages.length}}页</span>         {% else %}         {% endif %}         </div>     </section>     <aside class="sidebar"></aside>     <section class="clear"></section> </div> <!--首页页面脚本文件--> <script type="text/javascript" src="/script/home.js"></script> {% endblock %}  | 
                  
2)page.html
分类目录分页也是调用这个页面模板
| 
                       1 
                        2 
                        3 
                        4 
                        5 
                        6 
                        7 
                        8 
                        9 
                        10 
                        11 
                        12 
                        13 
                        14 
                        15 
                        16 
                        17 
                        18 
                        19 
                        20 
                        21 
                        22 
                        23 
                        24 
                        25 
                        26 
                        27 
                        28 
                        29 
                        30 
                        31 
                        32 
                       | 
                    {% extends './layouts/web.html' %} {% block content %} <div class="main">     <section class="articles">     {% for post in posts -%}         <article class="article">             <a href="/article/{{post.id}}"><img src="/files/article.jpg"></a>             <section>                 <h1><a href="/article/{{post.id}}">{{post.title}}</a></h1>                 <span>{{post.time}} / <a href="/{{post.author}}">{{post.author}}</a> / <a href="/{{post.classes}}">{{post.classes}}</a> / <a href="/article/{{post.id}}/#respond">{{post.comments.users.length + post.comments.visitor.length}} Comments</a></span>                 <p>{{post.content}}<a href="/article/{{post.id}}"> 阅读全文</a></p>                 <span class="article-tag">{% for tag in post.tag -%}<a href="/tag/{{tag}}">{{tag}}</a>{%- endfor %}</span>             </section>         </article>     {%- endfor %}         <div class="pagenav">         {% if perpagenum < total %}             {% for page in pages -%}             {% if loop.index == current_page %}<span class="current-page">{{page}}</span>{% else %}<a href="/{{category}}/page/{{page}}">{{page}}</a>{% endif %}             {%- endfor %}             <span>共{{pages.length}}页</span>         {% else %}         {% endif %}         </div>     </section>     <aside class="sidebar"></aside>     <section class="clear"></section> </div> <!--首页页面脚本文件--> <script type="text/javascript" src="/script/home.js"></script> {% endblock %}  | 
                  
3)home_controls.js
| 
                       1 
                        2 
                        3 
                        4 
                        5 
                        6 
                        7 
                        8 
                        9 
                        10 
                        11 
                        12 
                        13 
                        14 
                        15 
                        16 
                        17 
                        18 
                        19 
                        20 
                        21 
                        22 
                        23 
                        24 
                        25 
                        26 
                        27 
                        28 
                        29 
                        30 
                        31 
                        32 
                        33 
                        34 
                        35 
                        36 
                        37 
                        38 
                        39 
                        40 
                        41 
                        42 
                        43 
                        44 
                        45 
                        46 
                        47 
                        48 
                        49 
                        50 
                        51 
                        52 
                        53 
                        54 
                        55 
                        56 
                        57 
                        58 
                        59 
                        60 
                        61 
                        62 
                        63 
                        64 
                        65 
                        66 
                        67 
                        68 
                        69 
                        70 
                        71 
                       | 
                    var models = require('../models/models.js'); // 首页控制台 // 首页 exports.home = function(req, res){     var total,// 总文章数         pagenum,// 页数         perpagenum = 10,// 每页的条数         posts = [],         pages = [];     // console.log(page);     models.articles.find({}, function(err, articles){         articles = articles.reverse();// 颠倒数组中元素的顺序         total = articles.length;         pagenum = Math.ceil(total / perpagenum);// 对页数进行上舍入         // console.log(pagenum);         for(var i = 0,len = pagenum; i < len; i++){             pages[i] = i + 1;         }         for(var i = 0,len = (perpagenum < total ? perpagenum : total); i < len; i++){             posts[i] = articles[i];         }         res.render('home', {             title: '新思路团队网站 - NewThread',             total: total,             category: 'home',             current_page: '1',             perpagenum: perpagenum,             pages: pages,             posts: posts         });     }); }; // 首页分页 exports.home_page = function(req, res){     var strUrl = req.url,// 字符串URL,如 /home/page/1         arrayUrl = strUrl.split("/"),// 把字符串以“/”分割成字符串数组         page = arrayUrl[arrayUrl.length-1],// 获取page的值         total,// 总文章数         pagenum,// 页数         perpagenum = 10,// 每页的条数         posts = [],         pages = [];     if( !isNaN(page) ){// 判断是否是数字         page = page;     }else{         page = 1;     }     // console.log(page);     models.articles.find({}, function(err, articles){         articles = articles.reverse();// 颠倒数组中元素的顺序         total = articles.length;         pagenum = Math.ceil(total / perpagenum);// 对页数进行上舍入         // console.log(pagenum);         for(var i = 0,len = pagenum; i < len; i++){             pages[i] = i + 1;         }         for(var i = (page-1) * perpagenum,j = 0,len = (page * perpagenum < total ? page * perpagenum : total); i < len; i++,j ++){             posts[j] = articles[i];         }         res.render('page', {             title: '新思路团队网站 - NewThread',             total: total,             category: 'home',             current_page: page,             perpagenum: perpagenum,             pages: pages,             posts: posts         });     }); };  | 
                  
5.2 分类目录和分类目录分页
1)category.html
| 
                       1 
                        2 
                        3 
                        4 
                        5 
                        6 
                        7 
                        8 
                        9 
                        10 
                        11 
                        12 
                        13 
                        14 
                        15 
                        16 
                        17 
                        18 
                        19 
                        20 
                        21 
                        22 
                        23 
                        24 
                        25 
                        26 
                        27 
                        28 
                        29 
                        30 
                        31 
                        32 
                        33 
                        34 
                        35 
                        36 
                        37 
                        38 
                        39 
                        40 
                        41 
                        42 
                       | 
                    {% extends './layouts/web.html' %} {% block content %} <div class="main">     <section class="articles">     {% if posts.length %}         {% for post in posts -%}         <article class="article">             <a href="/article/{{post.id}}"><img src="/files/article.jpg"></a>             <section>                 <h1><a href="/article/{{post.id}}">{{post.title}}</a></h1>                 <span>{{post.time}} / <a href="/{{post.author}}">{{post.author}}</a> / <a href="/{{post.classes}}">{{post.classes}}</a> / <a href="/article/{{post.id}}/#respond">{{post.comments.users.length + post.comments.visitor.length}} Comments</a></span>                 <p>{{post.content}}<a href="/article/{{post.id}}"> 阅读全文</a></p>                 <span class="article-tag">{% for tag in post.tag -%}<a href="/tag/{{tag}}">{{tag}}</a>{%- endfor %}</span>             </section>         </article>         {%- endfor %}     {% else %}         <article class="article">             <a href="#"><img src="/files/article.jpg"></a>             <section>                 <h1>对不起</h1>                 <p>{{ '还没有与“' + category + '”分类目录相关的内容' }}</p>             </section>         </article>     {% endif %}         <div class="pagenav">         {% if perpagenum < total %}             {% for page in pages -%}             {% if loop.index == current_page %}<span class="current-page">{{page}}</span>{% else %}<a href="/{{category}}/page/{{page}}">{{page}}</a>{% endif %}             {%- endfor %}             <span>共{{pages.length}}页</span>         {% else %}         {% endif %}         </div>     </section>     <aside class="sidebar"></aside>     <section class="clear"></section> </div> <!--首页页面脚本文件--> <script type="text/javascript" src="/script/home.js"></script> {% endblock %}  | 
                  
2)category_controls.js
| 
                       1 
                        2 
                        3 
                        4 
                        5 
                        6 
                        7 
                        8 
                        9 
                        10 
                        11 
                        12 
                        13 
                        14 
                        15 
                        16 
                        17 
                        18 
                        19 
                        20 
                        21 
                        22 
                        23 
                        24 
                        25 
                        26 
                        27 
                        28 
                        29 
                        30 
                        31 
                        32 
                        33 
                        34 
                        35 
                        36 
                        37 
                        38 
                        39 
                        40 
                        41 
                        42 
                        43 
                        44 
                        45 
                        46 
                        47 
                        48 
                        49 
                        50 
                        51 
                        52 
                        53 
                        54 
                        55 
                        56 
                        57 
                        58 
                        59 
                        60 
                        61 
                        62 
                        63 
                        64 
                        65 
                        66 
                        67 
                        68 
                        69 
                        70 
                        71 
                        72 
                        73 
                        74 
                        75 
                       | 
                    var models = require('../models/models.js'); // 分类目录控制台 // 分类目录: 小组专区、成果展示、团队历程 exports.category = function(req, res){     var strUrl = req.url,// 字符串URL,如 /group         arrayUrl = strUrl.split("/"),// 把字符串以“/”分割成字符串数组         category = arrayUrl[arrayUrl.length-1],// 获取分类目录的值         total,// 总文章数         pagenum, // 页数         perpagenum = 10,// 每页的条数         posts = [],         pages = [];     // console.log(category);     models.articles.find({classes: category}, function(err, articles){         articles = articles.reverse();// 颠倒数组中元素的顺序         total = articles.length;         pagenum = Math.ceil(total / perpagenum);// 对页数进行上舍入         // console.log(pagenum);         for(var i = 0,len = pagenum; i < len; i++){    &nbnbsp;        pages[i] = i + 1;         }         for(var i = 0,len = (perpagenum < total ? perpagenum : total); i < len; i++){             posts[i] = articles[i];         }         res.render('category', {             title: '新思路团队网站 - NewThread',             total: total,             category: category,             current_page: '1',             perpagenum: perpagenum,             pages: pages,             posts: posts         });     }); }; // 分类目录分页 exports.category_page = function(req, res){     var strUrl = req.url,// 字符串URL,如 /group/page/1         arrayUrl = strUrl.split("/"),// 把字符串以“/”分割成字符串数组         category = arrayUrl[1],// 获取分类目录的值         page = arrayUrl[arrayUrl.length-1],// 获取page的值         total,// 总文章数         pagenum, // 页数         perpagenum = 10,// 每页的条数         posts = [],         pages = [];     if( !isNaN(page) ){// 判断是否是数字         page = page;     }else{         page = 1;     }     console.log(category);     models.articles.find({classes: category}, function(err, articles){         articles = articles.reverse();// 颠倒数组中元素的顺序         total = articles.length;         pagenum = Math.ceil(total / perpagenum);// 对页数进行上舍入         // console.log(pagenum);         for(var i = 0,len = pagenum; i < len; i++){             pages[i] = i + 1;         }         for(var i = (page-1) * perpagenum,j = 0,len = (page * perpagenum < total ? page * perpagenum : total); i < len; i++,j ++){             posts[j] = articles[i];         }         res.render('page', {             title: '新思路团队网站 - NewThread',             total: total,             category: category,             current_page: page,             perpagenum: perpagenum,             pages: pages,             posts: posts         });     }); };  | 
                  
5.3 搜索
1)search.html
| 
                       1 
                        2 
                        3 
                        4 
                        5 
                        6 
                        7 
                        8 
                        9 
                        10 
                        11 
                        12 
                        13 
                        14 
                        15 
                        16 
                        17 
                        18 
                        19 
                        20 
                        21 
                        22 
                        23 
                        24 
                        25 
                        26 
                        27 
                        28 
                        29 
                        30 
                        31 
                        32 
                        33 
                        34 
                        35 
                        36 
                        37 
                        38 
                        39 
                        40 
                        41 
                        42 
                        43 
                        44 
                        45 
                        46 
                        47 
                        48 
                        49 
                        50 
                        51 
                        52 
                        53 
                        54 
                        55 
                        56 
                        57 
                        58 
                        59 
                        60 
                        61 
                        62 
                        63 
                        64 
                        65 
                        66 
                        67 
                        68 
                        69 
                        70 
                        71 
                        72 
                        73 
                        74 
                        75 
                        76 
                        77 
                        78 
                        79 
                        80 
                        81 
                        82 
                        83 
                        84 
                        85 
                        86 
                        87 
                        88 
                        89 
                        90 
                        91 
                        92 
                        93 
                        94 
                        95 
                        96 
                        97 
                        98 
                        99 
                        100 
                        101 
                        102 
                        103 
                        104 
                        105 
                        106 
                        107 
                        108 
                        109 
                        110 
                        111 
                        112 
                        113 
                       | 
                    {% extends './layouts/web.html' %} {% block content %} <div class="main">     <header id="search-head">         <form class="searchform" action="/search" method="GET">             <input type="text" name="s" value="{{s}}" id="s" placeholder="输入关键字">             <input type="submit" name="submit" value="精确搜索" class="accurate-search">             <input type="submit" name="submit" value="模糊搜索" class="fuzzy-search">         </form>         {% if submit === '精确搜索' %}         <h2 class="search-title">共搜索到 {{titles.length}} 篇标题相关文章,{{authors.length}} 篇作者相关文章,{{tags.length}} 篇标签相关文章。</h2>         <nav id="search-nav">             <a class="active">标题</a><b>|</b>             <a>作者</a><b>|</b>             <a>标签</a>         </nav>         {% else %}         <h2 class="search-title">共搜索到 {{contents.length}} 篇相关文章。</h2>         <nav id="search-nav"></nav>         {% endif %}     </header>     <div id="search-results">         {% if submit === '精确搜索' %}         <section class="articles" style="display: block;">         {% if err %}             <p>{{ signal }}</p>         {% endif %}         {% if titles.length %}             {% for post in titles -%}             <article class="article">                 <a href="/article/{{post.id}}"><img src="/files/article.jpg"></a>                 <section>                     <h1><a href="/article/{{post.id}}">{{post.title}}</a></h1>                     <span>{{post.time}} / <a href="/{{post.author}}">{{post.author}}</a> / <a href="/{{post.classes}}">{{post.classes}}</a> / <a href="/article/{{post.id}}/#respond">{{post.comments.users.length + post.comments.visitor.length}} Comments</a></span>                     <p>{{post.content}}<a href="/article/{{post.id}}"> 阅读全文</a></p>                     <span class="article-tag">{% for tag in post.tag -%}<a href="/tag/{{tag}}">{{tag}}</a>{%- endfor %}</span>                 </section>             </article>             {%- endfor %}         {% else %}             <p>{{ '找不到与“' + s + '”相关的内容' }}</p>         {% endif %}         </section>         <section class="articles" style="display: none;">         {% if err %}             <p>{{ signal }}</p>         {% endif %}         {% if authors.length %}             {% for post in authors -%}             <article class="article">                 <a href="/article/{{post.id}}"><img src="/files/article.jpg"></a>                 <section>                     <h1><a href="/article/{{post.id}}">{{post.title}}</a></h1>                     <span>{{post.time}} / <a href="/{{post.author}}">{{post.author}}</a> / <a href="/{{post.classes}}">{{post.classes}}</a> / <a href="/article/{{post.id}}/#respond">{{post.comments.users.length + post.comments.visitor.length}} Comments</a></span>                     <p>{{post.content}}<a href="/article/{{post.id}}"> 阅读全文</a></p>                     <span class="article-tag">{% for tag in post.tag -%}<a href="/tag/{{tag}}">{{tag}}</a>{%- endfor %}</span>                 </section>             </article>             {%- endfor %}         {% else %}             <p>{{ '找不到与“' + s + '”相关的内容' }}</p>         {% endif %}         </section>         <section class="articles" style="display: none;">         {% if err %}             <p>{{ signal }}</p>         {% endif %}         {% if tags.length %}             {% for post in tags -%}             <article class="article">                 <a href="/article/{{post.id}}"><img src="/files/article.jpg"></a>                 <section>                     <h1><a href="/article/{{post.id}}">{{post.title}}</a></h1>                     <span>{{post.time}} / <a href="/{{post.author}}">{{post.author}}</a> / <a href="/{{post.classes}}">{{post.classes}}</a> / <a href="/article/{{post.id}}/#respond">{{post.comments.users.length + post.comments.visitor.length}} Comments</a></span>                     <p>{{post.content}}<a href="/article/{{post.id}}"> 阅读全文</a></p>                     <span class="article-tag">{% for tag in post.tag -%}<a href="/tag/{{tag}}">{{tag}}</a>{%- endfor %}</span>                 </section>             </article>             {%- endfor %}         {% else %}             <p>{{ '找不到与“' + s + '”相关的内容' }}</p>         {% endif %}         </section>         {% else %}         <section class="articles" style="display: block;">         {% if err %}             <p>{{ signal }}</p>         {% endif %}         {% if contents.length %}             {% for post in contents -%}             <article class="article">                 <a href="/article/{{post.id}}"><img src="/files/article.jpg"></a>                 <section>                     <h1><a href="/article/{{post.id}}">{{post.title}}</a></h1>                     <span>{{post.time}} / <a href="/{{post.author}}">{{post.author}}</a> / <a href="/{{post.classes}}">{{post.classes}}</a> / <a href="/article/{{post.id}}/#respond">{{post.comments.users.length + post.comments.visitor.length}} Comments</a></span>                     <p>{{post.content}}<a href="/article/{{post.id}}"> 阅读全文</a></p>                     <span class="article-tag">{% for tag in post.tag -%}<a href="/tag/{{tag}}">{{tag}}</a>{%- endfor %}</span>                 </section>             </article>             {%- endfor %}         {% else %}             <p>{{ '找不到与“' + s + '”相关的内容' }}</p>         {% endif %}         </section>         {% endif %}         <aside class="sidebar"></aside>         <section class="clear"></section>     </div> </div> <!--搜索页面脚本文件--> <script type="text/javascript" src="/script/search.js"></script> {% endblock %}  | 
                  
2)search_controls.js
| 
                       1 
                        2 
                        3 
                        4 
                        5 
                        6 
                        7 
                        8 
                        9 
                        10 
                        11 
                        12 
                        13 
                        14 
                        15 
                        16 
                        17 
                        18 
                        19 
                        20 
                        21 
                        22 
                        23 
                        24 
                        25 
                        26 
                        27 
                        28 
                        29 
                        30 
                        31 
                        32 
                        33 
                        34 
                        35 
                        36 
                        37 
                        38 
                        39 
                        40 
                        41 
                        42 
                        43 
                        44 
                        45 
                        46 
                        47 
                        48 
                        49 
                        50 
                        51 
                        52 
                        53 
                        54 
                        55 
                        56 
                        57 
                        58 
                        59 
                        60 
                        61 
                        62 
                        63 
                        64 
                        65 
                        66 
                       | 
                    var models = require('../models/models.js'); // 搜索控制台 //搜索 exports.search = function(req, res){     var s = req.query.s,// 获取输入的关键字。如果是POST方式,语句为 s = req.body.s         submit = req.query.submit,// 模糊搜索。如果是POST方式,语句为submit = req.body.submit         regex = eval('/' + s + '/'),// 正则表达式中使用变量,使用eval()将组合的字符串进行转换         titles = [],// 该数组用于存放与标题相关的文章         authors = [],// 该数组用于存放与作者相关的文章         tags = [],// 该数组用于存放与标签相关的文章         contents = [];// 该数组用于存放与内容相关的文章         // if(s.charAt(s.length-1) === "/"){         //     regex = eval('/' + s);         // }else{         //     regex = eval('/' + s + '/')         // }     console.log(s);     console.log(submit);     if(s.length){         if(submit === "精确搜索"){             models.articles.find({title: regex}, function(err, articles){// 查询与标题相关的文章             if(err) return console.error(err);             // for(var i = 0,len = articles.length; i < len; i++){             //     titles[i] = articles[len-i-1];             // }             titles = articles.reverse();         });         models.articles.find({author: regex}, function(err, articles){// 查询与作者相关的文章             if(err) return console.error(err);             authors = articles.reverse();         });         models.articles.find({tag: regex}, function(err, articles){// 查询与标签相关的文章             if(err) return console.error(err);             tags = articles.reverse();             res.render('search', {                 title: '搜索结果 - 新思路团队网站',                 s: s,                 submit: submit,                 titles: titles,                 authors: authors,                 tags: tags             });         });         }else{             models.articles.find({content: regex}, function(err, articles){// 查询与内容相关的文章             if(err) return console.error(err);             contents = articles.reverse();             res.render('search', {                 title: '搜索结果 - 新思路团队网站',                 s: s,                 submit: submit,                 contents: contents             });         });         }     }else{         console.log('输入不能为空');         res.render('search', {             title: '搜索结果 - 新思路团队网站',             err: true,             signal: '输入不能为空'         });     } };  | 
                  
                  
                  
2条评论
棒棒哒!
学长好牛哦!带学妹飞。