上一章,我们实现了添加博客文章功能,是不是很简单。
这一章,我们来实现查询、修改、删除博客文章功能。为什么放到一起呢?因为删除很简单,修改跟添加基本雷同,只有查询有较大区别,所以放到一章就能讲完了。
查询博客文章
首先,从查询展示博客文章开始。
下图就是查询博客文章的接口,文件名是 articleSelect.js
。
与添加功能类似,其实也是四部曲。
- 获取参数。
- 验证参数。
- 接口逻辑。
- 返回数据。
// /apis/articleSelect.js 文件
import { mysqlPool } from '../mysql.js';
export default async (req) => {
try {
// 参数去掉前后空格
const page = req.body.page; // 第几页
const limit = req.body.limit; // 每页多少条
const author = req.body.author; // 查谁的
// ------------------------------------------------------
// 验证标题参数
// 验证作者参数,必须为非0数字开头的整数
if (/[1-9]\d*/.test(page) === false) {
return {
code: 1,
msg: '当前页码必须为非0正整数'
};
}
// ------------------------------------------------------
// 验证内容参数
// 验证作者参数,必须为非0数字开头的整数
if (/[1-9]\d*/.test(limit) === false) {
return {
code: 1,
msg: '每页条数必须为非0正整数'
};
}
// ------------------------------------------------------
// 验证作者参数,必须为非0数字开头的整数
if (/[1-9]\d*/.test(author) === false) {
return {
code: 1,
msg: '文章作者必须传作者的数字ID'
};
}
// ------------------------------------------------------
// 从连接池中获取一个数据库连接
const db = await mysqlPool.getConnection();
// 查询数据库是否有对应的用户数据
const [rows] = await db.query({
sql: 'SELECT * FROM `article` WHERE `author` = :author LIMIT :offset,:limit',
values: {
offset: (Number(page) - 1) * Number(limit),
limit: Number(limit),
author: Number(author)
}
});
// 释放数据库连接
db.release();
// 返回成功信息
return {
code: 0,
msg: '查询文章成功',
data: rows || []
};
} catch (err) {
console.log('🚀 ~ err:', err);
return {
code: 1,
msg: '未知错误'
};
}
};
这里,我们接收 3 个参数,分别是:
page
(当前查询的是第几页?)。limit
(每一页查询多少条?)。author
(查询谁的数据?)。
举个例子,我们要查询第 2 页数据,每一页 10 条。
那么请求的 page=2,limit=10,接口收到后,分页查询的 SQL 部分就是 LIMIT (2 - 1) * 10 = 10,10。也就是 LIMIT 10,10。
什么意思呢,我稍微讲解一下:
第一页是 1-10 (第 1 条到第 10 条)。
第二页是 10-20 (第 10 条到第 20 条)。
第三页是 20-30 (第 20 条到第 30 条)。
LIMIT 的语法是 LIMIT n,m。
n 表示从第几条开始,m 是查询多少条。
如果我们接收到 page=2 后,不减 1 的话,那么我们的分页查询是 LIMIT 20,10,从第 20 条开始,查询 10 条,那就是 (20-30),属于第 3 页了,而我们要查询的是第二页 (10-20)。
所以,我们才需要把 page 减去 1,那么,为什么 page 不从 0 开始呢?第 0 页?这是典型的编程思维,程序是给人用的,从第 1 页开始,更加符合人为习惯。
查询接口实现后,便能把数据查询并显示到网页上了。
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>文章管理</title>
<script src="./template-web.js"></script>
</head>
<body>
<!-- 用于防止浏览器自动填充密码 -->
<input type="password" clearable hidden autocomplete="new-password" style="display: none" />
<div class="form">
<div class="group">
<div class="label">标题</div>
<div class="value">
<input class="title" type="input" placeholder="请输入标题" />
</div>
</div>
<div class="group">
<div class="label">内容</div>
<div class="value">
<input class="content" type="input" placeholder="请输入内容" />
</div>
</div>
<div class="button insert">添加</div>
<div class="button update">更新</div>
</div>
<!-- 数据面板 -->
<div class="panel"></div>
<!-- 文章列表模板 -->
<script type="text/html" id="article-lists">
<div class="table">
<div class="th">
<div class="td id">ID</div>
<div class="td author">作者</div>
<div class="td title">标题</div>
<div class="td content">内容</div>
<div class="td created_at">创建时间</div>
<div class="td updated_at">更新时间</div>
<div class="td action">操作</div>
</div>
{{each data item key}}
<div class="tr">
<div class="td id">{{ item.id }}</div>
<div class="td author">{{ item.author }}</div>
<div class="td title">{{ item.title }}</div>
<div class="td content">{{ item.content }}</div>
<div class="td created_at">{{ item.created_at2 }}</div>
<div class="td updated_at">{{ item.updated_at2 }}</div>
<div class="td action">
<span class="upd" data-id="{{item.id}}">更新</span>
<span class="del" data-id="{{item.id}}">删除</span>
</div>
</div>
{{/each}}
</div>
</script>
<script>
// 时间戳转年月日
const timestampToYMD = (timestamp) => {
if (!timestamp) return '';
const date = new Date(timestamp);
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 月份是从0开始的,所以需要+1
const day = date.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
};
// 查询文章列表
const apiArticleSelect = async () => {
// 获取登录时保存到本地的用户数据,并解析成对象结构
const user = JSON.parse(localStorage.getItem('user'));
// 请求查询接口,拿到文章列表
const result = await fetch('/api/articleSelect', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify({
page: 1,
limit: 10,
author: user.id
})
});
// 把拿到的数据变成JSON结构
const { code, data, msg } = await result.json();
// 判断 code 是否等于0,为0则表示拿到了正常的接口数据
if (code === 0) {
// 处理日期,把时间戳转为年月日,并用新字段保存
const data2 = data.map((item) => {
item.created_at2 = timestampToYMD(item.created_at);
item.updated_at2 = timestampToYMD(item.updated_at);
return item;
});
// 把数据用模板渲染
const html = template('article-lists', {
data: data2
});
// 把渲染后的数据放到页面中
document.querySelector('.panel').innerHTML = html;
} else {
// 否则在控制台显示接口异常提示
console.log(msg);
}
};
// 直接运行文章查询接口
apiArticleSelect();
</script>
</body>
</html>
则是页面代码。
需要注意的是,我们不用任何现代化框架,而是引入了一个 HTML 模板引擎,art-template。
HTML 模板引擎,是前端现代化框架 Vue,React 出来之前非常流行的网页开发方式,上手非常简单,一共只有 3 步:
- 写 HTML 模板语法。
- 将数据与模板进行渲染,得到 HTML 字符。
- 最后,把 HTML 字符插入到文档中即可。
<!-- 文章列表模板 -->
<script type="text/html" id="article-lists">
<div class="table">
<div class="th">
<div class="td id">ID</div>
<div class="td author">作者</div>
<div class="td title">标题</div>
<div class="td content">内容</div>
<div class="td created_at">创建时间</div>
<div class="td updated_at">更新时间</div>
<div class="td action">操作</div>
</div>
{{each data item key}}
<div class="tr">
<div class="td id">{{ item.id }}</div>
<div class="td author">{{ item.author }}</div>
<div class="td title">{{ item.title }}</div>
<div class="td content">{{ item.content }}</div>
<div class="td created_at">{{ item.created_at2 }}</div>
<div class="td updated_at">{{ item.updated_at2 }}</div>
<div class="td action">
<span class="upd" data-id="{{item.id}}">更新</span>
<span class="del" data-id="{{item.id}}">删除</span>
</div>
</div>
{{/each}}
</div>
</script>
这是 art-template
写的 HTML 模板语法,可以看到跟 Vue 风格很类似。
// 把拿到的数据变成JSON结构
const { code, data, msg } = await result.json();
// 判断 code 是否等于0,为0则表示拿到了正常的接口数据
if (code === 0) {
// 处理日期,把时间戳转为年月日,并用新字段保存
const data2 = data.map((item) => {
item.created_at2 = timestampToYMD(item.created_at);
item.updated_at2 = timestampToYMD(item.updated_at);
return item;
});
// 把数据用模板渲染
const html = template('article-lists', {
data: data2
});
// 把渲染后的数据放到页面中
document.querySelector('.panel').innerHTML = html;
} else {
// 否则在控制台显示接口异常提示
console.log(msg);
}
这是将模板用数据填充,得到渲染后的 HTML 字符,最后插入到文档中。
最后就得到了我们博客文章查询与展示的页面效果。
会员内容
会员隐藏内容,共 [7556] 字。 👉购买地址:https://sourl.cn/NM5H5m
最后,来演示一个完整的博客文章的增删改查操作。