今天教大家在 Vue3 项目中手搓一个useTable 表格 Hooks,可以大大提高代码的复用性!文末会包含完整代码!
1.列表页面重复代码
我们在开发 Vue3 项目的列表页面时,经常会用到表格组件。
如果项目存在多个列表页面,通常会有以下重复代码:
- 1.分页数据查询
// 获取分页列表数据
const gePageList = async () => {
const res = await userApi.gePageList(searchForm);
tableData.value = res.data.data.records;
total.value = res.data.data.total;
};
- 2.分页切换页码查询
const handleCurrentChange = (current) => {
searchForm.current = current;
gePageList();
};
- 3.分页切换页面 size 查询
const handleSizeChange = (size) => {
searchForm.size = size;
gePageList();
};
- 4.删除操作 / 批量删除操作
const handleDelete = async (ids) => {
const res = await orderApi.delOrder(ids);
if (res.data.code == 200) {
ElMessage.success("删除成功");
} else {
ElMessage.error("删除失败");
}
};
在 Vue3 项目中,我们可以自定义 Hooks 复用这些代码。
2. 开发思路
开发环境:
- 代码编辑器使用 Vscode
- Vite 创建 Vue3 项目
- 前端组件库使用 ElementPlus
- http 组件库使用 axios
首先我们要定义一个 Hooks: useTable.js

需求分析:
- 1.根据页面传递的列表 api 查询列表数据,Hooks 在请求数据时显示 loading 效果。
- 2.Hooks 要根据页面传递的 page 和 size 进行分页查询
- 3.Hooks 要根据页面传递的查询参数查询列表数据
- 4.页面将选中的数据传递给 Hooks,Hooks 根据页面传递的删除 api 和 id 列表删除数据
Hook 设计:
- 1.接收参数:列表 api、删除 api、查询参数、分页参数
- 2.输出数据:表格参数、分页对象、搜索函数、按页搜索函数、按size 搜索函数、删除函数、选中数据
- 3.Hooks 内部实现:获取列表数据、根据搜索参数查询列表数据、管理分页各种操作、删除操作
3.代码实现
3.1首先导入封装好的 http 和 ElementUI 一些组件

3.2 然后用一个变量接收页面传递的参数
const {
pageUrl,// 后台列表 url
delUrl,// 后台删除 url
searchParams = {}, // 初始条件查询参数
pagination = { current: 1, size: 10 }, // 分页配置
} = options;
3.3 定义和表格相关的变量
// 表格数据
const tableData = ref([]);
// 加载状态
const loading = ref(false);
// 分页信息
const paginationInfo = reactive({
current: pagination.current,
size: pagination.size,
total: 0,
});
// 选中的行
const selectedRows = ref([]);
3.4 定义和搜索相关的函数
// 获取数据
const fetchData = async () => {
loading.value = true;
try {
const params = {
...searchParams,
current: paginationInfo.current,
size: paginationInfo.size,
};
const res = await http.get(pageUrl, params);
tableData.value = res.data.data.records;
paginationInfo.total = res.data.data.total;
selectedRows.value = []; // 重置选中状态
} catch (error) {
console.error("数据加载失败:", error);
} finally {
loading.value = false;
}
};
// 搜索
const handleSearch = () => {
paginationInfo.current = 1;
fetchData();
};
// 切换页码搜索
const handlePageChange = (page) => {
paginationInfo.current = page;
fetchData();
};
// 切换 size 搜索
const handleSizeChange = (size) => {
paginationInfo.size = size;
fetchData();
};
3.5 定义删除函数
// 删除操作
const handleDelete = async (ids) => {
try {
ElMessageBox.confirm(`确定要删除用户信息吗?`, {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
const res = await http.post(delUrl, ids);
if (res.data.code == 200) {
ElMessage.success("删除成功");
} else {
ElMessage.error("删除失败");
}
})
.catch(() => {
ElMessage({
type: "info",
message: "取消删除",
});
})
.finally(() => {
selectedRows.value = [];
fetchData();
});
} catch (error) {
console.error("删除失败:", error);
}
};
3.6 初始化列表数据
// 初始化数据
onMounted(() => {
fetchData();
});
3.7 return 数据
return {
tableData,
loading,
paginationInfo,
selectedRows,
handleSearch,
handlePageChange,
handleSizeChange,
handleDelete,
};
4.使用案例
user.vue 页面:
案例中查询参数为 name,大家可以根据实际需要自行添加。
<template>
<div>
<el-card>
-- 查询条件 -->
<el-form inline:model="searchForm" ref="searchFormRef">
<el-form-item label="姓名:"prop="name">
<el-input
@clear="handleSearch"
clearable
v-model="searchForm.name"
placeholder="请输入姓名"
>
"primary" icon="Search" @click="handleSearch">搜索
"Refresh" @click="resetSearch">重置
"margin: 20px 0px">
"primary"> 新增
<el-button
type="danger"
@click="handleBatchDelete"
:disabled="selectedRows.length === 0"
>
批量删除
<el-table
border
ref="tableRef"
:data="tableData"
:loading="loading"
@selection-change="(val) => (selectedRows = val)"
>
"selection" width="55" />
"id" label="ID" />
"username" label="昵称" />
"name" label="姓名" />
"age" label="年龄" />
"操作">
"scope">
"danger" @click="handleDelete([scope.row.id])"
>删除</el-button
>
<el-pagination
style="margin-top: 20px"
:current-page="paginationInfo.current"
:page-size="paginationInfo.size"
:page-sizes="[10, 20, 30, 40]"
layout="->,total, sizes, prev, pager, next, jumper"
:total="paginationInfo.total"
@size-change="handleSizeChange"
@current-change="handlePageChange"
/>
声明:本站原创文章文字版权归本站所有,转载务必注明作者和出处;本站转载文章仅仅代表原作者观点,不代表本站立场,图文版权归原作者所有。如有侵权,请联系我们删除。