@qin-ui/antd-vue-pro

二次封装antd vue组件
11,947 5
Install
npm install @qin-ui/antd-vue-pro
Latest Version:2.4.5
Vue:3
License:MIT
Last Updated:Sep 9, 2026
Links: GitHub  ·  npm
Maintainer: dufan1994

@qin-ui/antd-vue-pro

基于 Ant Design Vue v4+ 和 Vue 3.x 的二次封装高级组件库,提供高度可配置、Schema 驱动的 ProForm 和 ProTable,助您摆脱繁琐的模板代码,快速搭建桌面端中后台应用。

Ant Design Vue 4.x Vue 3.3+ TypeScript MIT

📝 使用示例和文档详细内容


✨ 核心特性

  • 🛡️ 底层坚实:基于 Ant Design Vue 4.x 构建,原生支持 Vue 3.3+。
  • 🔥 Schema 驱动:使用声明式 JSON 配置即可快速生成表单,极大地减少了模板文件的编写。
  • ⚙️ 动态自适应:支持表单字段的动态隐藏、禁用与规则联动,表格列的动态控制与配置。
  • 🧩 极致扩展:原生支持自定义渲染组件与插槽定制,提供 ProComponentProvider 进行全局默认属性覆盖。
  • 📐 完美类型推导:基于 TypeScript 提供完备的强类型推导和自动补全,开发体验流畅。

📦 安装

确保您的项目中已安装 ant-design-vue (v4+) 和 vue (v3.3+):

npm i @qin-ui/antd-vue-pro
# 或使用 pnpm
pnpm add @qin-ui/antd-vue-pro

[!WARNING] 2.0+ 升级提示:2.0 版本进行了底层重构,useForm 返回的 formData 从原本的 ref 包装调整为了真正的 reactive 响应式对象,获取和修改属性时无需使用 .value。


🤖 AI 辅助开发

本项目内置 AI 上下文初始化工具。安装后在项目根目录执行:

npx @qin-ui/antd-vue-pro init-ai

将在项目中生成双载体 AI 上下文,使 Cursor / Claude Code / Codex 等 AI 工具深度理解本库的 Schema 驱动用法与属性透传规则:

  • AGENTS.md — 核心使用规则(跨工具开放约定,会话时自动注入,AI 默认加载)
  • .agents/skills/antd-vue-pro/SKILL.md — skills 入口(速查 + 参考导航)
  • .agents/skills/antd-vue-pro/references/ — 完整使用文档与结构化 API 元数据

生成的 AGENTS.md 使用标记区块写入,重复执行 init-ai 可安全更新,不影响项目内其他库的指令。建议将生成的文件提交到 Git 仓库,团队共享 AI 上下文。


🚀 快速开始

1. 全局注册组件(可选)

import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/reset.css';
import AntdVuePro from '@qin-ui/antd-vue-pro';
import App from './App.vue';

const app = createApp(App);
app.use(Antd);
app.use(AntdVuePro); // 全局注册 ProForm, ProTable 和 ProComponentProvider
app.mount('#app');

2. 基础表单使用示例

<script setup lang="ts">
import { ProForm, useForm } from '@qin-ui/antd-vue-pro';

interface UserForm {
  username: string;
  age: number;
  gender: string;
}

// 1. 创建类型安全的表单实例
const form = useForm<UserForm>(
  { username: '张三', age: 18, gender: 'male' }, // 初始数据
  [
    {
      path: 'username',
      label: '用户名',
      component: 'input',
      rules: [{ required: true, message: '请输入用户名' }],
    },
    {
      path: 'age',
      label: '年龄',
      component: 'input-number',
      min: 1,
      max: 150,
    },
    {
      path: 'gender',
      label: '性别',
      component: 'select',
      options: [
        { label: '男', value: 'male' },
        { label: '女', value: 'female' },
      ],
    },
  ]
);

// 2. 提交表单校验与数据获取
const handleSubmit = async () => {
  try {
    await form.formRef.value?.validate();
    console.log('提交的数据:', form.formData);
  } catch (error) {
    console.error('校验失败:', error);
  }
};
</script>

