背景
在后台管理系统中充斥着大量的搜索+表格的页面,需要重复定义
loading
,page
,tableData
getData()
等变量或方法,急需封装一个hook减少重复工作,useTable是最好的选择.
hook封装
hook接收请求地址,请求参数等参数,实现数据请求功能,分页改变自动请求,并返回分页,数据列表,加载状态等。
-
formatParams
请求参数params解构后将不能动态获取form的变化,所有定义了formatParams方法用于修改入参 -
formatResult
处理请求返回的列表,并将格式化后的结果保存到tableData中,当然也你可以在onSuccess的回调中处理 -
onSuccess
请求成功的回调 -
pagination
用于分页,分页改变后将自动重新请求
useList.js 完整代码
代码更新,感谢评论区@VOLUN的指导,onChange事件转移至useTable中,使用时更加简洁
import { onMounted, ref, watch } from 'vue'
import { post } from '@/utils/request'
import { message } from 'ant-design-vue'
/**
* @name: useTable
* @description: 获取列表数据
*/
export default function ({ url, params, formatParams, formatResult, onSuccess, immediate }) {
const loading = ref(false)
const pagination = ref({
total: 0,
current: 1,
pageSize: 10,
onChange: (pageNum, pageSize) => {
pagination.value.current = pageNum
pagination.value.pageSize = pageSize
}
})
const tableData = ref([])
//请求部分需结合具体项目修改
const getData = async () => {
loading.value = true
const { code, data, msg, total } = await post(url, {
...(formatParams ? formatParams(params) : params),
pageNum: pagination.value.current,
pageSize: pagination.value.pageSize
})
loading.value = false
if (code !== 0) return message.error(msg || '请求失败')
tableData.value = formatResult ? formatResult(data) : data
pagination.value.total = total
onSuccess && onSuccess(data)
}
//分页改变
watch(
() => pagination.value.current,
() => getData()
)
watch(
() => pagination.value.pageSize,
() => {
pagination.value.current = 1
getData()
}
)
//初始化请求
onMounted(() => immediate && getData())
return { loading, tableData, pagination, getData }
}
useTable文档
参数
参数 | 类型 | 说明 | 默认值 |
---|---|---|---|
immediate | boolean | 是否立即请求 | true |
pagination | boolean | 是否分页 | true |
url | string | 请求地址 | - |
params | ref | 请求参数 | - |
formatParams | function | 格式化入参 | (params)=>{} |
formatResult | function | 格式化出参 | (result)=>{} |
onSuccess | function | 成功回调 | (result)=>{} |
返回值
参数 | 类型 | 说明 | 默认值 |
---|---|---|---|
loading | boolean | 加载中 | true |
tableData | array | 表格数据 | [] |
pagination | object | 分页对象 | - |
getData | function | 手动请求方法 | - |
使用示例
UI框架使用Ant Design Vue
,示例省略部分代码
<template>
<a-form :model="formState">
<a-form-item name="key" label="名称">
<a-input v-model:value="formState.name" placeholder="请输入" />
</a-form-item>
<a-form-item name="stdate" label="日期范围">
<a-range-picker v-model:value="formState['range-picker']" />
</a-form-item>
</a-form>
<a-table :loading="loading" :columns="columns" :data-source="tableData" :pagination="pagination" />
</template>
<script setup>
import { ref } from 'vue'
import columns from './columns'
import useTable from './useTable'
const formState = ref({})
const { loading, tableData, pagination, getData } = useTable({
url: '/api/xxxxx',
immediate: true,
params: formState.value,
formatParams: (params) => {
return {
...params,
startDate: params['range-picker'][0],
endDate: params['range-picker'][1]
}
}
})
</script>
对比
在不使用useTable的情况下,代码如下,可以看出封装useTable大大减少重复工作,不用在每个表格下定义分页和loading,而且代码更简洁易懂。
<template>
<a-form :model="formState">
<a-form-item label="名称">
<a-input v-model:value="formState.name" placeholder="请输入" />
</a-form-item>
<a-form-item label="日期范围">
<a-range-picker v-model:value="formState['range-picker']" />
</a-form-item>
</a-form>
<a-table
:loading="loading"
:columns="columns"
:data-source="tableData"
:pagination="pagination"
- @change="onPageChange"
/>
</template>
<script setup>
import { ref, getData } from 'vue'
import columns from './columns'
import { post } from '@/utils/request'
+ import useTable from './useTable'
- const loading = ref(false)
- const pagination = ref({ total: 0, current: 1, pageSize: 10 })
const tableData = ref([])
const formState = ref({})
+ const { loading, tableData, pagination, getData } = useTable({
+ url: '/api/xxxxx',
+ immediate: true,
+ params: formState.value,
+ formatParams: (params) => {
+ return {
+ ...params,
+ startDate: params['range-picker'][0],
+ endDate: params['range-picker'][1]
+ }
+ }
+ })
- const getData = async () => {
- loading.value = true
- const { code, data, total } = await post('/api/xxxx', {
- ...formState.value,
- startDate: formState.value['range-picker'][0],
- endDate: formState.value['range-picker'][1],
- pageNum: pagination.value.current,
- pageSize: pagination.value.pageSize
- })
- loading.value = false
- if (code !== 0) return
- tableData.value = data
- pagination.value.total = total
- }
- const onPageChange = ({ current, pageSize }) => {
- pagination.value.current = current
- pagination.value.pageSize = pageSize
- getData()
- }
- onMounted(() => getData())
</script>
结尾
如有更好的意见或建议,欢迎留言探讨