antdv-next 迁移指南
💡 如果您使用 AI Agent,可以将本文档提交给 AI,让它出 plan 后,协助您完成以下工作。
提示:AI 辅助迁移后,仍需人工 review 和测试,特别是 Tree、Form 等复杂组件。
# 一、新增功能
# 1.1 核心组件增强
# Table 组件
- 新增
useBasicTable: 替代useTable,直接返回组件对象,省去 register 代码。 - 新增
columnResizable属性: 支持全局设置列宽调整功能 - 新增
dragColumnProps属性: 拖拽列参数配置
注意: useTable 仍然支持,使用 AI 迁移时,不必替换为 useBasicTable
# Form 组件
- 新增
useBasicForm: 替代useForm,直接返回组件对象,省去 register 代码
注意: useForm 仍然支持,使用 AI 迁移时,不必替换为 useBasicForm
# 其他组件
- ListSelect 新增事件:
'update:value','update:labelValue'事件 - setAuthCache 新增
immediate参数: 支持立即执行缓存设置
# 1.2 工具函数增强
- useRuleFormItem 新增参数: 增加
valueField和labelField传参支持 - useFormValues 增强: 支持嵌套字段名(包含点号)设置表单值
- window.emitter 全局事件监听工具: 初始化全局事件监听,多页面交互尤为重要
# 1.3 依赖和工具链
- 添加 oxlint、oxfmt 插件: 现代化 lint 工具(暂时保留 eslint、prettier、stylelint)
# 二、优化改进
# 2.1 性能优化
# 首屏加载优化
- 请求数量优化: 从 120 个请求减少到 30 个请求(减少 75%)
- 加载体积优化: 从 2.2MB 减少到 1.4MB(减少约 36%)
- 数据来源: 基于
pnpm preview本地预览环境,通过浏览器 DevTools Network 面板对比分析得出 - 速度提升: 在典型网络环境下,首屏加载速度,以及点击登录进入主页后,均有显著提升。
# 异步加载优化
- HR 仪表盘组件: 改为异步加载
- Bpm 组件: 改为异步加载
- MonacoEditor: 避免首屏加载
- 工作台面板: 组件异步加载
- 仪表盘和工作台页面: 组件异步加载
# 组件性能优化
- FormItem 重构: 性能提升,减少不必要的重复渲染,大幅度提升组件性能
- FormItem 更新机制优化: 使用
onUpdate:value替代onChange提升性能 - ref 引用优化: 将所有组件 ref 引用从
ref替换为shallowRef - UnoCSS: 大幅度提升 dev 下页面加载速度,减少不必要的加载
# 2.2 代码质量优化
# 代码规范
- 移除默认 install 方法: 当用到时再添加,不是每个组件都需要
- 业务代码不直接引用 antdv-next: 统一通过封装组件使用
- Promise 类型明确: 更新为
Promise<void>
# 类型优化
- 移除无用类型定义:
validate type ValidateFieldsTableCurrentDataSource
- 类型导入路径优化:
/lib/table/interface替换为 antdv-next/lib/form/interface替换为/dist/form/types/lib/grid/Col替换为/dist/grid/col
# 2.3 用户体验优化
- 主题设置页面细节配色优化
- 绿色主题色优化: 关闭页签按钮 hover 太亮等细节
- AI 对话样式优化: 自动折叠深度思考,发送按钮优化
- BasicTable 滚动条美化
- 全局更多细节调整美化
# 2.4 构建和优化
- 处理 unocss 和 lib 中的 unocss 冲突问题
- 消除 ECharts 的警告以及更多优化
- 优化 Vite theme 主题组件
# 三、迁移准备
# 3.1 环境检查
先将项目升级到 JeeSite Vue 5.17.1 的 ant-design-vue 版本。
# 3.2 了解变更范围
本次迁移涉及:
- 核心 UI 库替换:ant-design-vue → antdv-next
- Icons 库替换:@ant-design/icons-vue → @antdv-next/icons
- 大量组件 API 变更
- 样式系统调整
- 工具函数优化
- 性能提升优化
# 3.3 迁移建议
建议新项目或长期更新的产品迁移到 antdv-next,若是原来项目类型,建议保留原架构。新项目再使用 antdv-next。
如果您使用 AI Agent 可以将该文件提交给 AI 让它帮你。
注意,一定要先备份您的项目。
# 四、同步框架代码
通过创建新分支的方式,将 antdv-next 版本的代码合并到您的项目中,具体步骤如下:
# 4.1 创建 antdv-next 分支
# 在当前项目中创建一个新的分支
git checkout -b antdv-next
1
2
2
# 4.2 替换框架代码
# 下载 JeeSite Vue antdv-next 版本
git clone https://gitee.com/thinkgem/jeesite-vue.git temp-repo
# 切换到 antdv-next.dev 分支
cd temp-repo
git checkout antdv-next.dev
cd ..
# 复制核心文件到当前项目(保留您的业务代码)这是举例,根据你的项目情况拷贝
cp -r temp-repo/bin/* bin/
cp -r temp-repo/packages/* packages/
cp -r temp-repo/web/* web/
cp temp-repo/.* .
cp temp-repo/*.* .
# 清理临时目录
rm -rf temp-repo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
注意:
- ⚠️ 保留您的业务代码:不要覆盖除框架自带视图外,您的
/packages/**/views/下的业务页面 - ⚠️ 保留自定义配置:检查并合并您的自定义配置(通过git进行比较分析每一个文件)
- ⚠️ 备份重要文件:替换前先备份重要配置文件
# 4.3 提交分支代码
# 添加所有变更
git add .
# 提交更改
git commit -m "升级到 antdv-next 版本"
1
2
3
4
5
2
3
4
5
# 4.4 合并到主分支
确认 antdv-next 分支测试无误后,合并回主分支:
# 切换回主分支
git checkout main
# 合并 antdv-next 分支
git merge antdv-next
# 如果有冲突,手动解决后提交
git add .
git commit -m "合并 antdv-next 分支"
# 推送更新
git push origin main
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 处理合并冲突:通过 IDE git 管理工具手动 diff 合并代码
以上步骤完成后,JeeSite 平台底座已经更新,下面进行替换和修改业务代码。
# 五、全局替换策略
在 VSCode 或其他 IDE 中使用全局搜索替换:
搜索: 'ant-design-vue
替换为: 'antdv-next
1
2
2
搜索: @ant-design/icons-vue
替换为: @antdv-next/icons
1
2
2
# 六、组件 API 迁移
# 6.1 通用组件迁移清单
# Alert 组件
<!-- Before (ant-design-vue) -->
<Alert message="提示信息" />
<!-- After (antdv-next) -->
<Alert title="提示信息" />
1
2
3
4
5
2
3
4
5
message→title
# Tabs 组件
<!-- Before (ant-design-vue) -->
<template>
<Tabs tab-position="left">
<Tabs.TabPane key="1" tab="标签1">内容1</Tabs.TabPane>
<Tabs.TabPane key="2" tab="标签2">内容2</Tabs.TabPane>
</Tabs>
</template>
<script setup>
import { Tabs } from 'ant-design-vue'
</script>
<!-- After (antdv-next) -->
<template>
<Tabs tab-placement="start">
<TabPane key="1" tab="标签1">内容1</TabPane>
<TabPane key="2" tab="标签2">内容2</TabPane>
</Tabs>
</template>
<script setup>
import { Tabs, TabPane } from 'antdv-next'
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
注意:
Tabs.TabPane→TabPane(单独导入)tabPosition→tabPlacementactiveKey属性只能是 string 类型- rightExtra 插槽只能有一个元素
# Dropdown 组件
<!-- Before (ant-design-vue) -->
<Dropdown class="cursor-pointer">
<Button>下拉菜单</Button>
<template #overlay></template>
</Dropdown>
<!-- After (antdv-next) -->
<Dropdown>
<span class="cursor-pointer">
<Button>下拉菜单</Button>
</span>
<template #popupRender></template>
</Dropdown>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
overlay→popupRender- MenuItem
value→key - 不能接受 class,需要增加 div 接受
overlayClassName→classes.root
MenuItem 变更:
<!-- Before (ant-design-vue) -->
<Menu.Item value="1">选项1</Menu.Item>
<!-- After (antdv-next) -->
<MenuItem key="1">选项1</MenuItem>
1
2
3
4
5
2
3
4
5
# Drawer 组件
<!-- Before (ant-design-vue) -->
<Drawer
:width="800"
:destroy-on-close="true"
:mask-style="{ background: 'rgba(0,0,0,0.5)' }"
>
<!-- After (antdv-next) -->
<Drawer
size="large"
:destroy-on-hidden="true"
:styles="{ mask: { background: 'rgba(0,0,0,0.5)' } }"
>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
destroyOnClose→destroyOnHiddenwidth→sizemaskStyle→styles.mask
# Modal 组件
<!-- Before (ant-design-vue) -->
<Modal
:destroy-on-close="true"
class="custom-modal"
>
<!-- After (antdv-next) -->
<Modal
:destroy-on-hidden="true"
:classes="{ container: 'custom-modal' }"
>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
destroyOnClose→destroyOnHiddenclass→classes.container- 解决与内置 loading 冲突的情况
# Tooltip 组件
<!-- Before (ant-design-vue) -->
<Tooltip
overlay-class-name="custom-tooltip"
:overlay-style="{ color: 'red' }"
>
<!-- After (antdv-next) -->
<Tooltip
:classes="{ container: 'custom-tooltip' }"
:styles="{ container: { color: 'red' } }"
>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
overlayClassName→classes.containeroverlayStyle→styles.container
# Tree 组件
<!-- Before (ant-design-vue) -->
<Tree
:tree-data="treeData"
@load-data="onLoadData"
>
<template #title="{ dataRef }">
{{ dataRef.title }}
</template>
</Tree>
<script setup>
const onLoadData = (treeNode) => {
const key = treeNode.eventKey
// ...
}
</script>
<!-- After (antdv-next) -->
<Tree
:tree-data="treeData"
@load-data="onLoadData"
>
<template #titleRender="{ node }">
{{ node.title }}
</template>
</Tree>
<script setup>
const onLoadData = (treeNode) => {
const key = treeNode.id // 不再是 eventKey
// ...
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
items.title→ 插槽titleRendernode.dataRef→nodetree.dataRef→treeonLoadData事件参数treeNode.eventKey→treeNode.id- 加载时机和节点数据获取有变化
重要提示: Tree 组件加载时机和节点数据获取有变化,业务上使用的需要详细测试!
# Menu 组件
<!-- Before (ant-design-vue) -->
<template>
<Menu>
<SubMenu key="1">
<template #title>父菜单</template>
<MenuItem key="1-1">子菜单</MenuItem>
</SubMenu>
</Menu>
</template>
<script setup>
const handleClick = ({ item, key }) => {
console.log(item) // 有 item 参数
}
</script>
<!-- After (antdv-next) -->
<template>
<Menu>
<SubMenu key="1">
<template #title>父菜单</template>
<MenuItem key="1-1">子菜单</MenuItem>
</SubMenu>
</Menu>
</template>
<script setup>
import { Menu, SubMenu, MenuItem } from 'antdv-next'
const handleClick = ({ key }) => {
// 没有 item 参数了
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
重要提示:
Menu.SubMenu→SubMenu(单独导入)Menu.Item→MenuItem(单独导入)- onClick 没有了 item 参数
- Menu key 不能是数值类型
- Menu onClick 可能调用2次,需要注意
# Form 组件
<!-- Before (ant-design-vue) -->
<template>
<Form>
<Form.FormItem label="用户名">
<Input v-model:value="form.username" />
</Form.FormItem>
<Form.ItemRest>
<Button type="primary">提交</Button>
</Form.ItemRest>
</Form>
</template>
<!-- After (antdv-next) -->
<template>
<Form>
<FormItem label="用户名">
<Input v-model:value="form.username" />
</FormItem>
<!-- Form.ItemRest 已移除,无需添加 -->
<Button type="primary">提交</Button>
</Form>
</template>
<script setup>
import { Form, FormItem, Input, Button } from 'antdv-next'
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Input 组件变更:
<!-- Before (ant-design-vue) -->
<Input.Password />
<Input.Search />
<Input.Textarea />
<DatePicker.MonthPicker mode="month" />
<DatePicker.RangePicker mode="range" />
<DatePicker.WeekPicker mode="range" />
<!-- After (antdv-next) -->
<InputPassword />
<InputSearch />
<TextArea />
<DateMonthPicker />
<DateWeekPicker />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
Form.Item→FormItemForm.ItemRest移除(在 antdv-next 中无需添加)- Input.Group → InputGroup
- Input.Password → InputPassword
- Input.Search → InputSearch
- Input.TextArea → TextArea
- DatePicker.MonthPicker → DateMonthPicker
- DatePicker.RangePicker → DateRangePicker
- DatePicker.WeekPicker → DateWeekPicker
# Radio 组件
<!-- Before (ant-design-vue) -->
<template>
<Radio.Group>
<Radio.Button value="1">选项1</Radio.Button>
</Radio.Group>
</template>
<!-- After (antdv-next) -->
<template>
<RadioGroup>
<RadioButton value="1">选项1</RadioButton>
</RadioGroup>
</template>
<script setup>
import { RadioGroup, RadioButton } from 'antdv-next'
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Radio.Group→RadioGroupRadio.Button→RadioButton
# Checkbox 组件
<!-- Before (ant-design-vue) -->
<template>
<Checkbox.Group v-model:value="checkedList">
<Checkbox value="1">选项1</Checkbox>
</Checkbox.Group>
</template>
<!-- After (antdv-next) -->
<template>
<CheckboxGroup v-model:value="checkedList">
<Checkbox value="1">选项1</Checkbox>
</CheckboxGroup>
</template>
<script setup>
import { CheckboxGroup, Checkbox } from 'antdv-next'
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Checkbox.Group→CheckboxGroup
# Collapse 组件
<!-- Before (ant-design-vue) -->
<template>
<Collapse>
<Collapse.Panel key="1" header="标题1">
内容1
</Collapse.Panel>
</Collapse>
</template>
<!-- After (antdv-next) -->
<template>
<Collapse>
<CollapsePanel key="1" header="标题1">
内容1
</CollapsePanel>
</Collapse>
</template>
<script setup>
import { Collapse, CollapsePanel } from 'antdv-next'
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Collapse.Panel→CollapsePanel
# Descriptions 组件
<!-- Before (ant-design-vue) -->
<template>
<Descriptions>
<Descriptions.Item label="姓名">张三</Descriptions.Item>
</Descriptions>
</template>
<!-- After (antdv-next) -->
<template>
<Descriptions>
<DescriptionsItem label="姓名">张三</DescriptionsItem>
</Descriptions>
</template>
<script setup>
import { Descriptions, DescriptionsItem } from 'antdv-next'
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Descriptions.Item→DescriptionsItem
# Layout 组件
<!-- Before (ant-design-vue) -->
<template>
<Layout>
<Layout.Header>头部</Layout.Header>
<Layout.Sider>侧边栏</Layout.Sider>
<Layout.Content>内容</Layout.Content>
<Layout.Footer>底部</Layout.Footer>
</Layout>
</template>
<!-- After (antdv-next) -->
<template>
<Layout>
<LayoutHeader>头部</LayoutHeader>
<LayoutSider>侧边栏</LayoutSider>
<LayoutContent>内容</LayoutContent>
<LayoutFooter>底部</LayoutFooter>
</Layout>
</template>
<script setup>
import { Layout, LayoutHeader, LayoutSider, LayoutContent, LayoutFooter } from 'antdv-next'
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Layout.Header→LayoutHeaderLayout.Footer→LayoutFooterLayout.Sider→LayoutSiderLayout.Content→LayoutContent
注意: Layout 组件需要增加背景色
# List 组件(已移除)
<!-- Before (ant-design-vue) -->
<List :data-source="listData">
<template #renderItem="{ item }">
<ListItem>{{ item.name }}</ListItem>
</template>
</List>
<!-- After (antdv-next) -->
<div class="flex flex-col">
<div v-for="item in listData" :key="item.id" class="p-2">
{{ item.name }}
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- antdv-next 没有了 List 组件,使用 Flex/div 替代
# Breadcrumb 组件
<!-- Before (ant-design-vue) -->
<Breadcrumb :routes="routes">
<template #itemRender="{ route }">
{{ route.breadcrumbName }}
</template>
</Breadcrumb>
<!-- After (antdv-next) -->
<Breadcrumb :items="items">
<template #itemRender="{ route }">
{{ item.title }}
</template>
</Breadcrumb>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
routes→itemsroutes.children→item.menu
# BackTop 组件
<!-- Before (ant-design-vue) -->
<FloatButton.BackTop />
<!-- After (antdv-next) -->
<BackTop />
1
2
3
4
5
2
3
4
5
- antdv-next 未导出
FloatButton.BackTop,使用BackTop
# Spin/Loading 组件
<!-- Before (ant-design-vue) -->
<template>
<Spin tip="加载中..." />
</template>
<!-- After (antdv-next) -->
<template>
<Spin description="加载中..." />
</template>
<script setup>
import { Spin } from 'antdv-next'
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
tip→description
# Notification 组件
message→title
# 6.2 Table 组件专项迁移
Table 组件变更最多,需要特别注意:
<!-- Before (ant-design-vue) -->
<BasicTable
:custom-cell="customCell"
:custom-row="customRow"
scroll="{ x: 1200 }"
>
<!-- 筛选图标和下拉菜单插槽 -->
<template #customFilterIcon="{ column }">
<FilterIcon :column="column" />
</template>
<template #customFilterDropdown="{ column }">
<FilterDropdown :column="column" />
</template>
</BasicTable>
<!-- After (antdv-next) -->
<BasicTable
:on-cell="onCell"
:on-row="onRow"
>
<!-- 筛选图标和下拉菜单插槽(名称变更) -->
<template #filterIcon="{ column }">
<FilterIcon :column="column" />
</template>
<template #filterDropdown="{ column }">
<FilterDropdown :column="column" />
</template>
</BasicTable>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
重要提示:
customFilterIcon→filterIcon(插槽)customFilterDropdown→filterDropdown(插槽)onFilter→filterSearchcustomCell→onCellcustomRow→onRowgetBindValues不存在问题(使用干净的 getProps)- ColumnSetting:
overlayClassName→classes.container - EditableCell:
dropdownMatchSelectWidth→popupMatchSelectWidth - SizeSetting:
overlay→popupRender - scroll.x 支持 string 类型
- fixed 增加 start、end 值
- Action 操作列 color 增加 primary 和 danger
# 七、样式和主题迁移
多个组件的样式类名传递方式发生变化:
<!-- Tooltip -->
<!-- Before (ant-design-vue) -->
<Tooltip overlay-class-name="custom" :overlay-style="{ color: 'red' }" />
<!-- After (antdv-next) -->
<Tooltip :classes="{ container: 'custom' }" :styles="{ container: { color: 'red' } }" />
<!-- Dropdown -->
<!-- Before (ant-design-vue) -->
<Dropdown overlay-class-name="custom" />
<!-- After (antdv-next) -->
<Dropdown :classes="{ root: 'custom' }" />
<!-- Drawer -->
<!-- Before (ant-design-vue) -->
<Drawer :mask-style="{ background: 'rgba(0,0,0,0.5)' }" />
<!-- After (antdv-next) -->
<Drawer :styles="{ mask: { background: 'rgba(0,0,0,0.5)' } }" />
<!-- Modal -->
<!-- Before (ant-design-vue) -->
<Modal class="custom-modal" />
<!-- After (antdv-next) -->
<Modal :classes="{ container: 'custom-modal' }" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 相关资源
- antdv-next 官方迁移文档 (opens new window)
- 为什么使用 antdv-next (opens new window)
- JeeSite 文档 (opens new window)
# 重要提醒
- Tree 组件变化最大: 加载时机和节点数据获取有变化,必须详细测试所有使用 Tree 的功能
- Form 验证规则变更: 从自动验证改为手动触发,检查所有表单提交逻辑
- List 组件已移除: 需要使用 Flex 或 div 自行实现列表样式
- 渐进式迁移: 建议分模块逐步迁移,每完成一个模块就进行测试
- 如果您是 AI Agent 请确保
pnpm lint:all命令无错误
若文档中存在疏漏或您有宝贵建议,敬请不吝告知,我们将非常感谢并及时跟进。