<template>
  <div style="padding: 24px; max-width: 600px;">
    <ProForm :form="form" />
    <a-button type="primary" style="margin-top: 16px;" @click="handleSubmit">
      提交表单
    </a-button>
  </div>
</template>

🧱 属性分层透传(核心规则)

ProForm/ProTable 是渲染引擎,所有真实 UI 来自 ant-design-vue。Field 上的属性会被"剥离到不同 DOM 层",不是全塞给输入控件。写错层就会失效,这是最容易踩的坑:

<a-col :span="8">            ← Grid 层(仅 grid 开启时)
  <a-form-item label="...">  ← FormItem 层
    <a-input placeholder>     ← 输入控件层
  </a-form-item>
</a-col>
属性 落到哪一层 说明
span / offset / push / pull / flex / xs..xxl <a-col> Grid 层 仅 grid 开启时生效
label / rules / tooltip / colon / labelCol / wrapperCol / extra / help / validateTrigger / validateFirst / valuePropName / normalize / formItemStyle / formItemClass / formItemDataAttrs <a-form-item> 层 表单项相关属性
disabled / placeholder / allowClear / options / mode / maxlength / componentStyle / componentClass / componentDataAttrs + 该控件其余 ant-design-vue 原生属性 输入控件本身(a-input 等) 其余全部
component / hidden / modelProp / valueFormatter / fields / slots / formItemContainer / componentContainer / extraProps ProForm 逻辑消费,不绑到 DOM 框架级属性

规则:span 给 Grid,label/rules 给 FormItem,其余给输入控件。输入控件的具体属性名/类型请以 ant-design-vue 官方文档 为准。


📚 组件 API 说明

1. ProComponentProvider

作为全局或局部范围的上下文配置器,通过传入 componentVars 属性来统一覆盖子组件的默认配置。

Props
参数名 说明 类型 默认值
componentVars 需要全局 provide 给子组件的默认属性配置 ComponentVars -
内置默认预设(INJECT_CONFIG)

ProComponentProvider 内置了一套默认属性预设,即使不配置 componentVars 也会生效。Field 配置优先级最高,会覆盖这些预设。以下为各组件的内置默认值(写代码时需知晓,避免行为与预期不符)。其中部分值会改变宿主组件原生行为(如 maxlength 静默截断超长输入、input-number 限制数值范围并隐藏步进按钮),排查「输入被截断 / 数值有上限」类问题前先核对本清单:

component 默认预设
switch { modelProp: 'checked' } —— v-model 绑定 checked 而非 value
input / input-password { maxlength: 100, allowClear: true, placeholder: '请输入' }
textarea { maxlength: 200, autoSize: { minRows: 3, maxRows: 6 }, showCount: true, allowClear: true, placeholder: '请输入' }
input-number { max: 1e15-1, min: -(1e15-1), controls: false, placeholder: '请输入', style: { width: '100%' } }
select / cascader { allowClear: true, placeholder: '请选择', getPopupContainer }
date-picker / range-picker / time-picker { allowClear: true, getPopupContainer, style: { width: '100%' } }
pro-form { grid: { gutter: { xs: 8, sm: 16, md: 16, lg: 24 } } }
pro-form-item { validateFirst: true, span: 8 }
pro-table { pagination: { showTotal, showSizeChanger, pageSizeOptions: ['10', '20', '30', '40', '50', '100'], showQuickJumper: true }, searchFormConfig: { layout: 'grid', expand: { minExpandRows: 2, expandStatus: false } }, control: true, addIndexColumn: true }

modelProp 控制 v-model 绑定的属性名,默认 'value'(即 v-model:value)。switch 经预设绑定为 checked,通常无需手动设置。 showTotal(分页总计)与 placeholder 不在 INJECT_CONFIG 预设内,由 locale 体系提供,可在 Field / ProTable 配置中显式覆盖。


2. ProForm

基于 Ant Design Vue Form 深度封装的高级表单组件。

