---
title: 开发文档
order: 3
category: atom
---

# PisellSuperTabs 开发文档

## 1. 组件信息

- **组件名称**：PisellSuperTabs
- **组件版本号**：1.0.0
- **组件分类**：Pro Components (导航类)
- **组件编号**：pcp_na_super_tabs_V1.0

## 2. 组件描述

PisellSuperTabs 是一个通用导航框架封装的全能型 Tab 组件，用于构建多种导航模式（如菜单、标签页、导航栏等）。组件采用组合设计模式，通过封装 PisellScrollView、PisellBasicGrid 和 PisellCards 三个基础组件，提供了强大的布局、滚动和渲染能力。

### 设计理念

组件采用**职责分离**的设计原则：

```
PisellScrollView (滚动容器)
  └─ PisellBasicGrid (布局引擎)
       └─ renderItem (渲染函数)
            └─ PisellCards.XXX (业务 Card)
```

- **PisellScrollView**：负责滚动能力（横向/竖向滚动、滚动按钮、吸附滚动等）
- **PisellBasicGrid**：负责布局能力（排列方向、换行、间距、对齐等）
- **renderItem**：负责自定义渲染逻辑（由开发者提供）
- **PisellCards.XXX**：负责具体的 TabItem UI 实现（由开发者选择）

### 核心特性

1. **受控组件**：通过 value/onChange 控制激活状态
2. **数据驱动**：支持 dataSource 数据源，支持多级嵌套（children 字段）
3. **完全可定制**：通过 renderItem 自定义任意 TabItem 渲染
4. **极致配置化**：透传 PisellBasicGrid 和 PisellScrollView 的所有配置能力
5. **通用灵活**：适配多种导航场景（顶部导航、侧边导航、底部导航、锚点导航等）

## 3. 组件需求点罗列

### 3.1 基础功能

- [x] 支持受控模式（value / onChange）
- [x] 支持数据源驱动（dataSource）
- [x] 支持自定义渲染（renderItem）
- [x] 支持自定义 key 字段（rowKey）
- [x] 支持多级嵌套数据结构（children 字段）

### 3.2 布局能力（透传 PisellBasicGrid）

- [x] 支持排列方向（horizontal / vertical / horizontal-reverse / vertical-reverse）
- [x] 支持换行控制（nowrap / wrap / wrap-reverse）
- [x] 支持一行 N 个（columns）
- [x] 支持等分布局（equalWidth）
- [x] 支持间距设置（gap / rowGap / columnGap）
- [x] 支持对齐方式（justify / align / alignContent）

### 3.3 滚动能力（透传 PisellScrollView）

- [x] 支持滚动方向控制（overflow: auto / scroll / x / y / both）
- [x] 支持滚动条样式（scrollbarStyle: default / thin / minimal / rounded / overlay / none）
- [x] 支持滚动按钮（scrollActionsConfig）
- [x] 支持吸附滚动（snapScroll）
- [x] 支持滚动事件（onScroll / onScrollStart / onScrollEnd）
- [x] 支持边界检测（onReachTop / onReachBottom / onReachLeft / onReachRight）
- [x] 支持尺寸控制（width / height / maxWidth / maxHeight）

### 3.4 状态管理

- [x] 自动计算并传递激活状态到 renderItem
- [x] 支持点击切换激活状态
- [x] 支持外部控制激活状态

### 3.5 扩展能力

- [x] 支持展开/收起控制项透传（具体实现由 Card 组件负责）
- [x] 支持自定义容器样式（className / style）
- [x] 支持自定义 Grid 样式（gridClassName / gridStyle）
- [x] 支持自定义 ScrollView 样式（scrollViewClassName / scrollViewStyle）

## 4. 组件 API 设计

### 4.1 PisellSuperTabsProps

