夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 任务管理日历

  • 无代码平台

  • 图书管理系统

    • 图书管理系统:需求分析和原型图
    • 图书管理系统:用户模块后端开发
    • 图书管理系统:图书模块后端开发
    • 图书管理系统:用户模块前端开发
    • 图书管理系统:图书搜索前端开发
      • 图书列表
        • 请求列表
        • 添加搜索功能
      • 总结
    • 图书管理系统:图书增删改前端开发
    • 图书管理系统:项目总结
  • 《全栈项目》
  • 图书管理系统
神说要有光
2025-03-10
目录

图书管理系统:图书搜索前端开发

这节继续来写图书管理模块的前端部分。

就是一个页面和几个弹窗:

# 图书列表

我们先写下图书列表:

改下 BookManage/index.tsx

import { Button, Card, Form, Input } from 'antd';
import './index.css';

export function BookManage(){
    return <div id="bookManage">
        <h1>图书管理系统</h1>
        <div className="content">
            <div className='book-search'>
                <Form
                    name="search"
                    layout='inline'
                    colon={false}
                >
                    <Form.Item label="图书名称" name="name">
                        <Input />
                    </Form.Item>
                    <Form.Item label=" ">
                        <Button type="primary" htmlType="submit">
                            搜索图书
                        </Button>
                        <Button type="primary" htmlType="submit" style={{background: 'green'}} >
                            添加图书
                        </Button>
                    </Form.Item>
                </Form>
            </div>
            <div className="book-list">
                {
                    [1,2,3,4,5,6,7].map(item => {
                        return <Card
                            className='card'
                            hoverable
                            style={{ width: 300 }}
                            cover={<img alt="example" src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" />}
                        >
                            <h2>西游记</h2>
                            <div>神说要有光</div>
                            <div className='links'>
                                <a href="#">详情</a>
                                <a href="#">编辑</a>
                                <a href="#">删除</a>
                            </div>
                        </Card>
                    })
                }    
            </div>
        </div>
    </div>
}
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

上面是一个 Form,下面是 Card 的列表。

在 index.css 写下样式:

#bookManage {
    display: flex;
    flex-direction: column;
}

#bookManage h1 {
    height: 80px;
    line-height: 80px;
    border-bottom: 2px solid #ccc;
    padding-left: 20px;
}

#bookManage .content {
    padding: 20px;
}

#bookManage .book-list{
    padding: 20px;
    display: flex;
    flex-wrap: wrap;
}

#bookManage .book-list .card{
    margin-left: 30px;
    margin-bottom: 30px;
}

#bookManage .book-list .links{
    display: flex;
    
    flex-direction: row;
    justify-content: space-around;
}
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

这里还需要重置样式,在 main.tsx 里引入下:

看下效果:

# 请求列表

然后我们在 interfaces/index.ts 里加下图书列表的请求:

export async function list() {
    return await axiosInstance.get('/book/list');
}
1
2
3

然后在组件里调用下:

import { Button, Card, Form, Input, message } from 'antd';
import './index.css';
import { useEffect, useState } from 'react';
import { list } from '../../interfaces';

interface Book {
    id: number;
    name: string;
    author: string;
    description: string;
    cover: string;
}

export function BookManage(){

    const [bookList, setBookList] = useState<Array<Book>>([]);

    async function fetchData() {
        try {
            const data = await list();
            
            if(data.status === 201 || data.status === 200) {
                setBookList(data.data);
            }
        } catch(e: any) {
            message.error(e.response.data.message);
        }
    }

    useEffect(() => {
        fetchData();
    }, []);

    return <div id="bookManage">
        <h1>图书管理系统</h1>
        <div className="content">
            <div className='book-search'>
                <Form
                    name="search"
                    layout='inline'
                    colon={false}
                >
                    <Form.Item label="图书名称" name="name">
                        <Input />
                    </Form.Item>
                    <Form.Item label=" ">
                        <Button type="primary" htmlType="submit">
                            搜索图书
                        </Button>
                        <Button type="primary" htmlType="submit" style={{background: 'green'}} >
                            添加图书
                        </Button>
                    </Form.Item>
                </Form>
            </div>
            <div className="book-list">
                {
                    bookList.map(book => {
                        return <Card
                            className='card'
                            hoverable
                            style={{ width: 300 }}
                            cover={<img alt="example" src={`http://localhost:3000/${book.cover}`} />}
                        >
                            <h2>{book.name}</h2>
                            <div>{book.author}</div>
                            <div className='links'>
                                <a href="#">详情</a>
                                <a href="#">编辑</a>
                                <a href="#">删除</a>
                            </div>
                        </Card>
                    })
                }    
            </div>
        </div>
    </div>
}
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