Props
参数名 说明 类型 默认值
form 由 useForm 返回的表单实例 Form -
grid 是否启用栅格网格布局,支持传入 Grid 配置以配置自适应 boolean | GridProps false
... 其余属性均继承自 Ant Design Vue a-form 组件的原生 Props FormProps -
Events & Methods
  • 所有事件(如 finish, finishFailed 等)和方法(如 validate, resetFields)均与 Ant Design Vue a-form 组件完全继承,且能直接透传绑定。

3. ProTable

基于 Ant Design Vue Table 深度封装的高级表格组件,将搜索表单、列配置、分页高度集成。

Props
参数名 说明 类型 默认值
table 由 useTable 返回的表格实例 Table -
search 触发表格查询的回调函数,需返回 Promise 或直接返回查询数据 (params: any) => Promise<any> | any -
addIndexColumn 是否自动在表格首列插入序号列 boolean false
immediateSearch 表格挂载时(onMounted)是否立即触发一次 search 查询 boolean false
control 是否在表格右上角工具栏中展示尺寸调节和列动态显示控制按钮 boolean true
searchFormConfig 查询表单的布局配置参数 SearchFormConfig -
tableContainer 表格的外部包裹容器,默认为 false Component | false -
... 其余参数继承自 Ant Design Vue a-table 的原生属性 TableProps -
Slots
插槽名 说明
search-form 自定义搜索栏表单内容
button-bar 自定义操作按钮组区域(位于搜索栏下方,表格左上方)
toolbar 自定义工具栏区域(位于表格右上方控制按钮旁)
table 完全自定义渲染表格区域
数据流

ProTable 不会自动请求数据,查询由你提供的 search 回调驱动。内部串联逻辑:

点击搜索  -> 重置分页到第 1 页        -> 调用 search()
分页/排序变化 -> 更新 pageParam        -> 调用 search()
点击重置  -> resetQueryParams()       -> 调用 search()
挂载(immediateSearch) -> 立即触发一次   -> 调用 search()

search 回调内通常组装查询参数并赋值数据源:

const fetchData = async () => {
  const res = await api.list({
    ...table.searchForm.formData, // 搜索条件
    ...table.pageParam, // 分页
  });
  table.dataSource.value = res.data;
  table.setPageParam({ total: res.total });
};

// 重置按钮(ProTable 内部已串联 resetQueryParams -> search,一般无需手动处理)

⚙️ 核心 Hooks 说明

1. useForm

用于创建表单管理对象,整合了表单数据、字段规则和 ref 控制。

入参定义
const form = useForm<D>(initFormData?, initFields?, root?)
  • initFormData: 表单初始数据对象(DeepPartial<D>)
  • initFields: 初始字段配置数组(Field[])
  • root: 是否创建根 Form 实例,默认为 true。若为 false,则内部会隐式 inject 父级表单上下文。
返回值 (Form 实例)
属性/方法 说明 类型
formData 响应式表单数据对象(2.0+ 中由 reactive 包装) Reactive<D>
fields 响应式表单字段配置数组引用 Ref<Field[]>
formRef 底层 Ant Design Vue a-form 的 DOM/组件引用实例 Ref<FormInstance | undefined>
getFormData(path) 安全获取指定字段路径(支持深层 'a.b')的数据值 (path) => any
setFormData(path, value) 路径写入或函数式更新;传对象({...})批量覆盖整个表单;传函数 (prev) => new 批量更新 (path, val) => void
getField(path, opts?) 获取指定 path 的字段配置,支持查找函数定位,支持配置 { all: true } 获取所有匹配项 (path, opts) => Field
setField(path, patch, opts?) 默认合并更新字段配置;{updateType:'rewrite'} 覆盖;支持函数式 setField(path, prev=>({...}));{all:true} 批量更新所有匹配 (path, patch, opts) => void
deleteField(path, opts?) 删除字段配置;{all:true} 删除所有匹配的字段 (path, opts?) => void
appendField(path, field) 在指定字段后追加新字段(入参可为数组);undefined 在末尾追加;{all:true} 所有匹配后追加 (path, field, opts?) => void
prependField(path, field) 在指定字段前插入新字段(入参可为数组);undefined 在开头插入;{all:true} 所有匹配前插入 (path, field, opts?) => void
getParentField(path, opts?) 查找父级字段配置;{all:true} 返回所有匹配的父级字段 (path, opts?) => Field