```
interface PisellSuperTabsProps<T = any> {
  /* ==================== 基础属性 ==================== */

  /**
   * 自定义类名
   */
  className?: string;

  /**
   * 自定义样式
   */
  style?: CSSProperties;

  /* ==================== 数据源 ==================== */

  /**
   * 数据源
   * @description 支持多级嵌套，递归字段为 children
   */
  dataSource?: T[];

  /**
   * 数据项的唯一标识字段
   * @default 'key'
   */
  rowKey?: string | ((record: T, index: number) => string);

  /* ==================== 受控模式 ==================== */

  /**
   * 当前激活的 Tab key
   */
  value?: string;

  /**
   * Tab 切换时的回调
   */
  onChange?: (key: string, item: T) => void;

  /* ==================== 自定义渲染 ==================== */

  /**
   * 自定义 TabItem 渲染函数
   * @param item - 当前数据项
   * @param index - 当前索引
   * @param active - 是否激活
   * @returns ReactNode
   */
  renderItem?: (item: T, index: number, active: boolean) => ReactNode;

  /* ==================== PisellBasicGrid Props ==================== */

  /**
   * PisellBasicGrid 组件的配置
   * @description 透传给 PisellBasicGrid 组件的所有 Props
   * @see PisellBasicGridProps
   */
  gridProps?: Omit<PisellBasicGridProps<T>, 'dataSource' | 'renderItem' | 'rowKey'>;

  /* ==================== PisellScrollView Props ==================== */

  /**
   * PisellScrollView 组件的配置
   * @description 透传给 PisellScrollView 组件的所有 Props
   * @see PisellScrollViewProps
   */
  scrollViewProps?: Omit<PisellScrollViewProps, 'children'>;
}
```

### 4.2 gridProps 配置说明

`gridProps` 接收 PisellBasicGrid 组件的所有 Props（除了 dataSource、renderItem、rowKey）：

```
gridProps?: {
  // 布局属性
  direction?: 'horizontal' | 'horizontal-reverse' | 'vertical' | 'vertical-reverse';
  wrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
  columns?: number;
  equalWidth?: boolean;

  // 间距属性
  gap?: number | string;
  rowGap?: number | string;
  columnGap?: number | string;

  // 对齐属性
  justify?: 'start' | 'end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
  align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch';
  alignContent?: 'start' | 'end' | 'center' | 'space-between' | 'space-around' | 'stretch';

  // 样式
  className?: string;
  style?: CSSProperties;
}
```

**详细文档**：请参考 `PisellBasicGrid` 组件文档

### 4.3 scrollViewProps 配置说明

`scrollViewProps` 接收 PisellScrollView 组件的所有 Props（除了 children）：

```
scrollViewProps?: {
  // 滚动方向
  overflow?: 'auto' | 'scroll' | 'hidden' | 'x' | 'y' | 'both';

  // 滚动条样式
  scrollbarStyle?: 'default' | 'thin' | 'minimal' | 'rounded' | 'overlay' | 'custom' | 'none';
  scrollbarClassName?: string;

  // 滚动按钮
  scrollActionsConfig?: {
    show?: boolean;
    type?: 'rArrows' | 'lrArrows' | 'tbArrows';
    scrollDistance?: number;
  };

  // 吸附滚动
  snapScroll?: {
    enabled?: boolean;
    type?: 'mandatory' | 'proximity';
    align?: 'start' | 'center' | 'end';
  };

  // 滚动事件
  onScroll?: (data: any) => void;
  onScrollStart?: (data: any) => void;
  onScrollEnd?: (data: any) => void;
  onReachTop?: (data: any) => void;
  onReachBottom?: (data: any) => void;
  onReachLeft?: (data: any) => void;
  onReachRight?: (data: any) => void;
  reachThreshold?: number;
  scrollEndDelay?: number;

  // 尺寸控制
  width?: number | string;
  height?: number | string;
  maxWidth?: number | string;
  maxHeight?: number | string;
  minWidth?: number | string;
  minHeight?: number | string;

  // 样式
  className?: string;
  style?: CSSProperties;
}
```

**详细文档**：请参考 `PisellScrollView` 组件文档

### 4.4 数据源结构示例

```
// 基础数据项
interface TabDataItem {
  key: string;           // 唯一标识（必填）
  label?: string;        // 标签文本
  icon?: ReactNode;      // 图标
  children?: TabDataItem[]; // 子级数据（多级嵌套）
  [key: string]: any;    // 其他自定义字段
}

// 使用示例
const dataSource = [
  {
    key: 'home',
    label: '首页',
    icon: <HomeOutlined />
  },
  {
    key: 'products',
    label: '产品',
    children: [
      { key: 'product-1', label: '产品1' },
      { key: 'product-2', label: '产品2' }
    ]
  }
];
```

## 5. 组件模块拆解

### 5.1 目录结构

