---
title: 设计文档
order: 2
category: pro
---

# PisellSingleLineText 组件设计文档

> **组件定位**：PisellSingleLineText 是 Pisell 组件库中的基础单行文本输入/展示组件，适用于名称、标题、编号、描述性短文本等场景。组件基于
> Ant Design Input 组件开发，提供三种状态模式、可配置的展示样式和完整的校验框架。

## 1 组件概述

### 1.1 组件定位

PisellSingleLineText 是一个通用的单行文本组件，具有以下特点：

- **不绑定业务语义**：可用于各种单行文本场景
- **状态灵活切换**：支持只读、编辑、禁用三种状态
- **高度可配置**：样式、行为、校验规则均可配置
- **基于 Ant Design**：复用 Ant Design Input 组件的能力

### 1.2 使用场景

- 用户名称、昵称输入
- 标题、副标题编辑
- 编号、代码输入
- 简短描述性文本
- 搜索框、标签输入等

### 1.3 设计稿

Figma 设计稿：https://www.figma.com/design/pM8Ho6d7kCMv9vIBvFHUlj/Pisell-2.0-Component-Library?node-id=3215-6133&m=dev

### 1.4 相关组件

本组件是文本组件系列的第一个，后续还会开发：

- PisellLongText（长文本/多行文本）
- PisellPhone（电话号码）
- PisellEmail（邮箱地址）
- PisellUrl（URL 链接）

注：这些组件均为独立组件，但会复用共同的逻辑代码（hooks/utils）。

## 2 组件状态设计

### 2.1 三种状态模式

PisellSingleLineText 支持三种状态，通过 `mode` 和 `disabled` 属性控制：

| 状态      | 视觉表现            | 交互行为                  | 透明度  | 使用场景      |
|---------|-----------------|-----------------------|------|-----------|
| **只读态** | 不显示输入框，以纯文本形式展示 | 不可编辑，保留截断与样式配置        | 100% | 信息展示、数据预览 |
| **编辑态** | 显示输入框边框，可聚焦     | 可输入、可复制粘贴，支持校验提示      | 100% | 表单输入、内容编辑 |
| **禁用态** | 输入框灰化显示         | 不可编辑，无 hover/focus 状态 | 40%  | 表单禁用、权限限制 |

### 2.2 状态切换逻辑

// 状态优先级：disabled > mode
// 当 disabled=true 时，无论 mode 是什么，都显示为禁用态
interface StateControl {
mode: 'read' | 'edit'; // 基础模式
disabled?: boolean; // 禁用开关，优先级最高
}

// 渲染逻辑
function getDisplayState(mode: string, disabled: boolean) {
if (disabled) return 'disabled';
return mode; // 'read' or 'edit'
}

## 3 组件架构设计

### 3.1 渲染逻辑分层

组件采用状态驱动的渲染模式，将展示与编辑逻辑分离：

// 组件渲染逻辑
function PisellSingleLineText(props: PisellSingleLineTextProps) {
const displayState = getDisplayState(props.mode, props.disabled);

    switch (displayState) {
        case 'read':
            return <ReadOnlyView {...props} />; // 纯文本展示
        case 'edit':
            return <EditView {...props} />;      // Ant Design Input
        case 'disabled':
            return <DisabledView {...props} />; // 禁用态展示
    }

}

### 3.2 关注点分离

**只读态（ReadOnlyView）**：

- 支持 4 种展示样式变体：
  - **普通文本**（text）：默认样式，纯文本展示
  - **超链接样式**（link）：带下划线和颜色，可点击
  - **徽标样式**（badge）：带状态点的文本（成功/失败/警告等）
  - **标签样式**（tag）：有背景色的标签，可关闭
- 文本截断处理（ellipsis）
- 样式应用（fontSize、fontWeight、color）
- Tooltip 显示完整内容
- 可配置文本对齐方式

**编辑态（EditView）**：

- 基于 Ant Design Input 组件
- 处理输入、复制粘贴
- 实时校验与错误提示
- 字数统计与限制
- 清空按钮、前后缀配置

**禁用态（DisabledView）**：

- 基于编辑态或只读态视觉
- 透明度 40%
- 禁止所有交互行为

### 3.3 可配置性设计

组件通过 Props 提供丰富的配置项，满足不同场景需求：

interface PisellSingleLineTextProps {
// ========== 核心属性 ==========
value?: string; // 输入值（受控）
defaultValue?: string; // 默认值（非受控）
mode?: 'read' | 'edit'; // 状态模式，默认 'edit'
disabled?: boolean; // 是否禁用，默认 false

