---
title: 开发文档
order: 3
category: sub-component
---

# ToolBar 开发文档

## 技术栈

- **React**: ^18.0.0
- **TypeScript**: ^5.0.0
- **Less**: ^4.0.0
- **classnames**: ^2.3.0

## 项目结构

```
ToolBar/
├── index.tsx              # 组件主入口和实现
├── index.less            # 组件样式文件
├── type.ts               # TypeScript 类型定义
└── docs/                 # 文档目录
    ├── ToolBar.md                      # 组件使用文档
    ├── ToolBar.$tab-design.md          # 设计文档
    ├── ToolBar.$tab-dev.md             # 开发文档
    └── ToolBar.$tab-test.md            # 测试文档
```

## 核心实现

### 组件结构

```
const Toolbar: React.FC<ToolBarProps> = (props) => {
  const { className, style, tabs, topLeft, topRight, bottomLeft, bottomRight } =
    props;

  const toolbarClassName = classNames('pisell-grid-pro-toolbar', className);

  return (
    <div className={toolbarClassName} style={style}>
      {tabs && <div className="pisell-grid-pro-toolbar-row">{tabs}</div>}
      {(topLeft || topRight) && (
        <div className="pisell-grid-pro-toolbar-row toolbar-row">
          <div className="toolbar-row-left">{topLeft}</div>
          <div className="toolbar-row-right">{topRight}</div>
        </div>
      )}
      {(bottomLeft || bottomRight) && (
        <div className="pisell-grid-pro-toolbar-row toolbar-row">
          <div className="toolbar-row-left">{bottomLeft}</div>
          <div className="toolbar-row-right">{bottomRight}</div>
        </div>
      )}
    </div>
  );
};
```

### 类型定义

```
export interface ToolBarProps {
  /** 自定义类名 */
  className?: string;
  /** 自定义样式 */
  style?: React.CSSProperties;
  /** 标签页区域内容 */
  tabs?: React.ReactNode;
  /** 上方左侧区域内容 */
  topLeft?: React.ReactNode;
  /** 上方右侧区域内容 */
  topRight?: React.ReactNode;
  /** 下方左侧区域内容 */
  bottomLeft?: React.ReactNode;
  /** 下方右侧区域内容 */
  bottomRight?: React.ReactNode;
}
```

## 样式实现

### 容器样式

```less
.pisell-grid-pro-toolbar {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-bottom: 16px;
  gap: 12px;
  background: #ffffff;
}
```

### 行布局

```less
&-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 12px;
  align-self: stretch;
}
```

### 左右分栏

```less
.toolbar-row {
  justify-content: space-between;

  &-left {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 8px;
    flex: 1;
  }

  &-right {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
  }
}
```

## 设计模式

### 1. 条件渲染

组件采用条件渲染策略，只有当插槽有内容时才渲染对应的行：

```
{tabs && <div className="pisell-grid-pro-toolbar-row">{tabs}</div>}
{(topLeft || topRight) && (
  <div className="pisell-grid-pro-toolbar-row toolbar-row">
    {/* ... */}
  </div>
)}
```

**优点**:

- 避免空白占位，节省渲染开销
- 提升用户体验，不显示无用的空白区域

### 2. 插槽设计

所有插槽均使用 `ReactNode` 类型：

```
tabs?: React.ReactNode;
topLeft?: React.ReactNode;
// ...
```

**优点**:

- 最大化灵活性，支持任意 React 元素
- 便于业务方自定义内容

### 3. 样式扩展

支持 `className` 和 `style` 自定义：

```
const toolbarClassName = classNames('pisell-grid-pro-toolbar', className);
return <div className={toolbarClassName} style={style}>
```

**优点**:

- 支持外部样式覆盖
- 保留组件基础样式

## 开发规范

### 命名约定

1. **组件名**: Toolbar (不使用 Pisell 前缀，因为是子组件)
2. **类名前缀**: `pisell-grid-pro-toolbar`
3. **Props 接口**: `ToolBarProps`
4. **文件命名**: 使用 index.tsx、index.less