```
PisellSuperTabs/
├── index.tsx                      # 组件导出
├── PisellSuperTabs.tsx            # 组件主实现
├── PisellSuperTabs.less           # 组件样式
├── PisellSuperTabs.test.tsx       # 单元测试
├── types.ts                       # TS 类型定义
├── hooks/                         # 自定义 Hooks
│   ├── index.ts
│   └── useTabsState.ts            # Tab 状态管理
├── utils/                         # 工具函数
│   ├── index.ts
│   └── getRowKey.ts               # 获取 rowKey
└── docs/                          # 文档
    ├── PisellSuperTabs.md
    ├── PisellSuperTabs.$tab-design.md
    ├── PisellSuperTabs.$tab-dev.md
    └── PisellSuperTabs.$tab-test.md
```

### 5.2 核心模块

#### 5.2.1 主组件（PisellSuperTabs.tsx）

**职责**：

- 接收所有 Props（已按组件分组）
- 调用 Hooks 处理状态管理
- 组合 PisellScrollView 和 PisellBasicGrid
- 渲染 TabItem

**主要逻辑**：

1. 解构 Props（基础 Props、gridProps、scrollViewProps）
2. 使用 `useTabsState` 管理激活状态
3. 渲染组合结构：ScrollView > Grid > Items

#### 5.2.2 状态管理 Hook（useTabsState.ts）

**职责**：

- 管理当前激活的 Tab key
- 提供切换 Tab 的方法
- 支持受控和非受控模式

**输入**：

- value（受控值）
- onChange（切换回调）
- defaultValue（默认值）

**输出**：

- activeKey（当前激活的 key）
- handleTabChange（切换方法）

#### 5.2.3 Props 处理（组件内部）

**职责**：

- 提取基础 Props
- 提取并透传 gridProps
- 提取并透传 scrollViewProps

**说明**：
由于 Props 已经按照组件分组，不再需要单独的 Hook 进行分类处理，直接在组件内部解构即可。

#### 5.2.4 工具函数（getRowKey.ts）

**职责**：

- 根据 rowKey 配置获取数据项的唯一标识

**输入**：

- record（数据项）
- index（索引）
- rowKey（key 字段配置）

**输出**：

- string（唯一标识）

## 6. 组件实现方案

### 6.1 核心实现流程

```
1. 接收 Props（已按组件分组）
   ↓
2. 解构基础 Props、gridProps、scrollViewProps
   ↓
3. 使用 useTabsState 管理激活状态
   ↓
4. 渲染 PisellScrollView（传入 scrollViewProps）
   ↓
5. 渲染 PisellBasicGrid（传入 gridProps + dataSource + renderItem）
   ↓
6. 在 renderItem 中：
   - 判断当前项是否激活
   - 调用用户自定义的 renderItem
   - 包裹点击事件处理
   ↓
7. 完成渲染
```

### 6.2 关键实现点

#### 6.2.1 受控/非受控模式

```
const useTabsState = (props) => {
  const { value, onChange, defaultValue } = props;
  const [innerValue, setInnerValue] = useState(defaultValue);

  // 受控模式：使用外部 value
  // 非受控模式：使用内部 innerValue
  const activeKey = value !== undefined ? value : innerValue;

  const handleTabChange = (key, item) => {
    if (value === undefined) {
      setInnerValue(key); // 非受控模式：更新内部状态
    }
    onChange?.(key, item); // 触发回调
  };

  return { activeKey, handleTabChange };
};
```

#### 6.2.2 Props 解构

```
const PisellSuperTabs = <T,>(props: PisellSuperTabsProps<T>) => {
  const {
    // 基础属性
    className,
    style,
    dataSource,
    rowKey = 'key',
    value,
    onChange,
    renderItem,
    // Grid Props（已分组）
    gridProps = {},
    // ScrollView Props（已分组）
    scrollViewProps = {},
  } = props;

  // 使用状态管理 Hook
  const { activeKey, handleTabChange } = useTabsState({
    value,
    onChange,
  });

  // ... 后续实现
};
```

#### 6.2.3 渲染逻辑

