一、组件初始化阶段
1、初始化响应式状态对象:tablebody。
2、核心状态:
表格高度 ( tableHeight )
数据加载状态 ( tableLoading )
表格数据 ( tableList )
总条数 ( total )
分页参数 ( params ):设置默认分页参数。(第1页,每页50条)
const tableBody = reactive<stateType>({
tableHeight: 600,
showTable: true,
tableLoading: false,
tableList: [],
total: 0,
params: {
pageNum: 1,
pageSize: 50, // 默认每页50条
},
});
二、表单和表格配置
1、表单字段:
通过 getFormFields 获取表单配置:
const formDataModel = reactive({});
const formData = computed(() => ({
showButtons: false,
confirmText: '查询',
model: formDataModel, // 绑定表单数据模型
fields: getFormFields(), // 获取表单字段配置
}));
getFormFields() 返回的表单配置:
[
{ prop: 'dw', type: 'input', placeholder: '单位' },
{ prop: 'yd', type: 'datePicker', placeholder: '月度' }
]
2、表格列:
通过 getTableColumn 获取表格列配置:
const tableColumn = getTableColumn();
三、组件挂载自动加载数据
onMounted(init); // 组件挂载时触发数据加载
const init = () => {
getTableList();
};
四、核心数据获取方法
const getTableList = async () => {
try {
tableBody.tableLoading = true;
// 合并分页参数和表单参数
const params = {
...tableBody.params,
...formDataModel
};
const res: any = await getInfoApi(params);
if (res.status === 200) {
tableBody.tableList = res.data.records || [];
tableBody.total = res.data.total ? Number(res.data.total) : 0;
} else {
ElMessage.warning(res.message);
}
} finally {
tableBody.tableLoading = false;
}
};
注:其中 res.status 的 status 为状态名,
不同接口可能会有不同的状态名(如code等),所以需要根据不同情况进行修改 。
1、参数合并策略
const params = {
...tableBody.params, // 分页参数 { pageNum: 1, pageSize: 50 }
...formDataModel // 表单参数 { dw: '单位A', yd: ['2023-01', '2023-06'] }
};
合并后的请求参数示例:
{
"pageNum": 1,
"pageSize": 50,
"dw": "单位A",
"yd": ["2023-01", "2023-06"]
}
2、多种解构方式
功能/解构方式 | 直接解构:data.rows | 对象访问:res.data.rows |
API调用 | const { data, code, message } = await pageApi(params); |
const res: any = await getInfoApi(params); |
状态码检查 | if (code === 200) | if (res.status === 200) |
数据赋值 | tableBody.tableList = data.rows; | tableBody.tableList = res.data.records; |
3、响应数据处理
1.直接赋值
特点:保持原始结构 + 分页信息。
其中records要与接口返回的数组名一致。
如若是"list": [...],那么就得是res.data.list。
tableBody.tableList = res.data.records || []; // 表格数据
tableBody.total = Number(res.data.total) || 0; // 总数
假设后端返回数据结构:
{
"status": 200,
"data": {
"records": [...], // 当前页数据
"total": 1250 // 总记录数
}
}
2.字段映射
特点:必须转换 + 空安全
orgTypeList.value = (data as OrgItem[]).map(item => ({
label: item.name,
value: item.id,
转换过程:
// 原始数据
[{ name: "米哈油", id: "org-001" }]
// 转换后(丢弃id,保留label/value)
[{ label: "米哈油", value: "org-001" }]
为什么一定要转换为 { label, value } 格式?
- 适配 UI 组件的数据格式
- 统一处理逻辑
- 减少不必要的数据处理
- 清晰分离显示值与存储值
在少数简单场景下可以直接使用原始数据:
- 纯字符串/数字的简单列表
- 组件明确支持自定义字段映射
五、用户交互触发点
1、查询按钮
const submitHandler = () => {
console.log('Form Data Model:', formDataModel);
init(); // 触发数据加载
};
2、数据统计按钮
const dataStatistics = () => {
init(); // 同样触发数据加载
};
3、表格刷新/分页
注:该代码所在文件位置:index.vue。
<!-- Template中 -->
<table-operate @on-refresh="getTableList"/>
<free-table @pagination="getTableList"/>
六、动态列显示
按需求选择哪些列显示,哪些列不显示。
1. 表格操作组件引用index
<table-operate
ref="tableOperateRef"
:table-column="tableColumn"
@on-refresh="getTableList">
</table-operate>
2. 动态列计算属性hooks
const realTableColumn = computed(() =>
tableOperateRef.value?.realTableColumn ?? []
);
3. 表格组件绑定index
<free-table :column="realTableColumn"></free-table>