# ProSelect 选择器组件

<cite>
**本文引用的文件**
- [ProSelect.vue（核心实现）](file://packages/components/ProSelect.vue)
- [ProSelect.vue（演示用例）](file://src/views/ProSelect.vue)
- [ProForm.vue（表单集成示例）](file://src/views/ProForm.vue)
- [request.js（网络请求封装）](file://packages/libs/request.js)
- [util.js（模板工具）](file://packages/libs/util.js)
- [index.js（组件导出）](file://packages/index.js)
- [inject.ts（UI 适配器注入）](file://packages/core/src/ui-adapter/inject.ts)
- [index.ts（UI 适配器入口）](file://packages/core/src/ui-adapter/index.ts)
- [router/index.js（路由配置）](file://src/router/index.js)
</cite>

## 更新摘要
**变更内容**
- **已更新** mergedMap 计算属性重构：从 methods 部分移动到 computed 部分，改善数据映射功能和修复运行时错误
- $PRO_IVIEW 全局配置对象的引入，支持全局数据映射配置
- 组件级 map 配置与全局 map 配置的优先级规则

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

## 简介
本文件系统性地文档化 ProSelect 选择器组件，覆盖其配置语法、数据源处理、单选/多选与远程搜索能力、选项渲染与自定义模板、事件与数据绑定机制，并提供复杂场景示例与性能优化建议。该组件通过 UI 适配器模式对接不同 UI 框架的选择器控件，支持本地列表与远程请求两种数据源，具备灵活的标题模板与值映射能力。**最新版本**通过重构 mergedMap 计算属性，从 methods 移动到 computed 部分，显著改善了数据映射功能和运行时稳定性。

## 项目结构
ProSelect 组件位于 packages/components 下，同时在 packages/core/src/components 中提供核心实现版本；实际生产使用推荐采用核心实现。组件通过 UI 适配器注入机制对接具体 UI 框架的选择器与选项组件，并通过 request.js 封装网络请求，util.js 提供模板解析能力。全局配置通过 $PRO_IVIEW 对象提供，支持全局数据映射配置。

```mermaid
graph TB
A["ProSelect 核心组件<br/>packages/components/ProSelect.vue"] --> B["UI 适配器注入<br/>packages/core/src/ui-adapter/inject.ts"]
A --> C["网络请求封装<br/>packages/libs/request.js"]
A --> D["模板工具<br/>packages/libs/util.js"]
E["演示页面<br/>src/views/ProSelect.vue"] --> A
F["表单集成示例<br/>src/views/ProForm.vue"] --> A
G["组件导出入口<br/>packages/index.js"] --> A
H["$PRO_IVIEW 全局配置<br/>packages/index.js"] --> A
```

**图表来源**
- [ProSelect.vue（核心实现）:1-169](file://packages/components/ProSelect.vue#L1-L169)
- [ProSelect.vue（演示用例）:1-115](file://src/views/ProSelect.vue#L1-L115)
- [ProForm.vue（表单集成示例）:1-198](file://src/views/ProForm.vue#L1-L198)
- [index.js（组件导出）:1-70](file://packages/index.js#L1-L70)

**章节来源**
- [ProSelect.vue（核心实现）:1-169](file://packages/components/ProSelect.vue#L1-L169)
- [ProSelect.vue（演示用例）:1-115](file://src/views/ProSelect.vue#L1-L115)
- [ProForm.vue（表单集成示例）:1-198](file://src/views/ProForm.vue#L1-L198)
- [index.js（组件导出）:1-70](file://packages/index.js#L1-L70)

## 核心组件
- 组件名称：ProSelect
- 功能定位：基于 UI 适配器的选择器组件，支持本地列表与远程请求、标题模板、首项自动选择、多选/单选切换等
- 关键特性：
  - 数据源：list（本地数组）或 request（远程接口）
  - 映射：**已更新**支持组件级 map 与全局 $PRO_IVIEW.map 的智能合并，通过重构的 mergedMap 计算属性实现
  - 行为：first（自动选中首个）、valueType（值类型）
  - 渲染：支持图标与模板表达式
  - 事件：update:modelValue、change

**章节来源**
- [ProSelect.vue（核心实现）:1-169](file://packages/components/ProSelect.vue#L1-L169)

## 架构总览
ProSelect 通过 UI 适配器注入 Select 与 Option 组件，内部维护 innerList 与 innerValue，对外暴露 v-model 双向绑定。**已更新**通过重构的 mergedMap 计算属性实现组件级配置与全局配置的智能合并，提供更好的性能和响应式支持。当存在 list 时直接使用；否则根据 request 发起请求，使用 dataPath 提取选项。标题文本支持普通字段或 ES6 模板表达式，通过 template 工具解析。

```mermaid
sequenceDiagram
participant U as "用户"
participant PS as "ProSelect"
participant GM as "全局映射($PRO_IVIEW)"
participant RA as "UI 适配器"
participant REQ as "网络请求封装"
participant SV as "服务端"
U->>PS : 设置 v-model 与配置
PS->>PS : init()/fetchList()
PS->>GM : 合并组件级与全局映射配置
alt 存在 list
PS->>PS : innerList = list
else 存在 request
PS->>REQ : customRequest({request, method})
REQ-->>PS : 响应数据
PS->>PS : 解析 dataPath 并设置 innerList
end
PS->>RA : 渲染 Select/Option
U->>PS : 选择/输入
PS-->>U : 触发 update : modelValue 与 change
```

**图表来源**
- [ProSelect.vue（核心实现）:45-80](file://packages/components/ProSelect.vue#L45-L80)
- [request.js（网络请求封装）:39-77](file://packages/libs/request.js#L39-L77)
- [inject.ts（UI 适配器注入）:23-34](file://packages/core/src/ui-adapter/inject.ts#L23-L34)

## 详细组件分析

### 配置语法与数据源处理
- 属性概览
  - request：远程请求配置，可为字符串 URL、对象或函数
  - method：HTTP 方法，默认 GET
  - **已更新**map：数据映射对象，支持组件级配置
    - dataPath：响应数据提取路径（支持点号路径）
    - titlePath：选项标题字段或 ES6 模板表达式
    - valuePath：选项值字段
  - **已更新**$PRO_IVIEW.map：全局映射配置，支持全局默认配置
  - first：是否自动选中首个元素
  - list：本地选项数组
  - modelValue：双向绑定值
  - valueType：值类型提示（如 "string"）

- **已更新**配置合并策略
  - mergedMap 计算属性实现智能合并：组件级 map 优先于全局 $PRO_IVIEW.map
  - 合并顺序：组件级 map -> 全局 $PRO_IVIEW.map -> 默认值
  - 默认值：dataPath="data"、titlePath="title"、valuePath="value"
  - **性能改进**：计算属性自动缓存结果，只有在依赖变化时重新计算

- 数据源优先级
  - 若传入 list，则直接使用本地数组作为选项数据
  - 否则若传入 request，则通过 customRequest 发起请求，使用 dataPath 提取数据
  - 若未设置 list 且未设置 request，则 innerList 为空

- 标题模板
  - 当 titlePath 包含 "${...}" 时，使用 template 工具进行变量替换
  - 否则直接读取指定字段

- 首项自动选择
  - 当 first 为真且 modelValue 为空时，自动选择第一个选项并触发 update:modelValue 与 change 事件

**章节来源**
- [ProSelect.vue（核心实现）:24-43](file://packages/components/ProSelect.vue#L24-L43)
- [ProSelect.vue（核心实现）:85-101](file://packages/components/ProSelect.vue#L85-L101)
- [util.js（模板工具）:4-19](file://packages/libs/util.js#L4-L19)

### 单选、多选与远程搜索
- 单选/多选
  - 通过 $attrs 透传给底层 Select 组件，从而支持 multiple 属性
  - 内部 computed innerValue 负责将 modelValue 转换为数组（多选）或标量（单选），并在 setter 中回写 update:modelValue

- 远程搜索
  - 组件本身未内置搜索过滤逻辑，但底层 Select 支持 filterable 与 transfer 等属性
  - 如需前端搜索，可在外部使用 filterable 并自行处理；如需后端搜索，建议在 request 中携带查询参数并通过 map.dataPath 提取结果

- 值类型处理
  - 通过 valueType 或 modelValue 类型推断 isStringType，影响内部值转换策略

**章节来源**
- [ProSelect.vue（核心实现）:102-117](file://packages/components/ProSelect.vue#L102-L117)
- [ProSelect.vue（核心实现）:118-131](file://packages/components/ProSelect.vue#L118-L131)

### 选项渲染、自定义模板与样式
- 选项渲染
  - 使用 UI 适配器注入的 Option 渲染每个 item
  - 支持在 item 中提供 icon 字段，自动渲染图标
  - 标题通过 getExpText 计算，支持普通字段与模板表达式

- 自定义模板
  - titlePath 支持 ES6 模板表达式，如 "${fieldA} - ${fieldB}"
  - 模板变量必须是合法标识符，非法标识符会抛出异常

- 样式定制
  - 组件提供 pro_select 与 option 样式作用域，可按需扩展
  - 可通过外部样式覆盖或在父级容器中增加样式类名

**章节来源**
- [ProSelect.vue（核心实现）:134-169](file://packages/components/ProSelect.vue#L134-L169)
- [ProSelect.vue（核心实现）:51-57](file://packages/components/ProSelect.vue#L51-L57)
- [util.js（模板工具）:4-19](file://packages/libs/util.js#L4-L19)

### 事件处理与数据绑定
- 事件
  - update:modelValue：值变更时触发
  - change：选中项变更时触发（仅在 first 自动选择时触发一次）

- 数据绑定
  - v-model 双向绑定 modelValue
  - 内部通过 innerValue 计算属性实现 getter/setter，兼容多选与单选场景

- 监听与更新
  - 监听 request 的深变化，当 URL 或配置变化时重新初始化
  - 监听 list 变化，实时更新 innerList

**章节来源**
- [ProSelect.vue（核心实现）:97-99](file://packages/components/ProSelect.vue#L97-L99)
- [ProSelect.vue（核心实现）:102-117](file://packages/components/ProSelect.vue#L102-L117)
- [ProSelect.vue（核心实现）:118-131](file://packages/components/ProSelect.vue#L118-L131)

### 复杂场景示例
- 在演示页面中，展示了两种配置：
  - 本地 list：直接传入数组，titlePath 指向自定义字段，支持 icon 图标
  - 远程 request：通过 map 指定 titlePath/valuePath，从接口响应中提取数据
- 在表单中，通过 renderForm 或 renderForm: { type, props } 的方式动态渲染 ProSelect，并传递 request 与 map
- **已更新**全局配置使用：通过全局 $PRO_IVIEW.map 设置默认的数据映射配置，组件内可省略重复的 map 配置

**章节来源**
- [ProSelect.vue（演示用例）:45-102](file://src/views/ProSelect.vue#L45-L102)
- [ProForm.vue（表单集成示例）:36-55](file://src/views/ProForm.vue#L36-L55)
- [ProForm.vue（表单集成示例）:147-190](file://src/views/ProForm.vue#L147-L190)

## 依赖关系分析
- 组件依赖
  - lodash-es：数据处理与路径访问
  - UI 适配器：注入 Select/Option/Icon
  - request.js：统一网络请求封装
  - util.js：模板解析

- 组件耦合
  - 与 UI 适配器解耦，便于切换不同 UI 框架
  - 与网络层解耦，支持字符串 URL、对象配置与函数回调三种 request 形态
  - **已更新**与全局配置解耦，支持组件级与全局配置的灵活组合

```mermaid
classDiagram
class ProSelect {
+props request
+props method
+props map
+props first
+props list
+props modelValue
+props valueType
+data innerList
+data isStringType
+computed mergedMap
+methods init()
+methods getExpText(item)
+methods fetchList()
+computed innerValue
+watch request
+watch list
}
class GlobalConfig {
+$PRO_IVIEW.map
+methods mergeConfig()
}
class Request {
+customRequest(config)
}
class Util {
+template(str, item)
}
ProSelect --> Request : "调用"
ProSelect --> Util : "使用"
ProSelect --> GlobalConfig : "合并配置"
```

**图表来源**
- [ProSelect.vue（核心实现）:1-169](file://packages/components/ProSelect.vue#L1-L169)
- [request.js（网络请求封装）:39-77](file://packages/libs/request.js#L39-L77)
- [util.js（模板工具）:4-19](file://packages/libs/util.js#L4-L19)

**章节来源**
- [ProSelect.vue（核心实现）:1-169](file://packages/components/ProSelect.vue#L1-L169)
- [request.js（网络请求封装）:1-78](file://packages/libs/request.js#L1-L78)
- [util.js（模板工具）:1-110](file://packages/libs/util.js#L1-L110)

## 性能考量
- 列表渲染
  - 使用 v-for 渲染 Option，建议控制列表规模或启用虚拟滚动（由底层 Select 控制）
- 请求与缓存
  - remote 模式下建议在上层缓存请求结果，避免重复请求
  - request 变化时会重新 fetch，注意避免频繁变更导致的抖动
- **已更新**配置合并性能
  - mergedMap 计算属性会在依赖变化时重新计算，利用计算属性的缓存机制提升性能
  - 建议合理使用全局配置减少重复配置
  - 全局配置变更时会触发所有使用 $PRO_IVIEW.map 的组件重新计算
- 模板解析
  - 模板表达式仅在 titlePath 包含 "${...}" 时生效，避免不必要的模板计算
- 值类型推断
  - isStringType 仅影响初始值处理，对性能影响较小

## 故障排查指南
- 无法渲染选项
  - 检查 list 或 request 是否正确设置
  - 确认 map.dataPath 或 $PRO_IVIEW.map.dataPath 正确指向响应中的数组字段
  - **已更新**检查组件级 map 与全局 map 的合并是否符合预期

- 标题不显示或显示异常
  - 若使用模板表达式，确保 titlePath 中变量名合法
  - 检查 map.titlePath、$PRO_IVIEW.map.titlePath 与 map.valuePath 是否匹配数据结构

- 自动选中无效
  - first 为真时仅在 modelValue 为空时生效
  - 确认 map.valuePath 或 $PRO_IVIEW.map.valuePath 指向的字段存在且非空

- 事件未触发
  - 确认使用 v-model 绑定，组件通过 update:modelValue 回写
  - change 事件仅在 first 自动选择时触发一次

- **已更新**全局配置问题
  - 确认 $PRO_IVIEW.map 是否正确初始化
  - 检查组件级 map 与全局 map 的优先级是否符合预期
  - 验证全局配置的 dataPath、titlePath、valuePath 是否正确
  - **性能问题**：如果发现性能问题，检查是否正确使用了计算属性的缓存机制

**章节来源**
- [ProSelect.vue（核心实现）:58-80](file://packages/components/ProSelect.vue#L58-L80)
- [util.js（模板工具）:4-19](file://packages/libs/util.js#L4-L19)

## 结论
ProSelect 通过清晰的配置语法与灵活的数据源处理，满足本地与远程场景下的选择器需求。**最新版本**通过重构 mergedMap 计算属性，从 methods 移动到 computed 部分，显著改善了数据映射功能和运行时稳定性，同时保持了向后兼容性。新的实现提供了更好的性能和响应式支持，通过智能合并机制实现了组件级配置与全局配置的灵活组合。借助 UI 适配器与模板工具，组件具备良好的可扩展性与可定制性。在复杂业务场景中，建议结合表单与路由示例进行集成，并根据性能要求进行合理的缓存与渲染优化。

## 附录
- 组件导出入口：packages/index.js
- UI 适配器注入：packages/core/src/ui-adapter/inject.ts
- 路由配置：src/router/index.js（包含 ProSelect 页面）

**章节来源**
- [index.js（组件导出）:1-70](file://packages/index.js#L1-L70)
- [inject.ts（UI 适配器注入）:1-43](file://packages/core/src/ui-adapter/inject.ts#L1-L43)
- [router/index.js（路由配置）:1-65](file://src/router/index.js#L1-L65)