    // ========== 展示配置 ==========
    // 只读态样式
    ellipsis?: boolean;                // 超出省略，默认 true
    showTooltip?: boolean;             // 悬停显示完整内容，默认 true
    fontSize?: string | number;        // 字号，如 '14px' 或 14
    fontWeight?: string | number;      // 字重，如 'bold' 或 600
    color?: string;                    // 文本颜色
    textAlign?: 'left' | 'center' | 'right'; // 对齐方式，默认 'left'
    
    // ========== 编辑配置 ==========
    // 基于 Ant Design Input 的配置
    placeholder?: string;              // 占位文本
    maxLength?: number;                // 最大长度
    showCount?: boolean;               // 显示字数统计，默认 false
    allowClear?: boolean;              // 显示清空按钮，默认 false
    autoFocus?: boolean;               // 自动聚焦，默认 false
    prefix?: React.ReactNode;          // 前缀图标/文本
    suffix?: React.ReactNode;          // 后缀图标/文本
    addonBefore?: React.ReactNode;     // 前置标签
    addonAfter?: React.ReactNode;      // 后置标签
    
    // ========== 校验配置 ==========
    required?: boolean;                // 是否必填
    minLength?: number;                // 最小长度
    pattern?: string | RegExp;         // 自定义正则校验
    validator?: (value: string) => boolean | string; // 自定义校验函数
    validateTrigger?: 'onChange' | 'onBlur' | 'both'; // 校验触发时机
    errorMessage?: string;             // 自定义错误提示
    
    // ========== 事件回调 ==========
    onChange?: (value: string) => void;           // 值变化回调
    onBlur?: (value: string) => void;            // 失焦回调
    onFocus?: () => void;                        // 聚焦回调
    onPressEnter?: (value: string) => void;      // 回车回调
    onValidate?: (isValid: boolean, errors: string[]) => void; // 校验回调
    
    // ========== 样式类名 ==========
    className?: string;                // 自定义类名
    style?: React.CSSProperties;       // 自定义样式
    
    // ========== 无障碍访问 ==========
    'aria-label'?: string;
    'aria-describedby'?: string;

}

## 4 校验框架设计

### 4.1 校验规则

PisellSingleLineText 支持多种校验规则，按优先级执行：

| 优先级 | 校验规则    | 配置项       | 说明                    |
|-----|---------|-----------|-----------------------|
| 1   | 必填校验    | required  | 值不能为空或纯空白字符           |
| 2   | 最小长度校验  | minLength | 字符数不能少于指定值            |
| 3   | 最大长度校验  | maxLength | 字符数不能超过指定值（输入时自动截断）   |
| 4   | 正则校验    | pattern   | 值必须匹配指定的正则表达式         |
| 5   | 自定义校验函数 | validator | 自定义校验逻辑，返回 true 或错误信息 |

### 4.2 校验触发时机

通过 `validateTrigger` 配置校验触发时机：

- `'onChange'`：输入时实时校验（适合即时反馈场景）
- `'onBlur'`：失焦时校验（默认，避免输入过程中频繁提示）
- `'both'`：同时支持两种时机

### 4.3 校验实现

// 校验规则定义
interface ValidationRule {
validate: (value: string) => boolean;
message: string;
priority: number;
}

// 校验执行逻辑
function validateValue(
value: string,
props: PisellSingleLineTextProps
): { isValid: boolean; errors: string[] } {
const errors: string[] = [];

    // 1. 必填校验
    if (props.required && !value?.trim()) {
        errors.push(props.errorMessage || '此字段为必填项');
        return { isValid: false, errors };
    }
    
    // 2. 最小长度校验
    if (props.minLength && value.length < props.minLength) {
        errors.push(`最少需要 ${props.minLength} 个字符`);
    }
    
    // 3. 最大长度校验（通常在输入时已限制，这里是兜底）
    if (props.maxLength && value.length > props.maxLength) {
        errors.push(`最多允许 ${props.maxLength} 个字符`);
    }
    
    // 4. 正则校验
    if (props.pattern) {
        const regex = typeof props.pattern === 'string' 
            ? new RegExp(props.pattern) 
            : props.pattern;
        if (!regex.test(value)) {
            errors.push(props.errorMessage || '格式不正确');
        }
    }
    
    // 5. 自定义校验
    if (props.validator) {
        const result = props.validator(value);
        if (result !== true) {
            errors.push(typeof result === 'string' ? result : '校验失败');
        }
    }
    
    return {
        isValid: errors.length === 0,
        errors
    };

}

### 4.4 错误提示展示

