前面《Express脚手架项目》篇基本实现了一个留言板登录注册和留言的一个功能,但是一旦留言很多就会破坏页面结构,这里需要一个分页的效果。在说分页之前,先让留言能够查看在detail.ejs页面展示一下。
//detail.ejs
<!DOCTYPE html>
<html>
<head>
<title>详情</title>
<link rel='stylesheet' href='/stylesheets/bootstrap.min.css' />
<script src="/javascripts/jquery-1.11.0.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<%- include('head.ejs')%>
<h2>详情</h2>
<h1>歌曲名字:<%- detail2%></h1>
<h2>歌手:<%- detail1%></h2>
</html>
这里面的数据通过点击留言具体信息的时候,提交一个id去后台数据库查找,之后让后台把数据给前端页面,也就是前端会得到detail1和detail2这两条代表留言标题、留言内容的数据,在前端页面展示。下面是在留言页面去传递id和跳转到详情页面的操作。
//liuyan.ejs
<table class="table table-striped">
<tr><th>序号</th><th>标题</th><th>内容</th></tr>
<% list.map(function(item,i){%>
<tr>
<td><%- i+1%></td>
//点击跳转,通过query传参,search的方式,知道点击的是哪一条留言
<td onclick="location.href='/detail?id=<%- item._id%>'"><%- item.title%></td>
<td><%- item.con%></td>
</tr>
<% })%>
</table>
然后需要在前端路由渲染detail页面,还有通过req.query来接收前端传参数据。
//index.js
var mongodb = require("mongodb").MongoClient;
//这里引入mongodb模块里面的ObjectId是为了在查找的时候能通过id查找,因为前端传来的id是字符串格式,
//{ id: '5b6bb56282685418c87bf5ce' },而数据库里面的是处理过的
//{"_id": ObjectId('5b6bb56282685418c87bf5ce') }这样格式,不处理肯定找不到
var ObjectId = require("mongodb").ObjectId;
var db_str = "mongodb://localhost:27017/html5";
//详情
router.get("/detail",(req,res)=>{
//console.log(req.query)
var id = ObjectId(req.query.id)
mongodb.connect(db_str,(err,database)=>{
database.collection("liuyan",(err,coll)=>{
coll.find({_id:id}).toArray((err,data)=>{
//找到的留言信息传给前端页面
res.render("detail",{detail1:data[0].con,detail2:data[0].title})
database.close()
})
})
})
})
以上就实现了留言详情的一个展示,下面来实现分页。
在liuyan.ejs的发布留言按钮结构下面写入分页模块,拿了bootstrap的组件里面的分页结构,主要代码如下
//liuyan.ejs
<!--分页-->
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="/liuyan?pageNum=<%-pageNum<1?1:parseInt(pageNum)-1%>" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<!--<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>-->
<% if(page>4){%>
<li><a href="/liuyan?pageNum=1">1</a></li>
<li><a href="/liuyan?pageNum=2">2</a></li>
<li><a href="#">...</a></li>
<li><a href="/liuyan?pageNum=<%-page-1%>"><%-page-1%></a></li>
<li><a href="/liuyan?pageNum=<%-page%>"><%-page%></a></li>
<%}else{%>
<%for(let i=0; i<page;i++){%>
<li><a href="/liuyan?pageNum=<%-i+1%>"><%-i+1%></a></li>
<%}%>
<%}%>
<li>
<a href="/liuyan?pageNum=<%-pageNum>page?page:parseInt(pageNum)+1%>" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
前端路由对接收到的由前端页面用户点击的第几页即pageNum做的处理,如下
//index.js
//要安装async依赖模块(npm i async -D),然后引入
var async = require("async");
//留言
router.get("/liuyan",(req,res)=>{
//页码
var pageNum = req.query.pageNum;
//没点击时候,展示第一页,点击时候,点哪一页展示哪一页的数据
pageNum = pageNum?pageNum:1;
//总页数
var page = 0;
//每页数量
var size =5;
//总条数
var count = 0;
mongodb.connect(db_str,(err,database)=>{
database.collection("liuyan",(err,coll)=>{
async.series([
function(callback){
coll.find({}).toArray((err,data)=>{
count = data.length;
page = Math.ceil(count/size)
// 上一页/下一页
pageNum=pageNum<1?1:pageNum;
pageNum= pageNum.page?page:pageNum;
callback(null,"")
})
},
function(callback){
coll.find({}).sort({_id:-1}).limit(size).skip((pageNum-1)*size).toArray((err,data)=>{
callback(null,data)
})
}
],function(err,data){
res.render("liuyan",{list:data[1],pageNum:pageNum,page:page,count:count,size:size})
database.close()
})
// coll.find({}).sort({_id:-1}).toArray((err,data)=>{
// res.render("liuyan",{list:data})
// database.close()
// })
})
})
})
这里用到异步流程模块,主要是因为两个事件需要同时进行,没有先后顺序。
为了完善留言板功能,添加了一个富文本编辑器,这里需要引入几个文件,可以参考富文本编辑器入门的用法。主要是在javascripts中引入xheditor文件夹和fwb.js(可以从我上传的资源里面下,也可以在官网即入门里面下),然后再路由界面引入upload.js文件。
//liuyan.ejs
<script src="/javascripts/jquery-1.11.0.js" type="text/javascript" charset="utf-8"></script>
<script src="/javascripts/xheditor/xheditor-1.2.2.min.js" type="text/javascript" charset="utf-8"></script>
<script src="/javascripts/xheditor/xheditor_lang/zh-cn.js" type="text/javascript" charset="utf-8"></script>
//修改一下input框为多行文本输入框,加上xheditor类名
<label for="con">内容</label>
<textarea type="text" class="form-control xheditor" id="con" placeholder="内容"></textarea>
到这里可以实现富文本的表情、加粗、倾斜、字变色等功能,但是图片不能上传。下面配置一下,实现图片上传。
//liuyan.ejs
//在ajax事件的script上面调用一下,这里面配有上传图片路径upImgUrl: '/users/uploadImg',
<script src="/javascripts/fwb.js" type="text/javascript" charset="utf-8"></script>
然后看一下upload.js,它里面引入了一个multiparty模块,实现上传图片的。安装一下依赖(npm i multiparty -D),然后能看到这个upload.js文件封装了一个函数实现了文件的上传时候相关配置,最后作为upload模块暴露出去了,说明要在其他地方引用。下面是upload.js的代码。
//upload.js
var multiparty=require('multiparty')
var fs=require('fs')
function upload(req,res){
// 创建表单
var form =new multiparty.Form()
// 编码格式
form.encoding='utf-8';
// 文件大小
form.maxFilesSize=2*1024*1024;
// 文件上传目录
form.uploadDir='./uploadtem';
form.parse(req,function(err,fields,files){
var uploadurl='/images/upload';
// 获取文件
file=files['filedata'];
// 文件的原始名字
originalFilename=file[0].originalFilename;
// 文件路径
tempath=file[0].path;
var timestap=new Date().getTime()
uploadurl+=timestap+originalFilename;
newPath='./public/'+uploadurl;
var fsread=fs.createReadStream(tempath)
var fswrite=fs.createWriteStream(newPath)
fsread.pipe(fswrite)
fswrite.on('close',()=>{
fs.unlinkSync(tempath)
res.send('{"err":"","msg":"'+uploadurl+'"}')
})
})
}
module.exports=upload;
上面文件上传目录是根路径下的uploadtem,需要去在项目根路径创建一下这个目录,还有上传的路径是'/images/upload',所以要在images里面去建一下upload文件目录。再去看一下富文本fwb.js这个文件
//fwb.js
pageInit()
function pageInit() {
$.extend(XHEDITOR.settings, {shortcuts:{'ctrl+enter': submitForm}})
$('#con').xheditor({
html5Upload: false,
upMultiple: '1',
width:'100%',
upLinkUrl: 'upload.html',
upLinkExt: 'zip, rar, txt',
upImgUrl: '/users/uploadImg',
upImgExt: 'jpg,jpeg,gif,png',
upFlashUrl: 'upload.html',
upFlashExt: 'swf',
upMediaUrl: 'upload.html',
upMediaExt: 'wmv,avi,wma,mp3,mid'
})
}
// 富文本自动调用
function insertUpload(arrmsg){
var i ,msg;
for (i=0;i<arrmsg.length;i++) {
msg=arrmsg[i];
$('#uploadList').append('<option value="'+msg.id+'">'+msg.localname+'</option>')
}
}
function submitForm() {
$('#frmDemo').submit()
}
可以看到upImgUrl: '/users/uploadImg'----当我们上传图片时候,是在请求users路由里面的/uploadImg,所以去uses路由里面配置一下。
//user.js
//接收一下这个图片处理模块
var upload = require("./upload");
//图片
router.post("/uploadImg",(req,res)=>{
upload(req,res);
})
以上就将相关配置工作做好了,启动项目就可以实现登录、注册、富文本留言、查看详情这些操作了。