```
const PisellSuperTabs = <T,>(props: PisellSuperTabsProps<T>) => {
  const {
    className,
    style,
    dataSource,
    rowKey = 'key',
    value,
    onChange,
    renderItem,
    gridProps = {},
    scrollViewProps = {},
  } = props;

  // 状态管理
  const { activeKey, handleTabChange } = useTabsState({
    value,
    onChange,
  });

  // 自定义 renderItem
  const customRenderItem = (item: T, index: number) => {
    const key = getRowKey(item, index, rowKey);
    const active = key === activeKey;

    // 调用用户自定义渲染函数
    const content = renderItem?.(item, index, active);

    // 包裹点击事件
    return (
      <div
        key={key}
        onClick={() => handleTabChange(key, item)}
        className="pisell-super-tabs-item"
      >
        {content}
      </div>
    );
  };

  return (
    <div className={classNames('pisell-super-tabs', className)} style={style}>
      <PisellScrollView {...scrollViewProps}>
        <PisellBasicGrid
          {...gridProps}
          dataSource={dataSource}
          rowKey={rowKey}
          renderItem={customRenderItem}
        />
      </PisellScrollView>
    </div>
  );
};
```

### 6.3 样式设计

```
// PisellSuperTabs.less

.pisell-super-tabs {
  // 基础容器样式
  width: 100%;
  height: 100%;

  &-item {
    // TabItem 基础样式
    cursor: pointer;
    user-select: none;
  }
}
```

## 7. 通用性与可扩展性

### 7.1 通用性设计

1. **完全数据驱动**：通过 dataSource 控制所有内容
2. **完全自定义渲染**：renderItem 可以渲染任意内容
3. **完全配置化**：透传所有布局和滚动配置
4. **不限定 UI**：不内置任何 TabItem 样式，完全由开发者控制

### 7.2 可扩展性设计

1. **支持任意 Card 组件**：可使用 PisellCards.TabCard、PisellCards.MenuCard 或自定义组件
2. **支持多级嵌套**：dataSource 支持 children 递归结构（渲染由 Card 处理）
3. **支持所有布局模式**：横向、竖向、网格、等分等
4. **支持所有滚动模式**：横向滚动、竖向滚动、吸附滚动等
5. **易于扩展新功能**：通过 Props 透传和自定义渲染，无需修改组件代码

### 7.3 使用场景示例

#### 场景 1：顶部横向导航

```
<PisellSuperTabs
  dataSource={tabs}
  gridProps={{
    direction: 'horizontal',
    gap: 16,
  }}
  scrollViewProps={{
    overflow: 'x',
    scrollActionsConfig: { show: true, type: 'lrArrows' },
  }}
  renderItem={(item, index, active) => (
    <PisellCards.TabCard
      {...item}
      active={{ value: active }}
    />
  )}
/>
```

#### 场景 2：侧边竖向菜单

```
<PisellSuperTabs
  dataSource={menus}
  gridProps={{
    direction: 'vertical',
    gap: 8,
  }}
  scrollViewProps={{
    height: '100vh',
    overflow: 'y',
  }}
  renderItem={(item, index, active) => (
    <PisellCards.MenuCard
      {...item}
      active={{ value: active }}
    />
  )}
/>
```

#### 场景 3：底部图标导航

```
<PisellSuperTabs
  dataSource={bottomTabs}
  gridProps={{
    direction: 'horizontal',
    equalWidth: true,
  }}
  renderItem={(item, index, active) => (
    <PisellCards.TabCard
      {...item}
      active={{ value: active }}
      direction="vertical"
      size="large"
    />
  )}
/>
```

## 8. 注意事项

1. **多级嵌套**：SuperTabs 只负责渲染第一级数据，children 的渲染由 Card 组件自己实现
2. **Props 分组**：gridProps 和 scrollViewProps 都是对象形式，分别透传给对应的底层组件
3. **Props 优先级**：
   - style 作用于外层容器
   - gridProps.style 作用于 Grid 组件
   - scrollViewProps.style 作用于 ScrollView 组件
4. **受控模式**：当传入 value 时，组件为受控模式，必须配合 onChange 使用
5. **rowKey 必填**：dataSource 中的每一项必须有唯一的 key 字段（默认为 'key'）
6. **性能优化**：大数据量时建议使用虚拟滚动（后续扩展）

## 9. 后续优化方向

1. 支持虚拟滚动（大数据量场景）
2. 支持拖拽排序
3. 支持动态增删改查
4. 支持权限控制
5. 支持键盘导航
6. 支持无障碍访问（ARIA）