- 编辑态：在输入框下方显示错误信息（红色文本）
- 输入框边框变为红色（使用 Ant Design 的 status="error"）
- 支持自定义错误信息通过 `errorMessage` 配置

## 5 状态管理设计

### 5.1 受控与非受控模式

组件同时支持受控和非受控两种使用方式：

**受控模式**（推荐）：
const [value, setValue] = useState('');

<PisellSingleLineText
value={value}
onChange={(newValue) => setValue(newValue)}
/>

**非受控模式**：
<PisellSingleLineText
defaultValue="初始值"
onChange={(newValue) => console.log(newValue)}
/>

### 5.2 内部状态管理 Hook

封装自定义 Hook 管理组件内部状态：

/**

* 文本输入状态管理 Hook
* 管理值、校验状态、错误信息等
  */
  function useTextInputState(props: PisellSingleLineTextProps) {
  // 判断是否为受控组件
  const isControlled = props.value !== undefined;

  // 内部状态
  const [innerValue, setInnerValue] = useState(props.defaultValue || '');
  const [isTouched, setIsTouched] = useState(false);
  const [isValid, setIsValid] = useState(true);
  const [errors, setErrors] = useState<string[]>([]);

  // 当前值（受控优先）
  const currentValue = isControlled ? props.value : innerValue;

  // 值变更处理
  const handleChange = useCallback((newValue: string) => {
  // 更新内部状态（非受控模式）
  if (!isControlled) {
  setInnerValue(newValue);
  }

       // 根据配置决定是否立即校验
       if (props.validateTrigger === 'onChange' || props.validateTrigger === 'both') {
           const validation = validateValue(newValue, props);
           setIsValid(validation.isValid);
           setErrors(validation.errors);
           props.onValidate?.(validation.isValid, validation.errors);
       }
       
       // 触发外部回调
       props.onChange?.(newValue);
  }, [isControlled, props]);

  // 失焦处理
  const handleBlur = useCallback(() => {
  setIsTouched(true);

       // 失焦时执行校验
       if (props.validateTrigger !== 'onChange') {
           const validation = validateValue(currentValue || '', props);
           setIsValid(validation.isValid);
           setErrors(validation.errors);
           props.onValidate?.(validation.isValid, validation.errors);
       }
       
       props.onBlur?.(currentValue || '');
  }, [currentValue, props]);

  // 聚焦处理
  const handleFocus = useCallback(() => {
  setIsTouched(true);
  props.onFocus?.();
  }, [props]);

  return {
  value: currentValue,
  isTouched,
  isValid,
  errors,
  handleChange,
  handleBlur,
  handleFocus
  };
  }

### 5.3 事件流程

用户输入
↓
handleChange 触发
↓
更新内部状态（非受控）/ 通知外部（受控）
↓
校验（根据 validateTrigger）
↓
更新校验状态
↓
触发 onChange 回调
↓
UI 重新渲染

## 6 技术实现要点

### 6.1 基于 Ant Design Input

组件基于 `antd` 的 `Input` 组件进行封装：

import { Input } from 'antd';

// 编辑态渲染
function EditView(props: PisellSingleLineTextProps) {
const { value, handleChange, isValid, errors } = useTextInputState(props);

    return (
        <div className="pisell-single-line-text-edit">
            <Input
                value={value}
                onChange={(e) => handleChange(e.target.value)}
                onBlur={handleBlur}
                onFocus={handleFocus}
                onPressEnter={(e) => props.onPressEnter?.(e.currentTarget.value)}
                placeholder={props.placeholder}
                maxLength={props.maxLength}
                showCount={props.showCount}
                allowClear={props.allowClear}
                prefix={props.prefix}
                suffix={props.suffix}
                addonBefore={props.addonBefore}
                addonAfter={props.addonAfter}
                disabled={props.disabled}
                status={isValid ? undefined : 'error'}
                {...props['aria-label'] && { 'aria-label': props['aria-label'] }}
            />
            {!isValid && errors.length > 0 && (
                <div className="pisell-single-line-text-error">
                    {errors[0]}
                </div>
            )}
        </div>
    );

}

### 6.2 只读态实现

只读态使用 Typography.Text 实现文本展示和截断：

import { Typography, Tooltip } from 'antd';

