ProDescriptions 高级描述列表
高级描述列表组件,提供一个更加方便快速的方案来构建描述列表。
基础用法
每列需配置 dataIndex 或 prop(同时存在时以 dataIndex 为准)与 title 或 label。使用 request 拉取单条对象;dataSource 可本地直出,且 优先于 远程数据。
使用模拟 request 延迟返回一条详情:含金额、状态枚举、可复制备注。
| 名称 | — | 金额 | — |
| 状态 | — | 备注 | — |
| 描述 | |||
编辑模式
ProDescriptions 支持两种编辑模式,通过 editMode 属性配置:
- navigate(默认):点击标题后的编辑图标,触发
@edit事件,由调用方自行处理跳转或弹窗等逻辑。 - inline:点击编辑图标后,当前页面内将只读的 Descriptions 切换为可编辑的 Form 表单:
- 根据列配置自动生成表单字段
- 必填项自动显示红色星号(
*)并生成必填校验规则 - 支持通过
formItem.rules配置自定义校验规则(async-validator 格式) - 底部显示「取消」和「保存」按钮
- 点击「取消」恢复只读状态
- 点击「保存」时先触发全部字段的表单校验,所有规则验证通过后才执行
saveRequest业务逻辑
展示两种编辑模式:navigate 跳转模式 + inline 内联表单编辑(含只读/编辑态切换、表单校验)。
navigate 模式(跳转新页面编辑)
| 公司名称 | 国家/地区 | 时区 |
|---|---|---|
| CN-SZ | ET | |
| 公司官网 | 联系人姓名 | 联系人邮箱 |
| www.baidu.com | 杜军 | 905020481@qq.com |
| 服务商类型 | 营业执照 | |
| PSPESP | ||
inline 模式(当前页面内编辑)— 只读状态
| 公司名称 | 国家/地区 | 时区 |
|---|---|---|
| CN-SZ | ET | |
| 公司官网 | 联系人姓名 | 联系人邮箱 |
| www.baidu.com | 杜军 | 905020481@qq.com |
| 服务商类型 | 营业执照 | |
| PSPESP | ||
数据与 request
dataSource:受控数据;有值时不再以request结果覆盖展示(仍可在无dataSource时依赖request)。request(params?):返回{ data?, success? }。success: false时不更新已缓存的远程数据(仍结束 internal loading)。params变化会深度监听并重新请求。manualRequest: true:首屏不自动请求,需调用实例reload()。
列与展示
valueType:text(默认)、date、digit、money、select;select配合options或valueEnum({ '0': { text: '关' } }形式)。fieldProps.precision:digit/money小数位。span:对应UDescriptionsItem的列跨度。hideInDescriptions:为true不渲染该列(只读态隐藏)。hideInEditForm:为true编辑态下不渲染该列为表单项。tooltip:表头虚线悬停说明。copyable:内容区显示「复制」并写入剪贴板。textEllipsis:内容文本超长时以省略号截断显示。textEllipsisWidth:省略模式下的最大内容宽度,配合textEllipsis使用,支持string \| number。labelAlign:标签对齐方式,支持'left' \| 'center' \| 'right'。align:内容对齐方式,支持'left' \| 'center' \| 'right'。slotName:指定该列使用自定义插槽渲染。column:每行显示几项,默认3。
布局说明
- 列宽均分:表格采用
table-layout: fixed布局,列宽按column设置的列数平均分配,不随内容宽度自适应。 - 顶部对齐:单元格内容默认顶部对齐(
vertical-align: top),避免同一行中不同高度的单元格居中对齐导致不美观。
工具函数可从包内导出使用:getDescriptionsColumnKey、getDescriptionsColumnTitle、formatDescriptionsValue、getValueByPath。
ProDescriptions 属性
| 名称 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| columns | 列配置,必填 | array | — |
| dataSource | 本地数据;有值时优先于 request 的缓存结果 | object | — |
| request | 拉取单条详情 | function | — |
| params | 透传 request,变化时重新请求 | object | — |
| manualRequest | 为 true 时挂载不自动 request | boolean | false |
| loading | 外部 loading,与内部请求态或关系 | boolean | false |
| title | 描述标题 | string | — |
| titleSize | 标题字体大小 | string / number | 20px |
| showEditIcon | 是否显示标题后的编辑图标 | boolean | false |
| editIcon | 自定义编辑图标(组件或字符串) | Component / string | 默认铅笔图标 |
| editable | 编辑模式(受控) | boolean | — |
| editMode | 编辑模式 | enum | navigate |
| saveRequest | inline 模式保存请求 | function | — |
| column | 每行项数 | number | 3 |
| border | 是否带边框 | boolean | true |
| direction | 排列方向 | enum | horizontal |
| size | 尺寸 | enum | — |
| labelWidth | 标签区宽度 | string / number | — |
事件
| 名称 | 说明 | 类型 |
|---|---|---|
| requestEnd | 单次 request 结束 | function |
| edit | 点击编辑图标触发 | function |
| updateEditable | 编辑状态变化(双向绑定) | function |
| save | inline 保存按钮点击 | function |
| saveSuccess | inline 保存完成 | function |
| cancel | inline 取消按钮点击 | function |
保存机制详解
inline 编辑模式下的保存流程涉及 一个 prop 和 两个 event,它们各司其职:
三者职责
| 名称 | 类型 | 方向 | 职责 | 是否必填 |
|---|---|---|---|---|
saveRequest | prop (属性) | 外部 → 组件 | 执行业务逻辑(如调用 API 保存数据),返回 { success } | 可选 |
save | event (事件) | 组件 → 外部 | 通知外部「用户点击了保存」,携带当前表单值 | 自动触发 |
saveSuccess | event (事件) | 组件 → 外部 | 通知外部「保存已完成」,携带成功/失败状态 | 自动触发 |
完整执行流程
- 用户点击「保存」按钮
- ① 表单校验(validate)
- 校验失败 → 显示错误提示,终止流程
- 校验通过 → 继续
- ② saving = true(显示 loading)
- ③ saveRequest(values) 是否传入?
- YES →
await saveRequest(values)- 返回
{ success: true }:emit('save', values)— 触发 @saveemit('saveSuccess', true)— 触发 @save-success- 关闭编辑态 + 刷新数据
- 返回
{ success: false }:emit('save', values)emit('saveSuccess', false)- 保持编辑态(不关闭,方便修改后重试)
- 返回
- NO(未传 saveRequest):
emit('save', values)— 触发 @saveemit('saveSuccess', true)— 触发 @save-success- 直接关闭编辑态
- YES →
- ④ saving = false(取消 loading)
使用示例
推荐写法(解耦:业务逻辑与 UI 操作分离)
<template>
<ProDescriptions
:columns="columns"
:data-source="data"
edit-mode="inline"
:save-request="handleSave"
@save-success="onSaveDone"
/>
</template>
<script setup>
/** 步骤1:处理业务逻辑(调 API) */
async function handleSave(values: Record<string, unknown>) {
const res = await api.updateCompany(values)
return { success: res.ok } // 告诉组件是否成功
}
/** 步骤2:根据结果操作 UI */
function onSaveDone(ok: boolean) {
if (ok) {
message.success('保存成功')
// 其他 UI 更新...
} else {
message.error('保存失败')
}
}
</script>简化写法(无需 @save-success)
如果不需要区分成功/失败的 UI 提示,可以在 saveRequest 内直接处理一切:
<ProDescriptions
:columns="columns"
:data-source="data"
edit-mode="inline"
:save-request="handleSave"
/>
<script setup>
async function handleSave(values: Record<string, unknown>) {
const res = await api.updateCompany(values)
if (res.ok) {
message.success('保存成功') // 直接处理 UI
// 无需 @save-success,组件会自动关闭编辑态并刷新
} else {
message.error('保存失败')
}
return { success: res.ok }
}
</script>纯事件驱动(不传 saveRequest)
适用于只需获取数据、自行处理的场景:
<ProDescriptions
:columns="columns"
edit-mode="inline"
@save="onSave"
@save-success="(ok) => ok && message.success('已保存')"
/>
<script setup>
function onSave(values: Record<string, unknown>) {
console.log('用户提交的数据:', values)
// 自行处理保存逻辑...
}
</script>如何选择?
- 需要调用 API? → 传
saveRequest,返回{ success: boolean } - 需要保存后更新其他状态? → 监听
@save-success - 简单场景,一次搞定? → 只用
saveRequest,不用监听事件 - 纯数据采集,不自动保存? → 不传
saveRequest,只监听@save
暴露
| 名称 | 说明 | 类型 |
|---|---|---|
| reload | 再次执行 request | function |
插槽
| 名称 | 说明 | 参数 |
|---|---|---|
| editIcon | 自定义编辑图标 | — |
| 只读态:按列自定义渲染内容 | { record, column, editing: false, value } | |
| edit- | 编辑态:按列自定义表单控件 | { record, column, editing: true, modelValue, value } |
| action | 自定义操作按钮区(替代默认的 取消/保存) | { cancel, save, saving } |
列配置 ProDescriptionsColumn
| 名称 | 说明 | type | 默认值 |
|---|---|---|---|
| dataIndex | 字段路径,支持 a.b 点路径 | string | — |
| prop | 同 dataIndex 的备用名 | string | — |
| title | 列标题 | string | — |
| label | 同 title | string | — |
| span | 列跨度 | number | — |
| hideInDescriptions | 为 true 不展示(只读态) | boolean | — |
| hideInEditForm | 为 true 不展示为表单项 | boolean | — |
| valueType | 值格式化类型 | enum | — |
| fieldProps | 如 precision 小数位 | object | — |
| options | select 的选项 | array | — |
| valueEnum | 与 Ant valueEnum 类似 | object | — |
| textEllipsis | 内容文本省略 | boolean | — |
| textEllipsisWidth | 省略模式下的最大内容宽度 | string / number | — |
| labelAlign | 标签对齐方式 | enum | — |
| align | 内容对齐方式 | enum | — |
| tooltip | 表头说明 | string | — |
| copyable | 是否显示复制 | boolean | — |
| slotName | 自定义插槽名称 | string | — |
| formItem | inline 编辑模式的表单配置 | object | — |
表单配置 FormItemConfig
inline 编辑模式下,通过列的 formItem 字段配置表单项:
| 名称 | 说明 | type | 默认值 |
|---|---|---|---|
| formType | 表单控件类型 | enum | input |
| required | 是否必填。为 true 时自动生成必填校验规则(select 类型 trigger 为 change,其余为 blur);多选 select 会附加 type: 'array' 确保空数组被正确拦截 | boolean | false |
| placeholder | placeholder 文案 | string | — |
| formItemProps | 透传给 UFormItem 的属性 | object | — |
| fieldProps | 透传给具体控件的属性(如 multiple 控制 select 多选模式) | object | — |
| rules | 自定义校验规则(async-validator 格式)。与 required 同时使用时,自定义规则合并到必填规则之后 | array / object | — |
校验规则说明
必填规则(required: true):自动生成,无需手动编写
自定义规则(rules):支持 async-validator 完整语法,常用示例:长度限制
{ min: 2 }/{ max: 20 }、正则匹配{ pattern: /^1\d{10}$/ }等。select 多选:通过
fieldProps: { multiple: true }开启,必填规则会自动添加type: 'array'
表单校验流程
inline 编辑模式下点击「保存」按钮的完整校验流程如下:
- 用户点击「保存」按钮
- 调用
formRef.validate(callback)开始表单校验 - 遍历所有已注册的 FormItem:
- 对每个 FormItem 执行
getFilteredRule(trigger) - 合并
required自动规则(如有) - 合并
rules自定义规则(如有) - 使用 AsyncValidator 执行校验:
- 校验通过 → 继续下一个字段
- 校验不通过 → 显示错误信息,记录到
invalidFields
- 对每个 FormItem 执行
- 全部通过 →
callback(true)→ 执行saveRequest→ 业务逻辑 - 存在失败项 →
callback(false)→ 阻止保存,显示错误提示
类型
ProDescriptionsRequestResult:request返回值data:Record<string, unknown>— 单条详情对象success:boolean— 为false时不以本次结果更新 UI
ProDescriptionsSaveResult:saveRequest返回值success:boolean— 为false时视为保存失败
源码位于 packages/components 仓库的 pro-descriptions;安装与 registry 要求见 开发指南。