背景
在后台管理系统中充斥着大量的搜索+表格的页面,需要重复定义
loading
,page
,tableData
getData()
等变量或方法,急需封装一个hook减少重复工作,useTable是最好的选择.
hook封装
hook接收请求地址,请求参数等参数,实现请求数据功能,并返回分页,数据类别,加载状态
formatParams:
请求参数params解构后将不能动态获取form的变化,所有定义了formatParams方法用于修改入参
formatResult:
处理请求返回的列表,并将格式化后的结果保存到tableData中,当然也你可以在onSuccess的回调中处理
onSuccess:
请求成功的回调
pagination:
用于分页,分页改变后将自动重新请求
useList.js 完整代码
js
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 })
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, () => getData())
//初始化请求
onMounted(() => immediate && getData())
return { loading, tableData, pagination, getData }
}
使用示例
UI框架使用Ant Design Vue
,示例省略部分代码
html
<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" @change="(page) => (pagination = page)" />
</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, //请求入参 此处必须为ref对象,且不能解构
formatParams: (params) => { //格式化入参
return {
...params,
startDate: params['range-picker'][0],
endDate: params['range-picker'][1]
}
},
formatResult: (res) => { //格式化结果
//...
},
onSuccess: (res) => { //成功回调
//...
}
})
</script>
对比
在不使用useTable的情况下,代码如下,可以看出封装useTable大大减少重复工作,不用在每个表格下定义分页和loading,而且代码更简洁易懂。
html
<template>
<a-form :model="formState">
...
</a-form>
<a-table
:loading="loading"
:columns="columns"
:data-source="tableData"
:pagination="page"
@change="onPageChange"
/>
</template>
<script setup>
import { ref, getData } from 'vue'
import useTable from './useTable'
import columns from './columns'
import { post } from '@/utils/request'
const loading = ref(false)
const tableData = ref([])
const formState = ref({})
const page = ref({ total: 0, current: 1, pageSize: 10 })
//请求数据
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: page.value.current,
pageSize: page.value.pageSize
})
loading.value = false
if (code !== 0) return
tableData.value = data
page.value.total = total
}
//分页改变
const onPageChange = ({ current, pageSize }) => {
page.value.current = current
page.value.pageSize = pageSize
getData()
}
//初始化请求
onMounted(() => getData())
</script>
结尾
如有更好的意见或建议,欢迎留言探讨