2. useTable

用于创建和管理表格实例,内置集成了列配置操作与搜索表单组件。

入参参数
const table = useTable<D, T>({
  columns: [], // 初始列配置
  dataSource: [], // 静态初始数据源
  pageParam: {}, // 分页参数配置
  searchParam: {}, // 搜索栏初始数据
  searchFields: [], // 搜索栏字段 Schema 配置
});
返回值 (Table 实例)
属性/方法 说明 类型
columns 响应式表格列配置数组 Ref<Column[]>
dataSource 响应式表格列表数据源 Ref<T[]>
pageParam 响应式分页参数对象(包含 current, pageSize, total) Reactive<PageParam>
searchForm 搜索栏表单关联的 useForm 实例,提供完美的表单操作 API Form<D>
setColumn(key, patch) 合并或重置修改指定 key 的列配置属性(如 width、title 等) (key, patch) => void
deleteColumn(key) 动态移除某一个指定 key 对应的表格列配置 (key) => void
appendColumn(key, col) 在某一个列的后方动态追加配置列 (key, col) => void
prependColumn(key, col) 在某一个列的前方动态插入配置列 (key, col) => void
setPageParam(param) 增量设置当前分页参数值,支持传入对象或更新函数 (param) => void
resetQueryParams() 恢复分页与搜索参数到初始化快照 () => void
列配置(Column)

columns 数组中每一项为 Column<T> 类型,继承 ant-design-vue ColumnType,因此所有原生列属性(title / width / fixed / align / customRender / ellipsis 等)均可用。在此基础上新增:

属性 说明 类型 默认值
dataIndex 列数据路径(主要字段),类型安全,支持 'name' / 'address.city' / ['address','city'] string | string[] -
key 列字段标识(辅助),仅当 dataIndex 无法满足时使用,匹配优先级低于 dataIndex string -
hidden 是否隐藏该列(配合列动态控制) boolean false

📄 字段配置(Field)详解

在进行表单 Schema 编写时,Field 数组中的每一项都支持以下属性定义:

公共基础属性

属性名 说明 类型 默认值
path 字段标识,需对应数据对象 formData 的 key,支持多级嵌套,例如 address.city string -
label 字段中文标签,支持字符串或直接传入 VNode 组件进行自定义 string | Component | Slot -
component 调用的表单项组件的类型,支持内置类型键名或直接传入自定义 Vue 组件 string | Component 'input'
hidden 字段是否被隐藏(在 DOM 中彻底不渲染,但数据保留),支持 Ref/Computed 响应式 boolean | Ref<boolean> false
disabled 组件的禁用状态,支持 Ref/Computed 响应式 boolean | Ref<boolean> false
rules 字段数据校验规则,遵循 ant-design-vue Form 校验格式 Rule[] -
span 栅格占位宽度(在 ProForm 开启 grid 网格布局后有效) number -
formItemStyle 挂载在外部 a-form-item 节点上的额外 CSS 样式属性 CSSProperties -
formItemClass 挂载在外部 a-form-item 节点上的自定义类名 string -
formItemContainer 针对该表单项的最外层 DOM 包裹组件 Component -
formItemDataAttrs 附加在 a-form-item DOM 节点上的自定义 data 属性 Record<string, string> -
componentStyle 直接传递给内部表单输入组件的额外 CSS 样式属性 CSSProperties -
componentClass 直接传递给内部表单输入组件的自定义类名 string -
componentContainer 针对表单输入组件的包裹组件(位于 FormItem 与组件之间) Component -
componentDataAttrs 附加在内部输入组件 DOM 节点上的自定义 data 属性 Record<string, string> -
slots 该表单项的插槽自定义内容,包含 formItem 插槽或组件插槽 Record<string, Slot> -
valueFormatter 字段值转换处理器,可在输入更新或提取数据时做 get/set 转换 ValueFormatter -
modelProp 双向绑定的数据属性名称(当使用自定义组件且非 value 绑定时) string 'value'
fields 嵌套子表单项的 Schema 数组配置(用于分组或复杂嵌套表单) Field[] -
grid 针对当前嵌套子表单项所使用的网格布局参数(仅当有 fields 时有效) boolean | GridProps -
valueFormatter 字段值转换