### 代码风格

1. **使用函数组件**: 采用 `React.FC<Props>` 形式
2. **Props 解构**: 在函数参数中直接解构
3. **条件渲染**: 使用 `&&` 运算符
4. **类名组合**: 使用 `classnames` 库

### 注释规范

```
/**
 * ToolBar 组件 Props
 * @description 工具栏组件属性定义
 */
export interface ToolBarProps {
  /**
   * 自定义类名
   */
  className?: string;
  // ...
}
```

## 性能优化

### 1. 避免不必要的渲染

由于组件较为简单，暂未使用 `React.memo`。如果在复杂场景下频繁渲染，可以考虑：

```
export default React.memo(Toolbar);
```

### 2. 条件渲染优化

只渲染有内容的行，避免空 DOM 节点：

```
{tabs && <div>{tabs}</div>}
```

### 3. 样式优化

- 使用 Less 变量统一管理间距、颜色
- 避免使用复杂的 CSS 选择器
- 尽量使用 Flexbox 布局，避免浮动

## 扩展指南

### 添加新插槽

如果需要添加新的插槽位置：

1. 在 `ToolBarProps` 中添加新属性
2. 在组件 JSX 中添加对应的渲染逻辑
3. 在 Less 文件中添加对应的样式
4. 更新文档和示例

示例：添加 middle 行

```
// type.ts
export interface ToolBarProps {
  // ...
  middleLeft?: React.ReactNode;
  middleRight?: React.ReactNode;
}
```

```
// index.tsx
{(middleLeft || middleRight) && (
  <div className="pisell-grid-pro-toolbar-row toolbar-row">
    <div className="toolbar-row-left">{middleLeft}</div>
    <div className="toolbar-row-right">{middleRight}</div>
  </div>
)}
```

### 自定义主题

通过 Less 变量自定义主题：

```less
@toolbar-bg: #ffffff;
@toolbar-gap: 12px;
@toolbar-padding-bottom: 16px;
@toolbar-row-left-gap: 8px;
@toolbar-row-right-gap: 12px;

.pisell-grid-pro-toolbar {
  background: @toolbar-bg;
  gap: @toolbar-gap;
  padding-bottom: @toolbar-padding-bottom;
  // ...
}
```

## 调试技巧

### 1. 使用 React DevTools

在 React DevTools 中查看组件 Props 和渲染情况

### 2. 添加调试边框

临时添加边框，查看布局情况：

```less
.pisell-grid-pro-toolbar {
  border: 1px solid red;

  &-row {
    border: 1px solid blue;
  }

  .toolbar-row-left,
  .toolbar-row-right {
    border: 1px solid green;
  }
}
```

### 3. 日志输出

在组件内添加日志：

```
console.log('ToolBar props:', props);
```

## 常见问题

### Q1: 为什么不使用语义化命名？

A: 如注释所述，使用位置命名（topLeft/topRight）而非语义化命名（actions/filters）可以提供更大的灵活性，避免误导开发者某个插槽只能放特定内容。

### Q2: 如何调整间距？

A: 可以通过以下方式：

1. 使用 `style` prop 覆盖容器样式
2. 使用 `className` 添加自定义类
3. 修改 Less 文件中的间距值

### Q3: 为什么左右区域的 gap 不同？

A: 根据 Figma 设计稿，左侧区域使用 8px 间距，右侧区域使用 12px 间距，这是为了在视觉上更好地平衡内容密度。

## 相关资源

- [React 官方文档](https://react.dev/)
- [TypeScript 官方文档](https://www.typescriptlang.org/)
- [Less 官方文档](https://lesscss.org/)
- [classnames 库](https://github.com/JedWatson/classnames)

## 版本历史

- v1.0.0: 初始版本
  - 支持 tabs、topLeft、topRight、bottomLeft、bottomRight 六个插槽
  - 支持自定义 className 和 style
  - 基于 Figma 设计稿实现
