前言
对于面向企业的项目而言,前端开发中最常见的场景之一便是后台管理系统,而这类系统的核心页面多为基于表格表单的 CURD(增删改查)操作页面。随着同类页面开发量的增加,封装一套通用的 CURD 功能组件变得尤为必要——这不仅能显著提升开发效率,避免重复性工作,更能为后续的统一修改与维护提供便利。
一个标准的 CURD 页面通常包含以下核心功能模块:搜索条、操作工具条、数据表格、新增 / 编辑弹窗、详情弹窗等。
本方案将采用 “分而治之” 的策略:将每个功能模块封装为独立的基础组件,再通过组件组合的方式快速搭建完整的 CURD 页面。
在之前的文章中已经介绍了搜索条、数据表格、新增/编辑弹窗功能模块组件的封装,参见文章:
本篇文章将是该系列的最后一篇文章,用来介绍详情弹窗功能模块的封装实现细节。
详情弹窗
详情弹窗主要是对列表中数据条目更详细的展示,其相对于新增/编辑弹窗更简单,就是将表单控件转为显示字段的具体内容值。
对于需要特殊显示的内容,也可以通过配置插槽的方式实现。
实现
1.props参数
组件对外的参数有两个:data(详情数据对象)、columns(详情json配置项数组)
2.布局实现
详情的布局没有使用<el-descriptions>描述列表控件,而是选择<el-form>表单控件实现。这是因为前者无法很好的控制字段名称右对齐,需要css配合控制,而表格控件原生提供了字段名称的右对齐,更加方便。此外配合<el-col>栅格布局元素,能够更好的控制详情信息的分栏情况。
3.原生属性透传
v-bind="$attrs"外部属性绑定在<el-form>标签上,调用者可以直接使用 Element Plus 表单的所有原生属性,无需在封装组件中重复声明这些属性。
4.遍历生成详情信息
详情组件最核心的功能是遍历渲染。模板中通过v-for="item in columns"遍历配置数组,生成每个详情信息的容器<el-col>。
<el-col>容器占据的栅格宽度可以通过每个配置项中的span参数指定。也可以通过组件属性透传的cols属性整体设置表单的列数进行布局的控制。
容器内部分为两种类型,一种是配置了slot参数,通过插槽外部自定义详情信息的内容;另一种是显示对应prop字段的详情信息。
<template>
<el-dialog v-model="model" :title="$attrs.title || '详情'" :width="$attrs.width ?? 600" class="ts-detail-dialog">
<el-form :model="data" label-width="auto" v-bind="$attrs">
<el-row>
<el-col v-for="item in columns" :key="item.prop" :span="item.span || 24 / ($attrs.cols || 1)">
<slot v-if="item.slot" :name="item.slot" />
<el-form-item v-else :label="item.label + ':'">
<span>{{ data[item.prop] }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="model = false">关闭</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
defineProps({
data: {
type: Object,
required: true,
default: () => {}
},
columns: {
type: Array,
required: true,
default: () => []
}
});
defineOptions({
inheritAttrs: false
});
const model = defineModel();
</script>
调用
以下为详情弹窗组件的完整调用示例。
<template>
<!-- 详情弹窗 -->
<ts-detail-dialog v-model="detailVisible" :data="detailData" :columns="detailColumns" :width="600" />
</template>
<script setup>
const detailVisible = ref(false);
const detailData = ref({});
const detailColumns = reactive([
{
prop: 'name',
label: '姓名'
},
{
prop: 'gender',
label: '性别'
},
{
prop: 'age',
label: '年龄'
},
{
prop: 'date',
label: '出生日期'
},
{
prop: 'address',
label: '通讯地址',
span: 24
}
]);
function handleDetail(row) {
detailData.value = row;
detailVisible.value = true;
}
</script>
总结
详情弹窗组件与该系列中其他组件的实现方式一致,都是通过遍历json配置项列表来实现内容的渲染。
其实如果看过前面几篇文章的同学一定能够发现,整套CURD组件的实现原理都是一致的,都是通过遍历json配置项列表来实现同质内容的动态渲染,并且配合插槽参数实现个别自定义内容的插入,实现原理还是很简单的。