# 自定义适配器开发

<cite>
**本文档引用的文件**
- [README.md](file://README.md)
- [ARCHITECTURE_SUMMARY.md](file://ARCHITECTURE_SUMMARY.md)
- [MIGRATION.md](file://MIGRATION.md)
- [packages/index.js](file://packages/index.js)
- [packages/core/src/index.js](file://packages/core/src/index.js)
- [packages/core/src/ui-adapter/types.ts](file://packages/core/src/ui-adapter/types.ts)
- [packages/core/src/ui-adapter/inject.ts](file://packages/core/src/ui-adapter/inject.ts)
- [packages/adapters/view-ui-plus/src/index.js](file://packages/adapters/view-ui-plus/src/index.js)
- [packages/adapters/element-plus/src/index.js](file://packages/adapters/element-plus/src/index.js)
- [packages/core/src/components/ProForm.vue](file://packages/core/src/components/ProForm.vue)
- [packages/core/src/components/ProSearch.vue](file://packages/core/src/components/ProSearch.vue)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本指南面向希望为 ProIView v2 创建自定义 UI 适配器的开发者，系统讲解适配器接口规范、组件映射规则、统一 API 设计原则、开发流程与最佳实践，并提供从零开始创建新适配器的完整示例路径与调试方法。

## 项目结构
该仓库采用 Monorepo 架构，核心包与适配器包分离，通过依赖注入机制实现 UI 库解耦：

- packages/core：核心业务逻辑与 UI 适配器接口定义
- packages/adapters：各 UI 库适配器实现（view-ui-plus、element-plus）
- packages/compat：向后兼容包
- packages/index.js：传统入口（v1.x）导出

```mermaid
graph TB
subgraph "核心包"
CORE["packages/core/src/index.js"]
TYPES["packages/core/src/ui-adapter/types.ts"]
INJECT["packages/core/src/ui-adapter/inject.ts"]
PROFORM["packages/core/src/components/ProForm.vue"]
PROSEARCH["packages/core/src/components/ProSearch.vue"]
end
subgraph "适配器"
ADAPTER_VIEW["packages/adapters/view-ui-plus/src/index.js"]
ADAPTER_ELEMENT["packages/adapters/element-plus/src/index.js"]
end
subgraph "入口"
PKG_INDEX["packages/index.js"]
end
CORE --> TYPES
CORE --> INJECT
PROFORM --> INJECT
PROSEARCH --> INJECT
CORE --> ADAPTER_VIEW
CORE --> ADAPTER_ELEMENT
PKG_INDEX --> CORE
```

图表来源
- [packages/core/src/index.js:1-85](file://packages/core/src/index.js#L1-L85)
- [packages/core/src/ui-adapter/types.ts:1-60](file://packages/core/src/ui-adapter/types.ts#L1-L60)
- [packages/core/src/ui-adapter/inject.ts:1-43](file://packages/core/src/ui-adapter/inject.ts#L1-L43)
- [packages/adapters/view-ui-plus/src/index.js:1-64](file://packages/adapters/view-ui-plus/src/index.js#L1-L64)
- [packages/adapters/element-plus/src/index.js:1-109](file://packages/adapters/element-plus/src/index.js#L1-L109)
- [packages/index.js:1-69](file://packages/index.js#L1-L69)

章节来源
- [README.md:1-18](file://README.md#L1-L18)
- [ARCHITECTURE_SUMMARY.md:59-120](file://ARCHITECTURE_SUMMARY.md#L59-L120)

## 核心组件
本节聚焦适配器开发的关键构件：接口定义、注入机制与核心包安装流程。

- UI 适配器接口定义：统一 Form、Input、Button、Table、Modal、Message、Icon 等组件与 API 规范
- 依赖注入机制：provide/use 实现适配器注入，未安装适配器时抛出明确错误
- 核心包安装流程：解析 opts.adapter，注入并可选执行适配器 install(app)

章节来源
- [packages/core/src/ui-adapter/types.ts:9-48](file://packages/core/src/ui-adapter/types.ts#L9-L48)
- [packages/core/src/ui-adapter/inject.ts:15-34](file://packages/core/src/ui-adapter/inject.ts#L15-L34)
- [packages/core/src/index.js:13-57](file://packages/core/src/index.js#L13-L57)

## 架构总览
下图展示了核心包如何通过注入机制使用适配器，以及两种现有适配器的实现要点。

```mermaid
graph TB
APP["应用"]
PRO_PLUGIN["ProCore 插件<br/>packages/core/src/index.js"]
INJECT["useUIAdapter()<br/>packages/core/src/ui-adapter/inject.ts"]
TYPES["UIAdapter 接口<br/>packages/core/src/ui-adapter/types.ts"]
VIEW_ADAPTER["ViewUIPlusAdapter<br/>packages/adapters/view-ui-plus/src/index.js"]
ELEMENT_ADAPTER["ElementPlusAdapter<br/>packages/adapters/element-plus/src/index.js"]
APP --> PRO_PLUGIN
PRO_PLUGIN --> INJECT
INJECT --> VIEW_ADAPTER
INJECT --> ELEMENT_ADAPTER
PRO_PLUGIN --> TYPES
```

图表来源
- [packages/core/src/index.js:25-31](file://packages/core/src/index.js#L25-L31)
- [packages/core/src/ui-adapter/inject.ts:23-34](file://packages/core/src/ui-adapter/inject.ts#L23-L34)
- [packages/core/src/ui-adapter/types.ts:9-48](file://packages/core/src/ui-adapter/types.ts#L9-L48)
- [packages/adapters/view-ui-plus/src/index.js:23-61](file://packages/adapters/view-ui-plus/src/index.js#L23-L61)
- [packages/adapters/element-plus/src/index.js:66-106](file://packages/adapters/element-plus/src/index.js#L66-L106)

## 详细组件分析

### 适配器接口规范
- 组件映射：Form、FormItem；Input、Select、Option、Checkbox；Button；Table、TableColumn；Modal；Icon；可选 Page
- 反馈组件 API：统一 info/success/warning/error/loading/destroy，满足核心组件的消息提示需求
- 安装函数：install(app)，用于注册全局组件或进行额外初始化（如 element-plus 的 CompatibleIcon）

章节来源
- [packages/core/src/ui-adapter/types.ts:9-48](file://packages/core/src/ui-adapter/types.ts#L9-L48)

### 依赖注入机制
- provideUIAdapter(adapter)：在核心包安装时注入适配器实例
- useUIAdapter()：在组件中获取适配器；若未安装则抛出明确错误，指导用户正确安装适配器

章节来源
- [packages/core/src/ui-adapter/inject.ts:15-34](file://packages/core/src/ui-adapter/inject.ts#L15-L34)

### 核心包安装流程
- 解析 opts.adapter 并调用 provideUIAdapter
- 若适配器提供 install(app)，则在安装时执行
- 注册全局组件与指令，挂载国际化与工具库

章节来源
- [packages/core/src/index.js:13-57](file://packages/core/src/index.js#L13-L57)

### 现有适配器实现对比
- view-ui-plus 适配器：直接映射组件与统一 Message API
- element-plus 适配器：提供 CompatibleIcon 兼容层与统一 Message API，并注册全局组件

章节来源
- [packages/adapters/view-ui-plus/src/index.js:23-61](file://packages/adapters/view-ui-plus/src/index.js#L23-L61)
- [packages/adapters/element-plus/src/index.js:29-61](file://packages/adapters/element-plus/src/index.js#L29-L61)
- [packages/adapters/element-plus/src/index.js:87-106](file://packages/adapters/element-plus/src/index.js#L87-L106)

### 核心组件如何使用适配器
- ProForm 与 ProSearch 在 computed 中通过 useUIAdapter() 获取 Form、FormItem、Input、Button、Icon 等组件
- 保证核心组件不直接依赖具体 UI 库，实现与 UI 的解耦

章节来源
- [packages/core/src/components/ProForm.vue:159-173](file://packages/core/src/components/ProForm.vue#L159-L173)
- [packages/core/src/components/ProSearch.vue:124-135](file://packages/core/src/components/ProSearch.vue#L124-L135)

### 适配器开发流程（从零开始）
以下为创建新 UI 适配器的完整步骤与参考路径，便于对照实现：

1. 创建适配器目录与入口
   - 参考路径：[packages/adapters/view-ui-plus/src/index.js:1-64](file://packages/adapters/view-ui-plus/src/index.js#L1-L64)、[packages/adapters/element-plus/src/index.js:1-109](file://packages/adapters/element-plus/src/index.js#L1-L109)
   - 建议目录结构：packages/adapters/<ui-lib>/src/index.js 与 types/

2. 实现 UIAdapter 接口
   - 组件映射：Form、FormItem、Input、Select、Option、Checkbox、Button、Table/TableColumn、Modal、Icon
   - 反馈组件：统一 Message API（info/success/warning/error/loading/destroy）
   - 可选：Page
   - 参考接口定义：[packages/core/src/ui-adapter/types.ts:9-48](file://packages/core/src/ui-adapter/types.ts#L9-L48)

3. 处理 UI 差异
   - 图标差异：element-plus 需要图标组件注册，可参考 CompatibleIcon 的思路
     - 参考实现：[packages/adapters/element-plus/src/index.js:29-61](file://packages/adapters/element-plus/src/index.js#L29-L61)
   - 消息反馈差异：统一 API，必要时对 loading/destroy 行为做兼容
     - 参考实现：[packages/adapters/element-plus/src/index.js:87-106](file://packages/adapters/element-plus/src/index.js#L87-L106)、[packages/adapters/view-ui-plus/src/index.js:43-51](file://packages/adapters/view-ui-plus/src/index.js#L43-L51)

4. 编写适配器安装函数
   - 在 install(app) 中注册全局组件或进行额外初始化
   - 参考实现：[packages/adapters/element-plus/src/index.js:101-106](file://packages/adapters/element-plus/src/index.js#L101-L106)、[packages/adapters/view-ui-plus/src/index.js:57-61](file://packages/adapters/view-ui-plus/src/index.js#L57-L61)

5. 在核心包中使用适配器
   - 在应用中安装 ProCore，并传入 opts.adapter
   - 参考使用方式：[ARCHITECTURE_SUMMARY.md:160-174](file://ARCHITECTURE_SUMMARY.md#L160-L174)

6. 验证与测试
   - 在示例项目中验证适配器可用性
   - 参考示例：[ARCHITECTURE_SUMMARY.md:235-279](file://ARCHITECTURE_SUMMARY.md#L235-L279)

章节来源
- [MIGRATION.md:141-154](file://MIGRATION.md#L141-L154)
- [packages/adapters/view-ui-plus/src/index.js:23-61](file://packages/adapters/view-ui-plus/src/index.js#L23-L61)
- [packages/adapters/element-plus/src/index.js:29-61](file://packages/adapters/element-plus/src/index.js#L29-L61)
- [packages/adapters/element-plus/src/index.js:87-106](file://packages/adapters/element-plus/src/index.js#L87-L106)
- [packages/core/src/ui-adapter/types.ts:9-48](file://packages/core/src/ui-adapter/types.ts#L9-L48)
- [ARCHITECTURE_SUMMARY.md:160-174](file://ARCHITECTURE_SUMMARY.md#L160-L174)
- [ARCHITECTURE_SUMMARY.md:235-279](file://ARCHITECTURE_SUMMARY.md#L235-L279)

### 组件映射规则与统一 API 设计
- 组件映射：确保核心组件所需的所有 UI 组件均可通过 useUIAdapter() 获取
- 统一 API：Message 组件需提供一致的方法签名，避免核心组件在不同 UI 库间切换时出现兼容问题
- 可选组件：Page 等非必需组件可按需提供，保持接口一致性

章节来源
- [packages/core/src/ui-adapter/types.ts:9-48](file://packages/core/src/ui-adapter/types.ts#L9-L48)

### 错误处理与配置选项
- 未安装适配器：useUIAdapter() 会抛出明确错误，指导用户正确安装
- 全局配置：核心包通过 opts.pro_iview.format 与 opts.pro_iview.map 提供格式化与映射配置
- 参考实现：[packages/core/src/ui-adapter/inject.ts:26-31](file://packages/core/src/ui-adapter/inject.ts#L26-L31)、[packages/core/src/index.js:17-19](file://packages/core/src/index.js#L17-L19)

章节来源
- [packages/core/src/ui-adapter/inject.ts:26-31](file://packages/core/src/ui-adapter/inject.ts#L26-L31)
- [packages/core/src/index.js:17-19](file://packages/core/src/index.js#L17-L19)

### 最佳实践
- 命名约定：适配器导出常量名称建议采用 UI_LIB_NAMEAdapter（如 ViewUIPlusAdapter、ElementPlusAdapter）
- 代码结构：将组件映射、Message 统一 API、install(app) 分块组织，便于维护
- 测试策略：为适配器编写单元测试，覆盖组件映射、Message API 与 install(app) 的行为
- 类型定义：为适配器提供 TypeScript 类型定义，提升开发体验
- 参考实现：[packages/adapters/view-ui-plus/src/index.js:23-61](file://packages/adapters/view-ui-plus/src/index.js#L23-L61)、[packages/adapters/element-plus/src/index.js:66-106](file://packages/adapters/element-plus/src/index.js#L66-L106)

章节来源
- [packages/adapters/view-ui-plus/src/index.js:23-61](file://packages/adapters/view-ui-plus/src/index.js#L23-L61)
- [packages/adapters/element-plus/src/index.js:66-106](file://packages/adapters/element-plus/src/index.js#L66-L106)

### 调试方法与常见问题
- 未安装适配器：useUIAdapter() 抛错，检查是否正确传入 opts.adapter
  - 参考：[packages/core/src/ui-adapter/inject.ts:26-31](file://packages/core/src/ui-adapter/inject.ts#L26-L31)
- 图标组件缺失：element-plus 需要全局注册图标组件，否则 CompatibleIcon 会输出警告
  - 参考：[packages/adapters/element-plus/src/index.js:52-57](file://packages/adapters/element-plus/src/index.js#L52-L57)
- Message API 差异：确保统一 API，loading/destroy 行为一致
  - 参考：[packages/adapters/element-plus/src/index.js:87-106](file://packages/adapters/element-plus/src/index.js#L87-L106)、[packages/adapters/view-ui-plus/src/index.js:43-51](file://packages/adapters/view-ui-plus/src/index.js#L43-L51)
- 安装顺序：先安装 UI 库，再安装 ProCore 与适配器
  - 参考示例：[ARCHITECTURE_SUMMARY.md:235-279](file://ARCHITECTURE_SUMMARY.md#L235-L279)

章节来源
- [packages/core/src/ui-adapter/inject.ts:26-31](file://packages/core/src/ui-adapter/inject.ts#L26-L31)
- [packages/adapters/element-plus/src/index.js:52-57](file://packages/adapters/element-plus/src/index.js#L52-L57)
- [packages/adapters/element-plus/src/index.js:87-106](file://packages/adapters/element-plus/src/index.js#L87-L106)
- [packages/adapters/view-ui-plus/src/index.js:43-51](file://packages/adapters/view-ui-plus/src/index.js#L43-L51)
- [ARCHITECTURE_SUMMARY.md:235-279](file://ARCHITECTURE_SUMMARY.md#L235-L279)

## 依赖关系分析
下图展示核心包与适配器之间的依赖关系及注入流程。

```mermaid
sequenceDiagram
participant App as "应用"
participant Core as "ProCore 安装<br/>packages/core/src/index.js"
participant Inject as "useUIAdapter<br/>packages/core/src/ui-adapter/inject.ts"
participant Adapter as "UI 适配器实例"
App->>Core : "app.use(ProCore, { adapter })"
Core->>Core : "provideUIAdapter(opts.adapter)"
Core->>Adapter : "opts.adapter.install(app)"
App->>Inject : "组件中调用 useUIAdapter()"
Inject-->>Adapter : "返回适配器实例"
```

图表来源
- [packages/core/src/index.js:25-31](file://packages/core/src/index.js#L25-L31)
- [packages/core/src/ui-adapter/inject.ts:23-34](file://packages/core/src/ui-adapter/inject.ts#L23-L34)

章节来源
- [packages/core/src/index.js:25-31](file://packages/core/src/index.js#L25-L31)
- [packages/core/src/ui-adapter/inject.ts:23-34](file://packages/core/src/ui-adapter/inject.ts#L23-L34)

## 性能考虑
- 适配器安装：install(app) 中仅注册必要全局组件，避免重复注册与冗余开销
- 组件获取：useUIAdapter() 通过依赖注入一次性获取，避免在模板中重复计算
- 构建优化：Monorepo 架构支持独立构建与缓存，减少不必要的编译时间

## 故障排除指南
- 适配器未安装：检查 opts.adapter 是否正确传入，确保在安装 UI 库之后安装 ProCore
  - 参考：[packages/core/src/ui-adapter/inject.ts:26-31](file://packages/core/src/ui-adapter/inject.ts#L26-L31)
- 图标组件缺失：element-plus 需要用户注册所需图标组件，否则 CompatibleIcon 会输出警告
  - 参考：[packages/adapters/element-plus/src/index.js:52-57](file://packages/adapters/element-plus/src/index.js#L52-L57)
- Message API 不一致：统一 API，确保 loading/destroy 行为一致
  - 参考：[packages/adapters/element-plus/src/index.js:87-106](file://packages/adapters/element-plus/src/index.js#L87-L106)、[packages/adapters/view-ui-plus/src/index.js:43-51](file://packages/adapters/view-ui-plus/src/index.js#L43-L51)

章节来源
- [packages/core/src/ui-adapter/inject.ts:26-31](file://packages/core/src/ui-adapter/inject.ts#L26-L31)
- [packages/adapters/element-plus/src/index.js:52-57](file://packages/adapters/element-plus/src/index.js#L52-L57)
- [packages/adapters/element-plus/src/index.js:87-106](file://packages/adapters/element-plus/src/index.js#L87-L106)
- [packages/adapters/view-ui-plus/src/index.js:43-51](file://packages/adapters/view-ui-plus/src/index.js#L43-L51)

## 结论
通过统一的 UIAdapter 接口与依赖注入机制，ProIView v2 实现了核心逻辑与 UI 库的完全解耦。开发者只需遵循接口规范、处理 UI 差异并提供统一 API，即可快速创建新的 UI 适配器。配合 Monorepo 架构与清晰的示例，新适配器的开发与维护将更加高效与可靠。

## 附录
- 快速开始与示例：参考 [ARCHITECTURE_SUMMARY.md:235-279](file://ARCHITECTURE_SUMMARY.md#L235-L279)
- 迁移指南与构建命令：参考 [MIGRATION.md:94-139](file://MIGRATION.md#L94-L139)
- 传统入口与兼容包：参考 [packages/index.js:1-69](file://packages/index.js#L1-L69)