# 自定义适配器开发

<cite>
**本文引用的文件**
- [README.md](file://README.md)
- [ARCHITECTURE_SUMMARY.md](file://ARCHITECTURE_SUMMARY.md)
- [MIGRATION.md](file://MIGRATION.md)
- [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)
- [packages/core/src/components/ProSelect.vue](file://packages/core/src/components/ProSelect.vue)
</cite>

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

## 简介
本指南面向希望开发自定义 UI 适配器的开发者，系统讲解如何基于现有架构创建新的 UI 适配器，覆盖接口规范、实现流程、组件映射、属性转换、事件处理、测试与调试、打包发布与版本管理，并提供可复用的模板与最佳实践。

## 项目结构
该仓库采用 Monorepo 架构，核心与适配器分离，便于扩展与维护：
- packages/core：核心业务逻辑与 UI 适配器接口定义
- packages/adapters：各 UI 库适配器实现（view-ui-plus、element-plus）
- packages/compat：向后兼容包
- 根目录文档：架构总结、迁移指南、使用示例

```mermaid
graph TB
subgraph "核心层"
CORE["@pro-iview/core<br/>核心组件与适配器接口"]
end
subgraph "适配器层"
ADAPTER_VIEW["@pro-iview/view-ui-plus<br/>适配器实现"]
ADAPTER_ELEMENT["@pro-iview/element-plus<br/>适配器实现"]
end
subgraph "应用层"
APP["你的 Vue 应用"]
end
APP --> CORE
CORE --> ADAPTER_VIEW
CORE --> ADAPTER_ELEMENT
```

图表来源
- [ARCHITECTURE_SUMMARY.md:59-120](file://ARCHITECTURE_SUMMARY.md#L59-L120)

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

## 核心组件
本节聚焦 UI 适配器接口与注入机制，这是自定义适配器开发的基础。

- UI 适配器接口规范
  - 统一的组件映射：Form、FormItem、Input、Select、Option、Checkbox、Button、Table、TableColumn、Modal、Icon、Page 等
  - 统一的消息反馈 API：info、success、warning、error、loading、destroy
  - install(app) 安装函数用于注册全局组件或配置
- 依赖注入机制
  - provideUIAdapter(adapter) 提供适配器实例
  - useUIAdapter() 注入适配器实例，未安装时抛出明确错误提示

章节来源
- [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)

## 架构总览
下图展示核心组件如何通过注入机制使用适配器，以及两个内置适配器的实现方式。

```mermaid
sequenceDiagram
participant App as "应用"
participant Core as "@pro-iview/core"
participant Adapter as "UI 适配器"
participant Comp as "核心组件"
App->>Core : "app.use(ProCore, { adapter })"
Core->>Adapter : "install(app)"
App->>Comp : "渲染核心组件"
Comp->>Core : "useUIAdapter()"
Core-->>Comp : "返回适配器实例"
Comp->>Adapter : "读取组件/消息 API"
Adapter-->>Comp : "返回 UI 组件与 API"
```

图表来源
- [packages/core/src/ui-adapter/inject.ts:15-34](file://packages/core/src/ui-adapter/inject.ts#L15-L34)
- [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)

章节来源
- [ARCHITECTURE_SUMMARY.md:124-156](file://ARCHITECTURE_SUMMARY.md#L124-L156)
- [MIGRATION.md:20-82](file://MIGRATION.md#L20-L82)

## 详细组件分析

### UI 适配器接口与注入机制
- 接口定义要点
  - 组件映射：按需暴露核心 UI 组件（如 Form、Input、Button、Table、Modal、Icon 等）
  - 消息 API：统一 info/success/warning/error/loading/destroy
  - install(app)：注册全局组件或进行初始化
- 注入机制
  - provideUIAdapter(adapter) 在应用根部提供适配器
  - useUIAdapter() 在组件内注入，若未安装会抛错，便于早期发现配置问题

```mermaid
classDiagram
class UIAdapter {
+Form
+FormItem
+Input
+Select
+Option
+Checkbox
+Button
+Table
+TableColumn
+Modal
+Message
+Icon
+Page
+install(app)
}
class ViewUIPlusAdapter {
+Form
+FormItem
+Input
+Select
+Option
+Checkbox
+Button
+Table
+Modal
+Message
+Icon
+install(app)
}
class ElementPlusAdapter {
+Form
+FormItem
+Input
+Select
+Option
+Checkbox
+Button
+Table
+TableColumn
+Modal
+Message
+Icon
+install(app)
}
UIAdapter <|.. ViewUIPlusAdapter
UIAdapter <|.. ElementPlusAdapter
```

图表来源
- [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)

章节来源
- [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)

### 核心组件对适配器的使用方式
- ProForm
  - 通过 computed 属性从适配器获取 Form、FormItem、Input、Button、Icon
  - 在模板中直接使用适配器提供的组件
- ProSearch
  - 通过 computed 属性获取 Form、Input、Button、Icon
  - 事件绑定与交互逻辑与适配器解耦
- ProSelect
  - 通过 computed 属性获取 Select、Option、Icon
  - 数据加载与渲染逻辑与适配器解耦

```mermaid
sequenceDiagram
participant Comp as "核心组件(如 ProForm)"
participant Adapter as "UI 适配器"
participant UI as "UI 组件库"
Comp->>Adapter : "useUIAdapter()"
Adapter-->>Comp : "返回组件映射(Form/FormItem/Input/Button/Icon)"
Comp->>UI : "渲染适配器提供的组件"
UI-->>Comp : "触发事件/状态变化"
Comp->>Comp : "处理业务逻辑/更新模型"
```

图表来源
- [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)
- [packages/core/src/components/ProSelect.vue:9-18](file://packages/core/src/components/ProSelect.vue#L9-L18)

章节来源
- [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)
- [packages/core/src/components/ProSelect.vue:9-18](file://packages/core/src/components/ProSelect.vue#L9-L18)

### 内置适配器实现对比
- view-ui-plus 适配器
  - 直接导出 UI 库组件并统一封装 Message API
  - 适合已有 view-ui-plus 项目的无缝接入
- element-plus 适配器
  - 提供 CompatibleIcon 兼容层以适配统一的图标使用方式
  - 统一 Message API，处理 loading/destroy 等差异
  - install(app) 中注册 CompatibleIcon

```mermaid
flowchart TD
Start(["开始"]) --> Detect["检测 UI 库类型"]
Detect --> |view-ui-plus| UseView["使用 ViewUIPlusAdapter"]
Detect --> |element-plus| UseElement["使用 ElementPlusAdapter"]
UseElement --> RegisterIcon["注册 CompatibleIcon"]
UseView --> Done(["完成"])
RegisterIcon --> Done
```

图表来源
- [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:29-61](file://packages/adapters/element-plus/src/index.js#L29-L61)
- [packages/adapters/element-plus/src/index.js:88-95](file://packages/adapters/element-plus/src/index.js#L88-L95)

## 依赖关系分析
- 组件对适配器的依赖
  - 核心组件通过 useUIAdapter() 获取组件映射，避免直接依赖具体 UI 库
- 适配器对 UI 库的依赖
  - 适配器仅导出 UI 组件与统一封装的 API，不包含业务逻辑
- 兼容性
  - compat 包自动集成 view-ui-plus 适配器，保持 v1.x API 不变

```mermaid
graph LR
Core["@pro-iview/core"] --> Types["UIAdapter 接口"]
Core --> Inject["provide/use 注入"]
Inject --> AdapterView["@pro-iview/view-ui-plus"]
Inject --> AdapterEle["@pro-iview/element-plus"]
AdapterView --> ViewLib["view-ui-plus"]
AdapterEle --> ElementLib["element-plus"]
```

图表来源
- [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/adapters/view-ui-plus/src/index.js:6-18](file://packages/adapters/view-ui-plus/src/index.js#L6-L18)
- [packages/adapters/element-plus/src/index.js:6-20](file://packages/adapters/element-plus/src/index.js#L6-L20)

章节来源
- [ARCHITECTURE_SUMMARY.md:45-51](file://ARCHITECTURE_SUMMARY.md#L45-L51)

## 性能考虑
- 组件映射缓存
  - 在组件 computed 中缓存 useUIAdapter() 返回的组件引用，避免重复注入开销
- 消息 API 统一
  - 通过适配器统一封装 Message API，减少跨库差异带来的额外判断
- 按需引入
  - 适配器仅导出所需组件，避免不必要的打包体积

## 故障排查指南
- 未安装适配器
  - 现象：运行时报错提示 UI Adapter 未安装
  - 处理：确保在应用根部通过 app.use(ProCore, { adapter }) 正确安装适配器
- 图标组件异常（element-plus）
  - 现象：图标不显示或控制台警告
  - 处理：element-plus 适配器提供 CompatibleIcon 兼容层，需确保图标组件已全局注册；或使用适配器 install(app) 注册
- Message API 行为差异
  - 现象：loading/destroy 行为与预期不符
  - 处理：element-plus 适配器已统一封装，确认传参与返回值一致

章节来源
- [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:29-61](file://packages/adapters/element-plus/src/index.js#L29-L61)
- [packages/adapters/element-plus/src/index.js:88-95](file://packages/adapters/element-plus/src/index.js#L88-L95)

## 结论
通过统一的 UIAdapter 接口与依赖注入机制，核心组件与 UI 库实现彻底解耦。开发者只需遵循接口规范，即可快速创建新的 UI 适配器，实现多 UI 库支持与平滑迁移。

## 附录

### 自定义适配器开发流程
- 需求分析
  - 明确目标 UI 库的组件能力与差异点（如图标、消息、布局等）
- 接口实现
  - 实现 UIAdapter 接口中的组件映射与 Message API
  - 提供 install(app) 完成全局组件注册或初始化
- 组件映射与属性转换
  - 对齐核心组件期望的 props 与事件命名
  - 处理 UI 库特有的属性（如 element-plus 的 TableColumn）
- 事件处理
  - 统一事件命名与参数格式，保证核心组件行为一致
- 测试与调试
  - 编写单元测试覆盖关键组件映射与消息 API
  - 使用示例项目验证渲染与交互
- 打包与发布
  - 使用 pnpm workspace + Turborepo 管理构建与发布
  - 维护 package.json、vite.config.js、类型定义
- 版本管理
  - 遵循语义化版本，保持 UIAdapter 接口稳定，避免破坏性变更

章节来源
- [MIGRATION.md:141-154](file://MIGRATION.md#L141-L154)
- [ARCHITECTURE_SUMMARY.md:175-234](file://ARCHITECTURE_SUMMARY.md#L175-L234)

### 适配器模板与开发框架
- 目录结构
  - packages/adapters/<your-ui>/package.json
  - packages/adapters/<your-ui>/src/index.js
  - packages/adapters/<your-ui>/types/index.d.ts
  - packages/adapters/<your-ui>/vite.config.js
- 实现要点
  - 导出 YourUIAdapter 实例，实现 UIAdapter 接口
  - install(app) 中注册全局组件或进行初始化
  - 统一封装消息 API，处理 loading/destroy 等差异
- 参考实现
  - view-ui-plus 适配器：组件直连、消息 API 直通
  - element-plus 适配器：提供 CompatibleIcon、统一封装消息 API

章节来源
- [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:66-106](file://packages/adapters/element-plus/src/index.js#L66-L106)

### 关键技术点详解
- 组件映射
  - 核心组件通过 useUIAdapter() 获取组件引用，避免硬编码依赖具体 UI 库
- 属性转换
  - 对齐 props 命名与默认值，必要时在适配器层做兼容转换
- 事件处理
  - 统一事件命名与回调签名，保证核心组件逻辑一致
- 样式抽象
  - 核心组件使用抽象类名，适配器负责映射到具体 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)
- [packages/core/src/components/ProSelect.vue:9-18](file://packages/core/src/components/ProSelect.vue#L9-L18)
- [ARCHITECTURE_SUMMARY.md:280-296](file://ARCHITECTURE_SUMMARY.md#L280-L296)

### 测试方法与调试技巧
- 单元测试
  - 测试 useUIAdapter() 注入是否成功
  - 测试组件映射与消息 API 的行为一致性
- 集成测试
  - 在示例项目中验证渲染、交互与事件流
- 调试技巧
  - 通过控制台输出定位组件映射问题
  - 使用浏览器开发者工具检查组件树与事件绑定

章节来源
- [packages/core/src/ui-adapter/inject.ts:26-31](file://packages/core/src/ui-adapter/inject.ts#L26-L31)
- [MIGRATION.md:119-139](file://MIGRATION.md#L119-L139)

### 打包、发布与版本管理
- 构建命令
  - pnpm install、pnpm build、pnpm build:core、pnpm build:adapter:view、pnpm build:adapter:element
- 发布策略
  - 使用 pnpm workspace 管理多包发布，保持版本同步
- 类型定义
  - 为适配器提供完整的 TypeScript 类型定义，提升开发体验

章节来源
- [MIGRATION.md:119-139](file://MIGRATION.md#L119-L139)
- [ARCHITECTURE_SUMMARY.md:175-183](file://ARCHITECTURE_SUMMARY.md#L175-L183)

### 最佳实践建议
- 保持 UIAdapter 接口稳定，避免破坏性变更
- 在 install(app) 中完成必要的全局注册与初始化
- 对 UI 库差异进行集中封装，减少核心组件的分支逻辑
- 提供详尽的类型定义与示例项目，降低接入成本

章节来源
- [ARCHITECTURE_SUMMARY.md:226-229](file://ARCHITECTURE_SUMMARY.md#L226-L229)
- [MIGRATION.md:141-154](file://MIGRATION.md#L141-L154)