function ReadOnlyView(props: PisellSingleLineTextProps) {
const textStyle: React.CSSProperties = {
fontSize: props.fontSize,
fontWeight: props.fontWeight,
color: props.color,
textAlign: props.textAlign,
};

    const textContent = (
        <Typography.Text
            ellipsis={props.ellipsis}
            style={textStyle}
            className="pisell-single-line-text-read"
        >
            {props.value}
        </Typography.Text>
    );
    
    // 如果启用 tooltip 且内容被截断，显示悬浮提示
    if (props.showTooltip && props.ellipsis) {
        return (
            <Tooltip title={props.value}>
                {textContent}
            </Tooltip>
        );
    }
    
    return textContent;

}

### 6.3 性能优化

// 1. 防抖输入（可选配置）
function useDebouncedChange(
onChange: (value: string) => void,
delay: number = 300
) {
const debouncedOnChange = useMemo(
() => debounce(onChange, delay),
[onChange, delay]
);

    useEffect(() => {
        return () => debouncedOnChange.cancel();
    }, [debouncedOnChange]);

    return debouncedOnChange;

}

// 2. 使用 React.memo 避免不必要的重渲染
export const PisellSingleLineText = React.memo((props: PisellSingleLineTextProps) => {
// 组件实现
}, (prevProps, nextProps) => {
// 自定义比较逻辑
return prevProps.value === nextProps.value &&
prevProps.mode === nextProps.mode &&
prevProps.disabled === nextProps.disabled;
});

// 3. useCallback 缓存事件处理函数
const handleChange = useCallback((newValue: string) => {
// 处理逻辑
}, [依赖项]);

### 6.4 代码复用设计

为后续其他文本组件（Long Text、Phone、Email、URL）抽取可复用的逻辑：

// 可复用的 Hooks（存放在 hooks/ 目录）
export { useTextInputState } from './hooks/useTextInputState';
export { useTextValidation } from './hooks/useTextValidation';

// 可复用的工具函数（存放在 utils/ 目录）
export { validateValue } from './utils/validation';
export { getDisplayState } from './utils/stateHelper';

## 7 开发规范

### 7.1 文件结构

pisellSingleLineText/
├── index.tsx # 导出文件
├── PisellSingleLineText.tsx # 组件主文件
├── PisellSingleLineText.less # 样式文件
├── PisellSingleLineText.test.tsx # 单元测试
├── types.ts # 类型定义
├── hooks/ # 自定义 Hooks
│ ├── index.ts
│ ├── useTextInputState.ts # 状态管理 Hook
│ └── useTextValidation.ts # 校验 Hook
├── utils/ # 工具函数
│ ├── index.ts
│ ├── validation.ts # 校验函数
│ └── stateHelper.ts # 状态辅助函数
├── components/ # 子组件
│ ├── ReadOnlyView.tsx # 只读态视图
│ ├── EditView.tsx # 编辑态视图
│ └── DisabledView.tsx # 禁用态视图
└── docs/ # 文档
├── pisellSingleLineText.md # 使用文档
├── pisellSingleLineText.$tab-design.md # 设计文档（本文档）
├── pisellSingleLineText.$tab-dev.md # 开发文档
└── pisellSingleLineText.$tab-test.md # 测试文档

### 7.2 代码质量要求

1. **TypeScript 类型**：所有 Props 和内部状态必须有明确的类型定义
2. **注释规范**：使用 JSDoc 注释，说明组件、方法、参数用途
3. **测试覆盖**：单元测试覆盖率不低于 85%
4. **代码风格**：遵循 ESLint 和 Prettier 配置
5. **无障碍访问**：支持 ARIA 属性，键盘导航

### 7.3 设计原则

1. **基于 Ant Design**：复用 Ant Design Input 的能力，避免重复造轮子
2. **高内聚、低耦合**：UI 与逻辑分离，便于维护和测试
3. **可配置、可扩展**：提供丰富的配置项，支持自定义扩展
4. **性能优先**：使用 memo、useCallback、useMemo 等优化手段
5. **代码复用**：抽取公共逻辑，为后续其他文本组件提供基础

## 8 总结

PisellSingleLineText 是一个通用的单行文本组件，具备以下核心能力：

- ✅ 三种状态模式（只读、编辑、禁用）
- ✅ 基于 Ant Design Input，复用成熟组件能力
- ✅ 完善的校验框架（必填、长度、正则、自定义）
- ✅ 受控与非受控模式支持
- ✅ 高度可配置（样式、行为、校验）
- ✅ 性能优化（防抖、memo、缓存）
- ✅ 代码复用设计，为后续组件提供基础

本组件将作为文本组件系列的第一个，后续会开发 PisellLongText、PisellPhone、PisellEmail、PisellUrl
等组件，它们将复用本组件的公共逻辑（hooks/utils），保持一致的设计模式和用户体验。
