封装axios使用AntdVue实现分页查询
在日常开发的时候经常会使用到分页的功能,Antd自带的表格本身就具有分页的功能,但是实际开发中如果后端给我们返回了上万条数据,那么再由前端进行分页是不现实的,所以还是需要后端返回具体的参数来帮助前端进行分页。
本文使用vue3
组合式API配合setup
语法糖来编写。可以直接复制完整代码
只需要两步,第一步获取数据,第二步渲染数据到页面上,但是这两步里又包含了很多小的步骤,才能成功的达到我们的需求。
1.封装axios
分步解析
首先,我们需要封装axios
请求,这样才能更方便的获取多个接口。为什么需要封装呢,请观察以下几个链接
https://antdv.com/components/overview-cn
https://antdv.com/docs/vue/introduce-cn
https://antdv.com/components/pagination-cn/#api
他们都有相同的域名,https://antdv.com/
,所以我们需要把这个域名当作基础路径,然后再把其他路径直接拼接上去就可以了。
首先在vscode里建一个包utils
,再建立一个文件request.js
import axios from "axios";
const axiosInstance = axios.create({
baseURL: "填入你的项目的域名",
});
export default axiosInstance;
这段代码意思是,使用axios
库创建了一个名为axiosInstance
的实例,这个实例使用create
方法来配置一个baseURL
,然后默认到处这个实例,这样我们就能在其他地方使用了。
然后再创建一个services
包,再建立一个文件menu.js
里面放我们需要访问的接口路径
import request from "../utils/request.js";
const api = {
getMenuListByPage: "/menuListByPage"
};
export const getMenuListByPage = (params = {}) => {
return request({ url: api.getMenuListByPage, method: "get", params });
}
由于request.js
使用的是默认导出,所以导入的时候可以随意更改名字,且不需要加{}
,意味着不叫request
也可以,随便叫什么名字。
然后我们将路径放入api
这个对象中。
return request({ url: api.getMenuListByPage, method: "get", params });
这行代码定义了一个名为getMenuListByPage
的函数,它接受一个名为params
的参数,如果没有传入参数,则默认为一个空对象{}
。
在函数内部,它调用了一个名为request
的函数,传入了一个包含url
、method
和params
的对象作为参数。其中url
来自一个名为api.getMenuListByPage
的变量,method
为"get",params
为传入的参数。
实际上,这段代码调用一个名为request
的函数,该函数负责发起HTTP请求,从而获取菜单列表。通过api.getMenuListByPage
这个变量来存储API的URL。
到这里我们就可以获取到后端传过来的数据了,但还不是太完美,原因是后端在返回数据的时候,会将数据包裹在一个对象中,而axios
会默认将整个返回的对象作为response.data
,因此实际上当我们获取数据的时候,实际上是需要通过response.data.data
才能获取到实际的数据,所以我们可以在request.js
里增加拦截器来解决这个问题。
增加request.js
的代码
axiosInstance.interceptors.response.use(
function (response) {
return response.data
},
function (error) {
return Promise.reject(error)
},
)
这样我们就能少.
一层data
了
完整代码
request.js
import axios from "axios";
const axiosInstance = axios.create({
baseURL: "你自己项目的域名",
});
axiosInstance.interceptors.response.use(
function (response) {
return response.data
},
function (error) {
return Promise.reject(error)
},
)
export default axiosInstance;
menu.js
import request from "../utils/request.js";
const api = {
getMenuListByPage: "/menuListByPage"
};
export const getMenuListByPage = (params = {}) => {
return request({ url: api.getMenuListByPage, method: "get", params });
}
2.渲染数据到表格上
分步解析
表格 Table - Ant Design Vue (antdv.com)
antd
的表格要求两个值 一个是需要指定表的数据源,另外一个是指定表头。
搭好vue
基本结构后,配置好表头的内容
const columns = [
{
title: '菜名',
dataIndex: 'name'
},
{
title: '价格',
dataIndex: 'price'
}
]
文档里的实例你会看见表格上还需写key
值,不过文档也说了如果已经设置了唯一的 dataIndex
,可以忽略这个属性。详情可见api
文档
然后我们获取数据
import { getMenuListByPage } from '../services/menu';
导入我们定义好的函数,由于menu.js
使用的是具名导出,所以导入必须是使用导出使用的名字,且需要加上{}
。
然后再编写一个方法来调用,并赋值到我们实现定义好的变量上。最后再把columns
和data
配置到表格上
const getData = async () => {
const res = await getMenuListByPage();
data.value = res.data.record
}
完整代码
<template>
<div>
<Table :columns="columns" :dataSource="data"></Table>
</div>
</template>
<script setup lang="ts">
import { Table } from 'ant-design-vue';
import { getMenuListByPage } from '../services/menu';
import { ref } from 'vue';
const columns = [
{
title: '菜名',
dataIndex: 'name'
},
{
title: '价格',
dataIndex: 'price'
}
]
const data = ref([])
const getData = async () => {
const res = await getMenuListByPage();;
data.value = res.data.record
}
getData();
</script>
<style scoped></style>
此时数据已经渲染到了界面上。
如图所示,我们打印res
到控制台看看后端返回的数据长什么样子。
解释了为什么需要res.data.record
才能取出我们真正需要渲染的数据。并且请注意后端返回的其他值
pageNumber
代表现在是第几页
pageSize
代表一页显示多少条数据
totalItems
代表返回的总数据数量
totalPages
代表返回的总数/一页可以显示的数据,算出的可以分为多少页
由于后端限定了一页显示多少条数据,所以前端渲染出的页面就只有10条数据。
3.实现分页逻辑
分布解析
如果说我们想要实现分页逻辑,那么我们先看看antd
的API
文档
这里的意思是,table
组件上有个pagination
供我们进行分页功能,有设置为false
不展示分页,或者提供一个对象来进行分页。
我们点击pagniation
的组件文档来看可以提供哪些参数。
这里我们只需要把目光集中于以下几个参数,total(数据总数)
,current(当前页数)
,pageSize(每页条数)
即可
因为后端返回的参数中就有这些,只是名字不一样而已。
这意味着,只要我们把current
和pageSize
传给后端,那么后端就会根据我们提供的参数,再重新返回值让我们渲染表格。
刚刚提到如果table
需要使用到pagniation
参数就需要传入一个对象,于是我们编写一个对象,里面包含total(数据总数)
,current(当前页数)
,pageSize(每页条数)
这三个参数
<Table
:columns="columns"
:dataSource="data"
:pagination="page"
></Table>
由于这些数据都是会经常变化的,所以我们需要把它们定义成响应式的数据。
const page = ref({
current: 1,
pageSize: 5,
total: 0 //还不知道后端返回的总数会是多少
})
然后再在getMenuListByPage
传入当前我们设定的current(当前页数)
和pageSize(每页条数)
const getData = async () => {
const res = await getMenuListByPage({
pageNumber: page.value.current,//由于前端和后端定义的字段名称不一样所以需要映射一下
pageSize: page.value.pageSize //这里的代码意思是把page.pageSize的值传给pageSize
});;
data.value = res.data.record
page.value.total = res.data.totalItems
}
antd
自动给我们分出四页,不需要我们再获取了。但此时点击2,3,4发现页面的数据并没有变化,原因是因为,虽然我们传入了我们定义的数据,但此时当我们点击的时候,current(当前页数)
也随之改变,但是我们并没有监听到,于是就还是使用的我们写死了的数据 current: 1,
所以我们要使用方法来监听数据,并将改变后的数据再重新发送请求。
查看文档我们发现有这样一个事件,在分页的时候会触发,回调参数是指,在这个事件发生的时候,系统会自动调用先定义好的函数,然后再把相关的参数传递给这个函数。
我们可以打印出来看看
可以看到当我们点击第二页的时候,这个事件被触发,并返回我们定义的page
对象里所有参数,可以看到此时current
改变已经被我们监听到,此时将这个对象再赋给page
,然后我们再调用一次getData();
就能重新发送请求
const handleChange = (obj) => {
page.value = obj;
getData()
}
达到目的
完整代码
<template>
<div>
<Table :columns="columns" :dataSource="data" :pagination="page" @change="handleChange"></Table>
</div>
</template>
<script setup>
import { Table } from 'ant-design-vue';
import { getMenuListByPage } from '../services/menu';
import { reactive, ref } from 'vue';
const columns = [
{
title: '菜名',
dataIndex: 'name'
},
{
title: '价格',
dataIndex: 'price'
}
]
const data = ref([])
const page = ref({
current: 1,
pageSize: 5,
total: 0,
})
const getData = async () => {
const res = await getMenuListByPage({
pageNumber: page.value.current,
pageSize: page.value.pageSize
});;
data.value = res.data.record
page.value.total = res.data.totalItems
console.log(res);
}
getData();
const handleChange = (obj) => {
page.value = obj;
getData()
}
</script>
<style scoped></style>