一、前言
暑假期间,为了更好的学习一些后台的技术,我们团队一起做了用 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条评论
棒棒哒!
学长好牛哦!带学妹飞。