我现在服务端的 books.json 是这样的:

[
  {
    "id": 328555,
    "author": "曹雪芹",
    "name": "红楼梦",
    "description": "这是中国古代四大名著之一,被认为是中国文学的巅峰之作。它以贾、史、王、薛四大家族的婚姻和命运为线索,描绘了中国封建社会的荣辱兴衰、人情世故、爱恨情仇等。",
    "cover": "uploads/1721191961112-224327292-qiong.png"
  },
  {
    "id": 281167,
    "author": "施耐庵",
    "name": "水浒传",
    "description": "这是中国古代四大名著之一,以108位好汉的故事为主线,反映了宋朝末年民变斗争与各阶层人民的痛苦生活。该作品强调了义气、反抗不平等待遇等社会主题。",
    "cover": "uploads/1721191961112-224327292-qiong.png"
  },
  {
    "id": 197528,
    "author": "吴承恩",
    "name": "西游记",
    "description": "这是中国古代四大名著之一,讲述了唐僧师徒四人西天取经、斩妖除魔的故事。作品深入探讨了佛教和道教的思想,同时也展示了人性的善恶之间的斗争。",
    "cover": "uploads/1721191961112-224327292-qiong.png"
  }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

看下效果:

可以看到,图书列表加载并渲染了出来。

# 添加搜索功能

然后来实现下搜索,之前的 list 接口没支持搜索,我们改造下:

在 /book/list 接口添加一个 name 参数。

@Get('list')
async list(@Query('name') name: string) {
    return this.bookService.list(name);
}
1
2
3
4

然后在 BookService 里实现下搜索:

async list(name: string) {
    const books: Book[] = await this.dbService.read();
    return name ? books.filter(book => {
        return book.name.includes(name);
    }) : books;
}
1
2
3
4
5
6

在 postman 里测试下:

当没传参数时:

传 name=西 时:

传 name=水 时:

然后我们在前端代码里调用下:

export async function list(name: string) {
    return await axiosInstance.get('/book/list', {
        params: {
            name
        }
    });
}
1
2
3
4
5
6
7

当 form 提交的时候,修改 name 的 state,然后 name 的 state 改变触发重新搜索。

import { Button, Card, Form, Input, message } from 'antd';
import './index.css';
import { useEffect, useState } from 'react';
import { list } from '../../interfaces';

interface Book {
    id: number;
    name: string;
    author: string;
    description: string;
    cover: string;
}

export function BookManage(){

    const [bookList, setBookList] = useState<Array<Book>>([]);
    const [name, setName] = useState('');

    async function fetchData() {
        try {
            const data = await list(name);
            
            if(data.status === 201 || data.status === 200) {
                setBookList(data.data);
            }
        } catch(e: any) {
            message.error(e.response.data.message);
        }
    }

    useEffect(() => {
        fetchData();
    }, [name]);

    async function searchBook(values: { name: string}) {
        setName(values.name);
    }

    return <div id="bookManage">
        <h1>图书管理系统</h1>
        <div className="content">
            <div className='book-search'>
                <Form
                    onFinish={searchBook}
                    name="search"
                    layout='inline'
                    colon={false}
                >
                    <Form.Item label="图书名称" name="name">
                        <Input />
                    </Form.Item>
                    <Form.Item label=" ">
                        <Button type="primary" htmlType="submit">
                            搜索图书
                        </Button>
                        <Button type="primary" htmlType="submit" style={{background: 'green'}} >
                            添加图书
                        </Button>
                    </Form.Item>
                </Form>
            </div>
            <div className="book-list">
                {
                    bookList.map(book => {
                        return <Card
                            className='card'
                            hoverable
                            style={{ width: 300 }}
                            cover={<img alt="example" src={`http://localhost:3000/${book.cover}`} />}
                        >
                            <h2>{book.name}</h2>
                            <div>{book.author}</div>
                            <div className='links'>
                                <a href="#">详情</a>
                                <a href="#">编辑</a>
                                <a href="#">删除</a>
                            </div>
                        </Card>
                    })
                }    
            </div>
        </div>
    </div>
}
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

测试下:

案例代码上传了小册仓库 (opens new window)

# 总结

这节我们新增了图书列表页面,改造了 /book/list 接口支持搜索,然后在前端项目调用,实现了图书列表和搜索。

下节我们继续实现增删改的功能。

编辑 (opens new window)
上次更新: 2025/5/7 18:16:53
图书管理系统:用户模块前端开发
图书管理系统:图书增删改前端开发

← 图书管理系统:用户模块前端开发 图书管理系统:图书增删改前端开发→

最近更新
01
IoC 解决了什么痛点问题?
03-10
02
如何调试 Nest 项目
03-10
03
Provider注入对象
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式