控制表单值与组件值之间的转换(如日期 dayjs 与字符串互转)。在表单数据写入前(computed setter 中)执行,支持两种形态。函数形态仅 set(写入)方向生效,读取时不转换;对象形态 get/set 双向生效:

// 函数形态:(新值, 旧值) => 转换后的值,写回 formData
{ path: 'name', component: 'input', valueFormatter: (val, oldVal) => val?.trim() }

// 对象形态:get 读出时转换,set 写入时转换
{
  path: 'birthday',
  component: 'date-picker',
  valueFormatter: {
    get: (val) => (val ? dayjs(val) : null),                          // formData -> 组件显示
    set: (val) => (val ? dayjs(val).format('YYYY-MM-DD') : null),     // 组件 -> formData
  },
}

📌 旧值(oldVal)注入契约:仅当转换函数显式声明两个形参 (val, oldVal) => ... 时,底层才读取并传入写入前的旧值快照;声明单形参则不读取旧值(零克隆开销)。请勿使用默认参数或剩余参数声明(否则 fn.length 无法识别)。oldVal 为只读快照副本,不得依赖原地修改写回。

⚠️ valueFormatter 不支持响应式(不能包 ref/computed),与 component / fields / slots / modelProp 等同属不支持响应式的属性。


🔄 响应式联动

控制类属性(disabled / hidden / rules 等)支持三种响应式模式,按场景选最简的:

// A. computed() 声明式 -- 初始化时已知的联动(首选)
disabled: computed(() => !form.formData.enabled),
rules: computed(() => form.formData.hasLimit ? [{ required: true, message: '必填' }] : []),

// B. ref() -- 外部共享状态
const isDisabled = ref(false);
disabled: isDisabled,

// C. setField() 命令式 -- 事件驱动的运行时变更
form.setField('limitCount', { disabled: true });

规则:初始化时已知的联动用 computed(),运行时事件触发的用 setField(),外部共享状态用 ref()。能用 computed() 解决就不要用 setField()。

不支持响应式的属性

以下属性不能包 ref/computed(会失效或引发渲染异常),只能传静态值:

属性 原因
component 组件对象/函数,响应式代理会破坏渲染(需 markRaw)
valueFormatter 纯转换函数,无需响应式
fields 嵌套字段数组结构,响应式代理会干扰内部解析
slots 插槽内容,响应式代理会破坏渲染
modelProp 字符串标识,无需响应式
formItemContainer / componentContainer 容器组件,需 markRaw

动态切换 component 或 slots 时,用 setField() 命令式更新,而非包 computed。


内置组件映射(component 可选值)

组件库默认封装了 Ant Design Vue 的高频交互组件,您可以在 component 属性中填入以下预设键名来自动调用:

内置键名 渲染对应的 Ant Design Vue 组件
'input' a-input 文本输入框
'textarea' a-textarea 文本域
'input-search' a-input-search 搜索输入框
'input-password' a-input-password 密码框
'input-number' a-input-number 数字输入框
'select' a-select 下拉选择器
'cascader' a-cascader 级联选择器
'date-picker' a-date-picker 日期选择器
'range-picker' a-range-picker 日期范围选择器
'time-picker' a-time-picker 时间选择器
'checkbox-group' a-checkbox-group 复选框组
'radio-group' a-radio-group 单选按钮组
'switch' a-switch 开关切换器
'slider' a-slider 滑动条
'tree-select' a-tree-select 树形选择器
'transfer' a-transfer 穿梭框
'custom' 完全渲染自定义组件

🧩 自定义组件(4 种方式)

Field.component 的解析优先级(高 -> 低):

teleport 插槽注入 > ProComponentProvider.componentMap > 内置 componentMap > 原始 component 值

