50-18个表单控件的统一绑定
TextBox到Popup一共18个表单控件,每个内部都是同一段代码:
const { value } = useBinding(props.field)。这篇不逐个讲控件------讲统一的绑定契约怎么让18个控件写成"配置差异"而不是"18个实现",以及ComboBox/FileUpload/Popup三个特殊件的差异点。
文章目录
源码目录:
browise-vue/src/components/form/(18个.vue文件)
一、18个控件的清单
| 输入类 | 选择类 | 附件类 |
|---|---|---|
| TextBox 文本 | ComboBox 下拉 | FileUpload 上传 |
| Textarea 多行 | CheckBox 复选 | LinkUpload 关联上传 |
| NumberBox 数字 | RadioGroup 单选组 | LinkDown 关联下载 |
| Password 密码 | Switch 开关 | Popup 弹窗选择 |
| DateBox 日期 | Slider 滑块 | ColorPicker 颜色 |
| TimePicker 时间 | Rate 评分 | Range 范围 |
二、统一契约:三个props一个hook
每个控件的骨架完全一致:
vue
<script setup lang="ts">
const props = defineProps<{
field: string // ★绑定字段名------唯一的必传
label?: string // 字段标签
disabled?: boolean // 禁用
// ...各控件自己的扩展props
}>()
const { value, dirty, changed } = useBinding(props.field)
</script>
<template>
<el-form-item :label="label">
<el-input v-model="value" /> <!-- 控件壳换,value不变 -->
</el-form-item>
</template>
useBinding(props.field)是全部秘密 ------第45篇的55行hook让任何控件获得与store当前行的双向绑定。控件差异只是"外壳用什么Element Plus组件":
| 控件 | 外壳 | 扩展props |
|---|---|---|
| TextBox | el-input | maxlength/readonly |
| NumberBox | el-input-number | min/max/precision |
| DateBox | el-date-picker(type=date) | format |
| ComboBox | el-select | codeName(字典) |
| CheckBox | el-checkbox | --- |
| Popup | el-dialog+搜索列表 | dialogUrl |
写一个新控件的成本 ------挑一个Element Plus壳+useBinding+声明差异props------30行以内 。18个控件的存在不是因为绑定复杂,是因为外壳的视觉形态有18种。
三、ComboBox:字典翻译的特殊件
vue
<ComboBox field="psnSex" codeName="SEX" />
typescript
const props = defineProps<{ field: string; codeName?: string }>()
const { value } = useBinding(props.field)
// 字典选项------useDict按codeName缓存加载(AA10表)
const options = useDict(props.codeName)
codeName触发字典通道 ------选项列表从AA10码表来(SELECT AAA102,AAA103 FROM AA10 WHERE AAA100='SEX')------value存码值("1")、显示码名("男")。字典的缓存/失效由useDict+后端DictService管理(第53篇)------控件只消费。
元数据驱动下的自动升级 ------describe返回的codeName非空时,CommonForm/CommonQuery渲染该字段自动用ComboBox替代TextBox (第48篇)------零代码页面获得字典能力不需要任何配置之外的动作。
四、FileUpload/LinkUpload:附件三件套
| 控件 | 行为 |
|---|---|
| FileUpload | 上传到MinIO(FileController)→字段存文件ID |
| LinkUpload | 同上+已有附件回显(编辑场景) |
| LinkDown | 按文件ID下载(路径遍历已修------第34篇2.10) |
字段存的是文件ID不是URL ------BrowiseFile表(fileId→MinIO对象名→元数据)------URL由后端动态生成 (MinIO的预签名URL有时效)------前端永远只拿fileId。换存储(MinIO→本地盘→OSS)字段值不变------存储迁移对表单零影响。
五、Popup:弹窗选择的复合控件
vue
<Popup field="unitId" dialogUrl="/pages/CommonQueryPage?sqlId=UNIT_s"
displayField="unitName" />
三个props协作 ------dialogUrl打开选择弹窗(复用CommonQuery页)、选中行的unitId写value、displayField(unitName)做显示(存ID显名称------同ComboBox的码值模式)。
Popup的存在理由 ------下拉适合少量选项(字典),大量选项+条件筛选必须弹窗 (选机构要按名称搜)。弹窗内容是任意页面------Popup是"字段值来自另一个查询页"的通用机制。
六、v-permission与控件的交集
vue
<el-button v-permission="'user:delete'">删除</el-button>
按钮级权限(usePermission.ts)是另一个横切 ------不在控件内而在使用方。控件管数据绑定、指令管可见性 ------两个正交维度。设计器画的表单里的按钮配权限------PropertyPanel的按钮属性里有permission字段------保存进元素树,渲染时v-permission动态挂上。
✅ 亮点:18控件=18种Element Plus壳+同一段useBinding、新控件30行以内的成本结构、ComboBox的codeName与describe的自动联动、文件字段存ID不存URL的存储迁移自由、Popup作为"字段来自另一个查询页"的通用机制。适合做控件库规范化的人。扩展方向:第45篇useBinding、第48篇CommonQuery、第49篇FormEditor。