express-generator脚手架的使用(二)
1.前文回顾
2.实现一个案例
2.1案例整体规划
- 1. 完成 书籍列表的展示。(完成)
- 2. 列表的分页。(完成)
- 2.1. 一页显示10条(完成)
- 2.2. 上一页和下一页
- 2.3. 首页和尾页
- 2.4. 点击页码数字,跳转(完成)
- 3. 新增功能
- 4.删除功能
- 5.修改功能
- 6. 查询功能 在列表页面中添加一个搜索框,一个搜索按钮。在搜索框中输入书名,点击搜索,进行模糊匹配。
2.2实现列表上下页
2.2.1对book.js进行改造
//进入列表页面
book.get("/list",async (req, res) => {
//获取页码
let {page} = req.query;
if (!page) {
page = 1;
}
//获取数据库中的书籍数据
let sql = `select * from book limit ${(page-1)*5},5`;
let data = await db.query(sql);
//获取书籍的总数
let countSql = `select count(*) as count from book`;
let result = await db.query(countSql);
let count = result[0].count;
//根据总数计算总页数。
let totalPage = Math.ceil(count / 5);
res.render("bookList",{data,totalPage,page});
})
2.2.2对db.js文件进行改造
//添加一个query方法
let query = function (sql) {
return new Promise((resolve, reject) => {
pool.getConnection((err, conn) => {
if (err) {
console.log(err);
return
}
conn.query(sql, (err, data) => {
if (err) {
console.log(err);
return
}
resolve(data);
conn.release();
})
})
});
}
2.2.3对bookList.ejs文件进行改造
<h1>起点排行榜</h1>
<div class="container">
<table class="table table-hover table-bordered">
<tbody>
<tr class="info">
<th>排名</th>
<th>书名</th>
<th>作者</th>
<th>分类1</th>
<th>分类2</th>
<th>简介</th>
<th>时间</th>
</tr>
<% data.forEach((item,index) => { %>
<tr>
<td style="width: 60px;"><%= item.ranking %></td>
<td class="book_table"><%= item.info2 %></td>
<td class="book_table"><%= item.author %></td>
<td class="book_table"><%= item.category1 %></td>
<td class="book_table"><%= item.category2 %></td>
<td class="book_table"><%= item.info1.length>100?item.info1.slice(0,100)+"...":item.info1 %></td>
<td class="book_table"><%= item.booktime %></td>
</tr>
<% }) %>
</tbody>
</table>
<ul class="pagination">
<!-- 上一页 -->
<% if (page != 1) { %>
<li><a href="/book/list?page=<%= page-1 %> ">«</a></li>
<% } %>
<!-- 动态生成页码 -->
<% for( let i = 1; i <= totalPage; i++ ) { %>
<li><a href="/book/list?page=<%= i %> "><%= i %> </a></li>
<% } %>
<!-- 下一页 -->
<% if (page<totalPage) { %>
<li><a href="/book/list?page=<%= Number(page)+1 %>">»</a></li>
<% } %>
</ul>
</div>
2.2.4 运行验证
输入指令 npm run start
至此列表的分页功能已经完成。
2.3用户点击添加功能
2.3.1 在booklist.ejs里面添加新增按钮
//这里a标签的路径为接下来要写的路由路径
<a href="/book/addPage" class="btn btn-success">新增</a>
效果如下:
2.3.2在book.js里面写入路由
//进入新增页面
book.get("/addPage",(req,res)=>{
res.render("book_add") //这里的路径为接下来要写的添加页面
})
2.3.3在views新建一个book_add.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>新增书籍</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/book_add.css">
</head>
<body>
<div class="container">
<h1>新增书籍</h1>
<form method="post" action="/book/add">
<div class="form-group">
<label for="exampleInputEmail1">书名</label>
<input type="text" class="form-control" name="info2" placeholder="请输入书名">
</div>
<div class="form-group">
<label>作者</label>
<input type="text" class="form-control" name="author" placeholder="请输入作者">
</div>
<div class="form-group">
<label>分类1</label>
<select class="form-control" name="category1">
<!-- <option value="">---请选择---</option> -->
<option value="玄幻">玄幻</option>
<option value="都市">都市</option>
<option value="历史">历史</option>
<option value="科幻">科幻</option>
<option value="仙侠">仙侠</option>
<option value="轻小说">轻小说</option>
<option value="悬疑">悬疑</option>
<option value="游戏">游戏</option>
</select>
</div>
<div class="form-group">
<label for="exampleInputEmail1">分类2</label>
<input type="text" class="form-control" name="category2" placeholder="请输入分类">
</div>
<div class="form-group">
<label for="">简介</label>
<textarea class="form-control" name="info1" rows="6"></textarea>
</div>
<div class="form-group">
<label>时间</label>
<input type="text" class="form-control" name="booktime" placeholder="请输入时间">
</div>
<div class="form-group">
<label for="">排名</label>
<input type="number" name="ranking" class="form-control" placeholder="请输入排行">
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
</div>
</body>
</html>
界面如下:
2.3.4在路由里写一个处理新增书籍的请求
//处理新增书籍的请求
book.post("/add",async(req,res)=>{
let result = await db.insert("book",req.body);
//判断受影响的行数如果大于0,说明新增成功,否则失败。
if (result.affectedRows>0) {
res.send("新增成功")
} else {
res.send("新增失败")
}
})
2.3.5 运行验证
2.4用户点击实现删除功能
2.4.1在bookList.ejs里面添加删除界面
<td><button type="button" data-id="<%= item.id%>" class="btn btn-danger btn-del">删除</button></td>
//获取所有的删除按钮,为它们添加点击事件
let delBtns = document.querySelectorAll(".btn-del");
for (let i = 0; i < delBtns.length; i++) {
delBtns[i].onclick = function () {
//弹出确认框
if (confirm("确认删除吗?")) {
//发起删除请求 修改url中的地址
//告诉服务器,要删除的数据是哪一个
location.href = '/book/del?id='+this.dataset.id;
}
}
}
2.4.2在book.js里面添加删除响应
//实现删除功能 location.href只能发送get请求
book.get("/del",async(req,res)=>{
// 获取id
let {id} = req.query;
let result = await db.del("book",{id})
if (result.affectedRows>0) {
res.send("删除成功")
} else {
res.send("删除失败")
}
})
2.4.3 运行验证
2.5 用户点击实现修改功能
2.5.1 在bookList.ejs中添加修改按钮
<button type="button" data-id="<%= item.id%>" class="btn btn-warning btn-edit">修改</button>
//获取所有的修改按钮,为它们添加点击事件
let editBtns = document.querySelectorAll(".btn-edit");
for (let i = 0; i < editBtns.length; i++) {
editBtns[i].onclick = function(){
location.href = '/book/editPage?id=' + this.dataset.id;
}
}
2.5.2 新建一个删除页面的ejs文件
这里命名为 book_edit.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>修改书籍</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/book_add.css">
</head>
<body>
<div class="container">
<h1>修改书籍</h1>
<form method="post" action="/book/edit">
<div class="form-group">
<label for="exampleInputEmail1">书名</label>
<input type="text" class="form-control" name="info2" value="<%= info2 %>" placeholder="请输入书名">
</div>
<div class="form-group">
<label>作者</label>
<input type="text" class="form-control" name="author" value="<%= author %>" placeholder="请输入作者">
</div>
<div class="form-group">
<label>分类1</label>
<select class="form-control" name="category1">
<!-- <option value="">---请选择---</option> -->
<option value="玄幻" <% if (category1 == "玄幻") { %> selected <% } %>>玄幻</option>
<option value="奇幻" <% if (category1 == "奇幻") { %> selected <% } %>>玄幻</option>
<option value="都市" <% if (category1 == "都市") { %> selected <% } %>>都市</option>
<option value="历史" <% if (category1 == "历史") { %> selected <% } %>>历史</option>
<option value="科幻" <% if (category1 == "科幻") { %> selected <% } %>>科幻</option>
<option value="仙侠" <% if (category1 == "仙侠") { %> selected <% } %>>仙侠</option>
<option value="轻小说" <% if (category1 == "轻小说") { %> selected <% } %>>轻小说</option>
<option value="悬疑" <% if (category1 == "悬疑") { %> selected <% } %>>悬疑</option>
<option value="游戏" <% if (category1 == "游戏") { %> selected <% } %>>游戏</option>
</select>
</div>
<div class="form-group">
<label for="exampleInputEmail1">分类2</label>
<select class="form-control" name="category2">
<!-- <option value="">---请选择---</option> -->
<option value="东方玄幻" <% if (category2 == "东方玄幻") { %> selected <% } %>>东方玄幻</option>
<option value="两宋元明" <% if (category2 == "两宋元明") { %> selected <% } %>>两宋元明</option>
<option value="侦探推理" <% if (category2 == "侦探推理") { %> selected <% } %>>侦探推理</option>
<option value="修真文明" <% if (category2 == "修真文明") { %> selected <% } %>>修真文明</option>
<option value="原生幻想" <% if (category2 == "原生幻想") { %> selected <% } %>>原生幻想</option>
<option value="古典仙侠" <% if (category2 == "古典仙侠") { %> selected <% } %>>古典仙侠</option>
<option value="娱乐明星" <% if (category2 == "娱乐明星") { %> selected <% } %>>娱乐明星</option>
<option value="幻想修仙" <% if (category2 == "幻想修仙") { %> selected <% } %>>幻想修仙</option>
<option value="异世大陆" <% if (category2 == "异世大陆") { %> selected <% } %>>异世大陆</option>
<option value="异术超能" <% if (category2 == "异术超能") { %> selected <% } %>>异术超能</option>
<option value="时空穿梭" <% if (category2 == "时空穿梭") { %> selected <% } %>>时空穿梭</option>
<option value="现代修真" <% if (category2 == "现代修真") { %> selected <% } %>>现代修真</option>
<option value="现代魔法" <% if (category2 == "现代魔法") { %> selected <% } %>>现代魔法</option>
<option value="神话修真" <% if (category2 == "神话修真") { %> selected <% } %>>神话修真</option>
<option value="秦汉三国" <% if (category2 == "秦汉三国") { %> selected <% } %>>秦汉三国</option>
<option value="衍生同人" <% if (category2 == "衍生同人") { %> selected <% } %>>衍生同人</option>
<option value="诡秘悬疑" <% if (category2 == "诡秘悬疑") { %> selected <% } %>>诡秘悬疑</option>
<option value="进化变异" <% if (category2 == "进化变异") { %> selected <% } %>>进化变异</option>
<option value="都市异能" <% if (category2 == "都市异能") { %> selected <% } %>>都市异能</option>
<option value="高武世界" <% if (category2 == "高武世界") { %> selected <% } %>>高武世界</option>
</select>
</div>
<div class="form-group">
<label for="">简介</label>
<textarea class="form-control" name="info1" rows="6"><%= info1 %></textarea>
</div>
<div class="form-group">
<label>时间</label>
<input type="text" class="form-control" name="booktime" value="<%= booktime %>" placeholder="请输入时间">
</div>
<div class="form-group">
<label for="">排名</label>
<input type="number" name="id" class="form-control" value="<%= id %>" placeholder="请输入排行">
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
</div>
</body>
</html>
界面如下:
2.5.3 在路由里添加修改功能
//实现修改功能
book.post("/edit",async(req,res)=>{
//获取传递过来的参数
let editBook = req.body;
//实现修改功能
let result = await db.update("book",editBook,{id:editBook.id});
if (result.affectedRows>0) {
res.send("修改成功")
} else {
res.send("修改失败")
}
})
2.5.4 运行验证
至此大功告成!
2.6 用户点击实现搜索功能
2.6.1 在bookList.ejs添加搜索样式
<form class="form-inline" action="/book/list" method="get">
<div class="form-group">
<label for="searchBox">书名:</label>
<input type="text" value="<%= bookName %>" class="form-control" id="searchBox" name="bookName">
</div>
<button type="submit" class="btn btn-default">查询</button>
</form>
2.6.2 修改路由里的book.js文件
//定义获取书籍数据的sql 只定义好了一部分。
let sql = `select * from book`
//定义查询所有书籍数量的SQL
let countSql = `select count(*) as count from book`;
if (bookName) {
sql += ` where info2 like '%${bookName}%'`
countSql += ` where info2 like '%${bookName}%'`
}
sql+= ` limit ${(page-1)*5},5`
//完成拼接,去执行sql
let data = await db.query(sql);
let result = await db.query(countSql);
let count = result[0].count;
//根据总数计算总页数。
let totalPage = Math.ceil(count / 5);
//bookName 是为了分页时,点击分页标签不会出现查询错误。
res.render("bookList",{data,totalPage,page,bookName});
})
2.6.3 运行验证
2.7 整体效果图
总结
查询的流程
localhost:3000/book/list
用户地址栏输入地址 域名+端口 (localhost:3000),发生了一个请求 => 找到nodeJs启动的服务 => 根据端口后面跟着的 URL 找到匹配的路由 (/book/list) => 获取参数(page) 查询数据库 得到数据列表 => 逻辑处理 => 响应一个页面给浏览器 (res.render(要响应的页面,页面中需要的数据)) => 响应的字符串渲染成可视化的页面。
新增页面中点击提交按钮
=> form表单将用户输入的值,提交到action中的地址上,参数的键是表单元素中的name。 => form表单发起了一个请求。 => 找到对应的服务,找到对应的路由。 => 获取参数,进行逻辑处理(数据库的操作) => 响应一个结果给浏览器 => 浏览器解析响应结果展示。
转载自:https://juejin.cn/post/7044479073569112095