方式 1:传入 SFC 单文件组件对象(推荐,单字段最常用)

component 直接传组件对象,必须用 markRaw 包裹:

import { markRaw } from 'vue';
import MyInput from './MyInput.vue';

const fields = [{ path: 'code', label: '验证码', component: markRaw(MyInput) }];

⚠️ 必须 markRaw:不包会被 Vue 当成响应式对象深度代理,触发性能警告甚至渲染异常。类型上 component 接受 RenderComponentType | Raw<RenderComponentType>,Raw<T> 即 markRaw 的类型标记。此字段不支持响应式(不能包 ref/computed)。

方式 2:传入 render 函数(单字段,需动态拼装 props 时)

component 传 (props, ctx) => VNode。props 含 v-model 绑定值与 path,ctx.attrs 含透传属性:

import { h } from 'vue';
import MyInput from './MyInput.vue';

const fields = [
  {
    path: 'code',
    label: '验证码',
    component: (p, ctx) => h(MyInput, { ...p, ...ctx.attrs }),
  },
];
方式 3:ProComponentProvider 注入 componentMap(全局复用,推荐多字段场景)

在根用 componentMap 注册,Field 里用字符串引用。可覆盖内置组件(如 input: MyInput 替换全局 input)。

<script setup lang="ts">
import { ProComponentProvider } from '@qin-ui/antd-vue-pro';
import MyRichTextEditor from './components/MyRichTextEditor.vue';

const componentMap = {
  'rich-editor': MyRichTextEditor,
};
</script>

<template>
  <ProComponentProvider :component-map="componentMap">
    <AppLayout />
  </ProComponentProvider>
</template>

追加 TypeScript 全局声明获取强类型补全(项目任意 .d.ts):

declare module '@qin-ui/antd-vue-pro' {
  interface ComponentMap {
    'rich-editor': typeof MyRichTextEditor;
  }
}

之后 component: 'rich-editor' 即获精准属性类型联想与校验。

方式 4:模板 scoped slot(声明式,简单替换)

插槽名 = 字段 path,绑定参数通过 v-bind="scoped" 转发(teleport 机制,优先级最高):

<ProForm :form="form">
  <template #agreement="scoped">
    <a-checkbox v-bind="scoped">同意协议</a-checkbox>
  </template>
</ProForm>
选择建议
场景 推荐方式
单字段复用一个 SFC 方式 1(markRaw(SFC))
单字段、需动态拼装 props 方式 2(render 函数)
多处复用 / 替换内置组件 方式 3(componentMap + 声明扩充)
简单声明式替换、不想写 h() 方式 4(scoped slot)
自定义组件需遵守的约定
  • v-model:默认绑 value(v-model:value)。若组件用别的 prop(如 Switch 用 checked),通过字段 modelProp 指定,或在 componentVars 预设 modelProp。
  • 接收 path:组件会收到 path prop(字段路径),可用于透传或标识。
  • 属性透传:Field 上除框架级属性外(component / hidden / modelProp / valueFormatter / fields / slots / formItemContainer / componentContainer / extraProps 等),其余作为 attrs 透传给自定义组件。

Peer Dependencies

依赖包名称 推荐版本要求
vue ^3.5.0
ant-design-vue ^4.0.0

🤝 贡献与反馈

欢迎在任何时候通过 GitHub Issues 提交对本子包的优化建议和反馈。

📄 开源许可证

基于 MIT 开源许可证。

Related Packages

@qin-ui/vant-pro

基于 vant 和 @qin-ui/pro-components-core 封装的高级表单和列表组件库

3,916 5
el-search-table-pagination

A component which combines form、table with pagination components in Element UI.

3,527 303
pro-my-ui

组件库教程

1,223
el-table-pagination

A Component Library for Vue.js.

1,088 5

Version History

Version Released Vue License
2.4.5 ^3.5.0 MIT
2.4.4 ^3.5.0 MIT
2.4.3 ^3.5.0 MIT
2.4.2 ^3.5.0 MIT
2.4.1 ^3.5.0 MIT