从零开始,搭建一个简单的购物平台(七)
从零开始,搭建一个简单的购物平台(六):https://blog.csdn.net/time_____/article/details/105440818
项目源码(持续更新):https://gitee.com/DieHunter/myCode/tree/master/shopping
到现在为止,项目前后端功能已实现登录,token获取验证,上传头像,添加用户,这篇文章主要讲述实现前后端用户列表分页查找,模糊查询,用户列表渲染功能
- 首先是分页查找,后端实现方式通过数据库查找表的长度,配合数据库函数skip(n)(跳过前n条数据),和limit(m)(向后查找m条数据),通过db.find().skip((page - 1) * pageSize).limit(pageSize)(page代表第几页,从0开始,第一页则不需要跳过。pageSize表示分页后每页数据条数),所以我们在command.js中新建两个方法,用于查询表的长度和关键字查询并分页
/* 查询分页
* @param {object} mod 数据库model
* @param {number} sort 排序顺序 负数倒序 正数顺序
* @param {number} page 当前页数
* @param {number} pageSize 分页大小
* @param {object} pageSize 关键字模糊查询
*/
static async findByPage(mod, sort, page, pageSize, keyWord) {
//分页查
return await mod
.find(keyWord)
.sort(sort)
.skip((page - 1) * pageSize)
.limit(pageSize);
}
/* 查询分页
* @param {object} mod 数据库model
* @param {number} pageSize 分页大小
*/
static async getTotalPage(mod, pageSize) {
let allNum = await mod.find().estimatedDocumentCount();
return { totalPage: parseInt(allNum / pageSize) + 1, allNum };
}
- 在users.js中添加获取用户列表的接口,通过电子邮件或者用户名查找,分页
router.get(Config.ServerApi.userList, Util.checkToken, async (req, res) => {
if (res._data.userTokenType != "admin") {
//非管理员
res.send({
result: -999,
msg: "请用管理员账号登录",
});
return;
}
let total = await getTotalPage(Mod, res._data.pageSize);
let query = new RegExp(res._data.keyWord, "i"); //模糊查找正则条件
res.send({
result: 1,
data: {
page: res._data.page,
pageSize: res._data.pageSize,
totalPage: total.totalPage,
allNum: total.allNum,
list: await findByPage(
Mod,
{
time: res._data.sort,
},
res._data.page,
res._data.pageSize,
res._data.keyWord.length
? {
$or: [
{
mailaddress: query,
},
{
username: query,
},
],
}
: {}
),
},
msg: "查找成功",
});
});
后端部分实现完成后,开始编写前端,需要用到表格组件,分页组件和input查找组件,这里可以将表格组件单独写出来,写成我们自己的组件,以供后期商品列表重复使用
- 先配置一下用户表格字段,封装到一个class里
import React from "react";
import {
Button,
Popconfirm,
} from "antd";
import config from "../../config/config";
const { FilePath } = config;
export default class UserTable {
constructor(_this) {
return [
{ align: "center", title: "用户名", dataIndex: "username", width: 200 },
{
align: "center",
title: "邮箱",
dataIndex: "mailaddress",
width: 200,
render: (text, data) => {
return <div>{text + data.mailurl}</div>;
},
},
{
align: "center",
title: "密码",
dataIndex: "password",
width: 300,
},
{
align: "center",
title: "头像",
dataIndex: "headPic",
width: 150,
render: (imgPath) => {
return (
<img
src={FilePath + imgPath}
alt=""
style={{ width: 60, margin: "0 auto" }}
/>
);
},
},
{
align: "center",
title: "性别",
dataIndex: "sex",
width: 200,
render: (sex) => {
return <div>{sex == "man" ? "男" : "女"}</div>;
},
},
{
align: "center",
title: "收货地址",
dataIndex: "alladdress",
width: 200,
render: (text, data, index) => {
return <div>{text.join("-") + data.address}</div>;
},
},
{
align: "center",
title: "个性签名",
dataIndex: "descript",
width: 200,
},
{
align: "center",
title: "用户类型",
dataIndex: "userType",
width: 200,
render: (type) => {
return <div>{type == "admin" ? "管理员" : "用户"}</div>;
},
},
{
align: "center",
title: "注册时间",
dataIndex: "time",
width: 200,
},
];
}
}
- 在表格渲染前判断一下表格类型,是显示用户还是商品,达到组件复用功能,将分页组件与pageconfig绑定,达到切换页面的效果
import React from "react";
import {
Table,
Button,
Card,
Pagination,
Input,
Col,
Row,
} from "antd";
import userTab from "./userTab";
import { PlusOutlined } from "@ant-design/icons";
const { Search } = Input;
export default class ListTable extends React.Component {
state = {
tableType: this.props.tableType,
pageConfig: {
totalPage: 0,
page: 0,
pageSize: 0,
allNum: 0,
},
columns: [],
list: [],
};
componentDidMount() {
if (this.state.tableType == "user") {
this.setState({
columns: new userTab(this)
});
} else {
}
this.props.onTableRef(this);
}
render() {
return (
<Card title="用户列表">
<Row gutter={16}>
<Col span={12}>
<Button onClick={this.props.showDrawer} type="primary">
<PlusOutlined />
新增用户
</Button>
</Col>
<Col span={12}>
<Search
style={{ float: "right" }}
placeholder="输入用户名/邮箱"
enterButton="查找"
size="large"
allowClear
onSearch={(val) => {
let { pageConfig } = this.state;
pageConfig.keyWord = val;
this.setState({
pageConfig,
});
this.props.changePage(pageConfig);
}}
/>
</Col>
</Row>
<Table
scroll={{ x: 2000 }}
rowKey={(record) => record._id}
columns={this.state.columns}
dataSource={this.state.list}
pagination={false}
></Table>
<Pagination
style={{ marginTop: 50 }}
hideOnSinglePage
total={this.state.pageConfig.allNum}
current={this.state.pageConfig.page}
pageSize={this.state.pageConfig.pageSize}
showSizeChanger
showQuickJumper
showTotal={(total) => `共 ${total} 条`}
onChange={this.changePage}
onShowSizeChange={this.changePage}
/>
</Card>
);
}
changePage = (page, pageSize) => {
let pageConfig = this.state.pageConfig;
pageConfig.page = page;
pageConfig.pageSize = pageSize;
this.setState({
pageConfig,
});
this.props.changePage(pageConfig);
};
}
- 最后在userlist中调用,与表格中的page达到一个数据双向绑定效果
import React from "react";
import ListTable from "../../../components/table/table";
import {
message,
} from "antd";
import config from "../../../config/config";
const { ServerApi, StorageName } = config;
export default class UserList extends React.Component {
state = {
userType: "adduser",
pageConfig: {
token: this.$utils.getStorage(StorageName.token),
keyWord: "",
page: 1,
pageSize: 2,
totalPage: 1,
sort: 1,
},
};
componentDidMount() {
this.getUserList();
}
render() {
return (
<div>
<ListTable
tableType="user"
onTableRef={(child) => {
this.tableChild = child;
}}
showDrawer={this.showDrawer}
changePage={this.changePage}
></ListTable>
<ListDrower
getUserList={this.getUserList}
userType={this.state.userType}
onDrowerRef={(child) => {
this.drawerChild = child;
}}
></ListDrower>
</div>
);
}
showDrawer = () => {
this.drawerChild.showDrawer();
};
changePage = (pageConfig) => {
this.setState({ pageConfig });
this.getUserList();
};
getUserList = () => {
let data = { ...this.state.pageConfig };
this.$axios
.get(ServerApi.user.userList, {
params: { crypto: this.$crypto.setCrypto(data) },
})
.then((res) => {
let { list, totalPage, allNum } = res.data;
let { pageConfig } = this.state;
pageConfig.allNum = allNum;
pageConfig.totalPage = totalPage;
this.tableChild.setState({ pageConfig, list });
})
.catch((err) => {});
};
}
- 全部完成后,测试一下
总结
在组件化开发的前端代码中,组件复用可以使代码可维护性提升,通过修改state或者初始状态值对相对应的组件进行使用,大大提升代码效率