# 插槽与作用域插槽

<cite>
**本文引用的文件**
- [packages/components/ProTypeItem/ProTypeItem.vue](file://packages/components/ProTypeItem/ProTypeItem.vue)
- [packages/core/src/components/ProTypeItem/ProTypeItem.vue](file://packages/core/src/components/ProTypeItem/ProTypeItem.vue)
- [packages/components/ProForm.vue](file://packages/components/ProForm.vue)
- [packages/core/src/components/ProForm.vue](file://packages/core/src/components/ProForm.vue)
- [src/views/ProTable.vue](file://src/views/ProTable.vue)
- [src/views/Home.vue](file://src/views/Home.vue)
- [packages/core/src/components/ProTypeItem/comFillArr.js](file://packages/core/src/components/ProTypeItem/comFillArr.js)
- [packages/libs/util.js](file://packages/libs/util.js)
- [packages/core/src/libs/util.js](file://packages/core/src/libs/util.js)
</cite>

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

## 简介
本篇文档聚焦于 ProTypeItem 的插槽系统，特别是 scopedSlots（作用域插槽）的配置与使用。我们将系统讲解：
- scopedSlots 的两种形态：对象与数组
- 数组到对象的转换机制
- 插槽函数的参数模型（modelValue、props、val 等）
- 在表单与表格中的典型用法（自定义渲染、条件显示、图标/文案注入）
- 插槽与组件样式的协同
- 最佳实践与性能建议

## 项目结构
围绕插槽系统的关键文件与职责如下：
- ProTypeItem：负责根据 renderItem 动态渲染组件，并处理 scopedSlots 的数组到对象转换、样式与事件透传
- ProForm：在表单中消费 ProTypeItem，绑定 modelValue 与更新事件
- ProTable 示例：展示在表格列中使用 scopedSlots 的实际场景
- 工具与适配：通用工具函数与 HTML 标签判定、组件填充列表

```mermaid
graph TB
subgraph "表单层"
PF["ProForm.vue"]
end
subgraph "类型项渲染"
PTI["ProTypeItem.vue"]
Fill["comFillArr.js"]
Util["libs/util.js"]
end
subgraph "视图示例"
VPT["src/views/ProTable.vue"]
VH["src/views/Home.vue"]
end
PF --> PTI
PTI --> Fill
PTI --> Util
VPT --> PF
VH --> PF
```

图表来源
- [packages/components/ProForm.vue:80-100](file://packages/components/ProForm.vue#L80-L100)
- [packages/components/ProTypeItem/ProTypeItem.vue:1-132](file://packages/components/ProTypeItem/ProTypeItem.vue#L1-L132)
- [packages/core/src/components/ProTypeItem/comFillArr.js:1-13](file://packages/core/src/components/ProTypeItem/comFillArr.js#L1-L13)
- [packages/libs/util.js:1-110](file://packages/libs/util.js#L1-L110)
- [src/views/ProTable.vue:250-275](file://src/views/ProTable.vue#L250-L275)
- [src/views/Home.vue:395-414](file://src/views/Home.vue#L395-L414)

章节来源
- [packages/components/ProForm.vue:80-100](file://packages/components/ProForm.vue#L80-L100)
- [packages/components/ProTypeItem/ProTypeItem.vue:1-132](file://packages/components/ProTypeItem/ProTypeItem.vue#L1-L132)
- [packages/core/src/components/ProTypeItem/comFillArr.js:1-13](file://packages/core/src/components/ProTypeItem/comFillArr.js#L1-L13)
- [packages/libs/util.js:1-110](file://packages/libs/util.js#L1-L110)
- [src/views/ProTable.vue:250-275](file://src/views/ProTable.vue#L250-L275)
- [src/views/Home.vue:395-414](file://src/views/Home.vue#L395-L414)

## 核心组件
- ProTypeItem
  - 接收 props：item、outData、modelValue、renderItem
  - 渲染逻辑：当 renderItem 为对象时，解析 useExp、text、type、style、props、on、scopedSlots；当为函数时，直接调用并补全 v-model
  - 作用域插槽：若 scopedSlots 为数组，则将其转换为对象形式，键为 name，值为返回 VNode 的函数
  - 事件与格式化：input 方法支持 format 与 formatWapper，触发 update:modelValue 或 wapperInput
- ProForm
  - 将 columns 中的 renderForm 作为 renderItem 传入 ProTypeItem
  - 双向绑定 modelValue 并监听 update:modelValue 与 wapperInput

章节来源
- [packages/components/ProTypeItem/ProTypeItem.vue:7-132](file://packages/components/ProTypeItem/ProTypeItem.vue#L7-L132)
- [packages/components/ProForm.vue:80-100](file://packages/components/ProForm.vue#L80-L100)

## 架构总览
下面以序列图展示“表单 -> ProTypeItem -> 组件实例”的渲染与事件流。

```mermaid
sequenceDiagram
participant Form as "ProForm"
participant TypeItem as "ProTypeItem"
participant Comp as "具体组件(i-input/i-switch等)"
participant Util as "commonToFn/evalUse"
Form->>TypeItem : 传入 props(item, outData, renderItem, modelValue)
TypeItem->>TypeItem : 解析 renderItem(useExp/text/type/style/props/on/scopedSlots)
TypeItem->>TypeItem : 若scopedSlots为数组则转为对象
TypeItem->>Comp : h(type, props, slots, children)
Comp-->>TypeItem : 用户输入触发 onUpdate : modelValue
TypeItem->>Util : input(value) -> format/formatWapper
Util-->>TypeItem : 返回格式化后的值
TypeItem-->>Form : emit update : modelValue 或 wapperInput
```

图表来源
- [packages/components/ProForm.vue:80-100](file://packages/components/ProForm.vue#L80-L100)
- [packages/components/ProTypeItem/ProTypeItem.vue:37-49](file://packages/components/ProTypeItem/ProTypeItem.vue#L37-L49)
- [packages/libs/util.js:56-78](file://packages/libs/util.js#L56-L78)

章节来源
- [packages/components/ProForm.vue:80-100](file://packages/components/ProForm.vue#L80-L100)
- [packages/components/ProTypeItem/ProTypeItem.vue:37-49](file://packages/components/ProTypeItem/ProTypeItem.vue#L37-L49)
- [packages/libs/util.js:56-78](file://packages/libs/util.js#L56-L78)

## 详细组件分析

### ProTypeItem 的作用域插槽（scopedSlots）机制
- 输入形态
  - 对象：{ open: () => VNode, close: () => VNode }
  - 数组：[{ name, title }, ...]
- 转换规则
  - 当 scopedSlots 为数组时，遍历生成对象：键为 name，值为函数，函数内部：
    - 若 title 为函数，则以 h 和参数对象调用，参数包含 modelValue、props、val
    - 否则以文本节点包装返回
- 使用位置
  - 渲染时通过 scopedSlots 透传给具体组件（如 i-switch）

```mermaid
flowchart TD
Start(["进入 render"]) --> CheckType{"scopedSlots 是否为数组?"}
CheckType -- 否 --> UseAsIs["直接使用对象形式"]
CheckType -- 是 --> BuildObj["遍历数组构建对象"]
BuildObj --> ItemLoop{"逐项处理"}
ItemLoop --> IsFunc{"title 是否为函数?"}
IsFunc -- 是 --> CallFunc["调用 title(h, {modelValue, props, val})"]
IsFunc -- 否 --> WrapText["h('span', title)"]
CallFunc --> SetSlot["写入对象[name] = 函数"]
WrapText --> SetSlot
SetSlot --> NextItem{"还有下一项?"}
NextItem -- 是 --> ItemLoop
NextItem -- 否 --> DoneBuild["完成对象构建"]
UseAsIs --> Render["渲染组件并传入 scopedSlots"]
DoneBuild --> Render
Render --> End(["结束"])
```

图表来源
- [packages/components/ProTypeItem/ProTypeItem.vue:58-69](file://packages/components/ProTypeItem/ProTypeItem.vue#L58-L69)

章节来源
- [packages/components/ProTypeItem/ProTypeItem.vue:58-69](file://packages/components/ProTypeItem/ProTypeItem.vue#L58-L69)

### 插槽函数参数模型
- 参数对象包含：
  - modelValue：当前字段的值
  - props：原始 props
  - val：当前插槽项的配置对象（含 name、title 等）
- 调用方式：
  - 若 title 为函数：title(h, { modelValue, props, val })
  - 若 title 为字符串：h("span", title)

章节来源
- [packages/components/ProTypeItem/ProTypeItem.vue:63-66](file://packages/components/ProTypeItem/ProTypeItem.vue#L63-L66)

### 在表格列中的使用示例
- 场景：i-switch 的 open/close 文案替换
- 配置要点：
  - renderForm.type 指定为 i-switch
  - scopedSlots 为数组，包含两个插槽项：open 与 close
  - 每个插槽项的 title 可为字符串或函数（函数接收 h 与参数对象）

```mermaid
sequenceDiagram
participant View as "ProTable.vue"
participant Form as "ProForm"
participant TypeItem as "ProTypeItem"
participant Switch as "i-switch"
View->>Form : 列配置(renderForm)
Form->>TypeItem : 传入 renderItem
TypeItem->>TypeItem : 数组scopedSlots转对象
TypeItem->>Switch : h('i-switch', props, scopedSlots)
Switch-->>TypeItem : 触发更新事件
TypeItem-->>Form : 更新modelValue
```

图表来源
- [src/views/ProTable.vue:250-275](file://src/views/ProTable.vue#L250-L275)
- [packages/components/ProForm.vue:80-100](file://packages/components/ProForm.vue#L80-L100)
- [packages/components/ProTypeItem/ProTypeItem.vue:58-69](file://packages/components/ProTypeItem/ProTypeItem.vue#L58-L69)

章节来源
- [src/views/ProTable.vue:250-275](file://src/views/ProTable.vue#L250-L275)
- [packages/components/ProForm.vue:80-100](file://packages/components/ProForm.vue#L80-L100)
- [packages/components/ProTypeItem/ProTypeItem.vue:58-69](file://packages/components/ProTypeItem/ProTypeItem.vue#L58-L69)

### 在表单中的使用示例
- 场景：自定义渲染内容、条件显示、图标添加
- 自定义渲染内容
  - renderItem 为函数时，可直接返回 VNode，并确保 props.modelValue 与 onUpdate:modelValue 存在
- 条件显示
  - 可在函数内基于 modelValue 或外部上下文决定是否渲染
- 图标/文案注入
  - 通过 scopedSlots 的 open/close 注入自定义文案或图标

章节来源
- [packages/components/ProTypeItem/ProTypeItem.vue:99-124](file://packages/components/ProTypeItem/ProTypeItem.vue#L99-L124)
- [src/views/Home.vue:395-414](file://src/views/Home.vue#L395-L414)

### 插槽与组件样式的结合使用
- 样式透传
  - ProTypeItem 会将 useExp 与 style 结合，动态计算最终样式
  - 支持 useExp=true 时，style 为表达式字符串，通过 evalUse 计算
- 宽度与布局
  - 基于组件名判断是否需要宽度占满类名，影响布局表现

章节来源
- [packages/components/ProTypeItem/ProTypeItem.vue:55-56](file://packages/components/ProTypeItem/ProTypeItem.vue#L55-L56)
- [packages/components/ProTypeItem/ProTypeItem.vue:84-86](file://packages/components/ProTypeItem/ProTypeItem.vue#L84-L86)
- [packages/core/src/components/ProTypeItem/comFillArr.js:1-13](file://packages/core/src/components/ProTypeItem/comFillArr.js#L1-L13)

## 依赖关系分析
- 组件耦合
  - ProForm 依赖 ProTypeItem 进行字段渲染
  - ProTypeItem 依赖工具函数进行表达式求值与组件识别
- 外部依赖
  - lodash-es：用于对象/数组处理
  - Vue：h、resolveComponent、v-model 事件

```mermaid
graph LR
PF["ProForm.vue"] --> PTI["ProTypeItem.vue"]
PTI --> Lodash["lodash-es"]
PTI --> Vue["Vue(h/resolveComponent)"]
PTI --> Util["libs/util.js"]
PTI --> Fill["comFillArr.js"]
```

图表来源
- [packages/components/ProForm.vue](file://packages/components/ProForm.vue#L147)
- [packages/components/ProTypeItem/ProTypeItem.vue:2-5](file://packages/components/ProTypeItem/ProTypeItem.vue#L2-L5)
- [packages/libs/util.js:1-110](file://packages/libs/util.js#L1-L110)
- [packages/core/src/components/ProTypeItem/comFillArr.js:1-13](file://packages/core/src/components/ProTypeItem/comFillArr.js#L1-L13)

章节来源
- [packages/components/ProForm.vue](file://packages/components/ProForm.vue#L147)
- [packages/components/ProTypeItem/ProTypeItem.vue:2-5](file://packages/components/ProTypeItem/ProTypeItem.vue#L2-L5)
- [packages/libs/util.js:1-110](file://packages/libs/util.js#L1-L110)
- [packages/core/src/components/ProTypeItem/comFillArr.js:1-13](file://packages/core/src/components/ProTypeItem/comFillArr.js#L1-L13)

## 性能考量
- 表达式求值
  - useExp 与 style 的动态计算可能带来额外开销，建议仅在必要时启用
- 作用域插槽函数
  - 数组到对象的转换发生在每次渲染，尽量减少插槽数量与复杂度
- 事件与格式化
  - format 与 formatWapper 的执行频率与数据规模相关，避免在高频输入场景中进行重型计算
- 组件识别与宽度
  - 组件名列表用于宽度策略，保持列表简洁有助于减少判断成本

## 故障排查指南
- 作用域插槽未生效
  - 检查 scopedSlots 是否为数组且包含 name 与 title
  - 确认 title 为函数时的参数是否正确传入
- 更新事件未触发
  - 确保 renderItem 为函数时，返回的 VNode 上存在 modelValue 与 onUpdate:modelValue
  - 若使用 format/formatWapper，请确认格式化结果符合预期
- 样式异常
  - useExp 为 true 时，检查 style 的表达式字符串是否合法
  - 确认组件名是否在填充列表中，以决定是否应用宽度类名

章节来源
- [packages/components/ProTypeItem/ProTypeItem.vue:99-124](file://packages/components/ProTypeItem/ProTypeItem.vue#L99-L124)
- [packages/components/ProTypeItem/ProTypeItem.vue:55-56](file://packages/components/ProTypeItem/ProTypeItem.vue#L55-L56)
- [packages/core/src/components/ProTypeItem/comFillArr.js:1-13](file://packages/core/src/components/ProTypeItem/comFillArr.js#L1-L13)

## 结论
ProTypeItem 的插槽系统通过“数组到对象”的转换，统一了作用域插槽的配置方式，使开发者能够灵活地为不同 UI 组件注入自定义内容。配合表单与表格场景，可实现丰富的交互与展示需求。在实践中应关注表达式求值、事件透传与样式策略的性能影响，并遵循最佳实践以获得稳定高效的体验。

## 附录
- 关键路径参考
  - [ProTypeItem 渲染与插槽转换:51-98](file://packages/components/ProTypeItem/ProTypeItem.vue#L51-L98)
  - [ProForm 传参与事件绑定:80-100](file://packages/components/ProForm.vue#L80-L100)
  - [表格列 scopedSlots 示例:250-275](file://src/views/ProTable.vue#L250-L275)
  - [Home 页面注释示例（作用域插槽）:395-414](file://src/views/Home.vue#L395-L414)
  - [组件填充列表（宽度策略）:1-13](file://packages/core/src/components/ProTypeItem/comFillArr.js#L1-L13)
  - [通用工具函数（表达式与组件识别）:56-94](file://packages/libs/util.js#L56-L94)