Skip to content

上一章,我们实现了添加博客文章功能,是不是很简单。

这一章,我们来实现查询、修改、删除博客文章功能。为什么放到一起呢?因为删除很简单,修改跟添加基本雷同,只有查询有较大区别,所以放到一章就能讲完了。

查询博客文章

首先,从查询展示博客文章开始。

下图就是查询博客文章的接口,文件名是 articleSelect.js

与添加功能类似,其实也是四部曲。

  1. 获取参数。
  2. 验证参数。
  3. 接口逻辑。
  4. 返回数据。
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 个参数,分别是:

  1. page (当前查询的是第几页?)。
  2. limit (每一页查询多少条?)。
  3. 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 页开始,更加符合人为习惯。

picture 0

查询接口实现后,便能把数据查询并显示到网页上了。

html
<!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 步:

  1. 写 HTML 模板语法。
  2. 将数据与模板进行渲染,得到 HTML 字符。
  3. 最后,把 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 风格很类似。

js
// 把拿到的数据变成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

picture 4

最后,来演示一个完整的博客文章的增删改查操作。

何以解忧,唯有代码。不忘初心,方得始终。