Phase 006: migrate the chat page from naive-ui to Arco Design Vue
Swaps the rendering layer only. Chat store logic, keyboard handling, and the /chat-run Socket.IO contract are untouched, so a mixed UI cannot hide a chat regression behind a library swap. Arco's dropdowns take their items from a #content slot of a-doption children rather than a droplist prop, and Arco Triggers cannot be nested, so the two toolbar menus lost their a-tooltip in favour of a native title. Both rules are recorded in docs/arco-mapping.md, and tests/e2e/chat-input-dropdown.spec.ts plus tests/e2e/chat-rendering-smoke.spec.ts keep the menus, the streaming markdown rendering, and the no-Arco-inside-the-bubble red line from regressing silently.
This commit is contained in:
+23
-4
@@ -21,13 +21,15 @@ Phase 005 起,新代码与迁移代码一律使用 Arco Design Vue。本文表
|
||||
|
||||
| Naive | Arco | 用量 | 备注 |
|
||||
|---|---|---|---|
|
||||
| `NButton` | `a-button` | 732 | `block`→`long`、`size="tiny"`→`size="mini"`、`type="warning"`→`type="primary" status="warning"`、`quaternary`→`status="secondary"` |
|
||||
| `NButton` | `a-button` | 732 | `block`→`long`、`size="tiny"`→`size="mini"`、`type="warning"`→`type="primary" status="warning"`、`quaternary`/`secondary`→`type="secondary"`(Arco `status` 只有 `normal\|success\|warning\|danger`,没有 `secondary`) |
|
||||
| `NInput` | `a-input` / `a-textarea` | 160 | `type="textarea"` 用独立 `a-textarea`;`a-input` 关闭了 attrs 透传,`autofocus` 无效,需 `ref` + `focus()` |
|
||||
| `NModal` | `a-modal` | 138 | `v-model:show`→`v-model:visible`;`preset="dialog"` 无对应,信息型弹窗用 `:footer="false"`(`footer` 为 Boolean prop,默认 true) |
|
||||
| `NFormItem` | `a-form-item` | 136 | 校验规则 API 不同(`rules` 结构、`required` 表达式)需适配 |
|
||||
| `NSelect` | `a-select` | 97 | `options` 的 `label/value` 语义一致;`consistent-menu-width` 等 prop 无对应 |
|
||||
| `NSpin` | `a-spin` | 86 | `show`→`loading` |
|
||||
| `NTooltip` | `a-tooltip` | 76 | `trigger="hover"` 默认一致;`placement` 语义基本一致 |
|
||||
| `NTooltip` | `a-tooltip` | 76 | `trigger="hover"` 默认一致;`placement`→`position`;**触发元素走默认插槽**,naive 的 `<template #trigger>` 必须拆掉 |
|
||||
| `NPopconfirm` / `NTooltip` 的 `#trigger` 槽 | Arco 默认插槽 | — | Arco 的 `a-tooltip` / `a-popconfirm` / `a-dropdown` 都用默认插槽承载触发元素,naive 的 `<template #trigger>` 写法会静默丢内容 |
|
||||
| Arco Trigger 嵌套 | 不可嵌套,无论谁包谁 | — | `a-tooltip` / `a-dropdown` / `a-popconfirm` 内部都用 `mergeFirstChild` 找首个元素节点并各自接管事件;嵌套时两个 popup 容器互相踩,菜单**点不开**(`.arco-trigger-popup-wrapper` 卡在过渡中间态、选项数为 0)。同一触发元素要同时有说明文案和下拉时,说明文案改用原生 `:title`,不要套 `a-tooltip` |
|
||||
| `NTag` | `a-tag` | 57 | `bordered` prop 存在(默认 true);`size="small"` 一致;naive `type="info"`→`color="arcoblue"` 等内建色(`red/orange/green/arcoblue/...`),自定义色用 `color` 传 CSS 颜色 |
|
||||
| `NSwitch` | `a-switch` | 53 | `value`/`v-model` 一致 |
|
||||
| `NSpace` | `a-space` | 51 | `size` 语义一致(数字/预设名) |
|
||||
@@ -36,7 +38,7 @@ Phase 005 起,新代码与迁移代码一律使用 Arco Design Vue。本文表
|
||||
| `NForm` | `a-form` | 32 | 校验规则 API 不同,需适配 |
|
||||
| `NTabPane` | `a-tab-pane` | 30 | `NTabs/NTabPane` → `a-tabs/a-tab-pane` |
|
||||
| `NDrawer` / `NDrawerContent` | `a-drawer` | 27 | Arco 无独立 content 组件;`footer` slot 用 `a-drawer` 的 `footer` |
|
||||
| `NDropdown` | `a-dropdown` | 25 | `options` 结构不同(`label`→`content`,需转换函数) |
|
||||
| `NDropdown` | `a-dropdown` | 25 | **Arco 没有 `droplist` prop**:菜单内容必须写进 `#content` 插槽、用 `a-doption` / `a-dsubmenu` 声明。传 `:droplist` 会被静默忽略,弹层能打开但 `<ul class="arco-dropdown-list">` 是空的;子菜单用 `a-dsubmenu` + 自己的 `#content` 插槽 |
|
||||
| `NDescriptions` / `NDescriptionsItem` | `a-descriptions` / `a-descriptions-item` | 19 | 基本一致 |
|
||||
| `NAlert` | `a-alert` | 19 | `type` 一致;`show-icon` 一致 |
|
||||
| `NRadioButton` / `NRadioGroup` / `NRadio` | `a-radio`(`type="radio-button"`)/ `a-radio-group` | 32 | Arco radio-button 是 `a-radio` 的 `type` prop |
|
||||
@@ -50,7 +52,7 @@ Phase 005 起,新代码与迁移代码一律使用 Arco Design Vue。本文表
|
||||
| `NDataTable` | `a-table` | 4 | **列定义 API 差异最大**(`columns`/`render`/`slots`),逐例处理 |
|
||||
| `NSlider` | `a-slider` | 3 | 基本一致 |
|
||||
| `NScrollbar` | `a-scrollbar` | 3 | Arco 全局可用,无需组件包裹注册 |
|
||||
| `NPopselect` | `a-select`(`trigger-element`) | 3 | 无直接对应,改用 `a-dropdown` 或带 trigger 的 `a-select` |
|
||||
| `NPopselect` | `a-dropdown` | 3 | 无直接对应。实测 `a-dropdown` + `:droplist`(`key`/`content`)可完整替代 |
|
||||
| `NPopover` | `a-popover` | 3 | `trigger` 语义有差异 |
|
||||
| `NIcon` | `<icon-*>`(`@arco-design/web-vue/es/icon`) | 3 | Arco 图标是独立组件,需 import |
|
||||
| `NBadge` | `a-badge` | 3 | `value`→`count` |
|
||||
@@ -63,3 +65,20 @@ Phase 005 起,新代码与迁移代码一律使用 Arco Design Vue。本文表
|
||||
|
||||
- Phase 006:聊天页(`components/hermes/chat/`)——消息气泡内部**不用** Arco 组件(性能红线)
|
||||
- Phase 007:其余视图 + `stores/` + `composables/` 批量替换 + 删除 naive-ui 依赖
|
||||
|
||||
## 例外
|
||||
|
||||
- 聊天虚拟滚动区不用 `a-scrollbar` 包裹。`VirtualMessageList.vue` 直接用
|
||||
`vue-virtual-scroller` 的 `DynamicScroller` 独占滚动(原本也没有 `NScrollbar`),
|
||||
额外包一层滚动容器会破坏高度测量与 sticky 定位。
|
||||
- 测试里 Arco 组件的 stub 必须用 Arco 内部组件名(`Dropdown` / `Modal` / `Spin`),
|
||||
而不是模板里的 `a-*` 标签名:`app.use(ArcoVue)` 之后组件已全局注册,VTU 的
|
||||
`stubs` 只按内部名匹配,用 `ADropdown` 会静默不生效。
|
||||
- `ChatInput.vue` 的推理强度按钮、输入设置按钮放弃 `a-tooltip`,改用原生 `:title`。
|
||||
这两个按钮必须挂 `a-dropdown`,而 Trigger 不能嵌套(见上表同名行),因此失去
|
||||
Arco 的悬浮气泡;文案与 `aria-label` 都保留,信息量不变。
|
||||
- Arco(和 Vue 本身)不会对拼错的 prop 报错,未声明的 prop 会作为普通 attribute
|
||||
落到根元素上。所以「弹层能打开、但内容是空的」几乎总是 prop 写错而不是数据为空。
|
||||
排查手法:`el.__vueParentComponent.props` 看目标组件到底认不认这个 prop,
|
||||
再看 `el.outerHTML` 确认渲染出来的骨架。回归由
|
||||
`tests/e2e/chat-input-dropdown.spec.ts` 卡住。
|
||||
|
||||
Reference in New Issue
Block a user