nex_design/docs/components/ButtonExtension.md

752 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 按钮扩展组件设计文档
> **版本:** v1.2.0
> **更新时间:** 2025-11-17
> **作者:** Nex Design Team
> **状态:** ✅ 已完成
---
## 📖 目录
1. [概述](#概述)
2. [设计方案](#设计方案)
3. [组件API](#组件api)
4. [使用指南](#使用指南)
5. [最佳实践](#最佳实践)
6. [更新日志](#更新日志)
---
## 概述
### 设计目标
为终端列表页面的按钮提供清晰的操作介绍和帮助信息,解决以下问题:
- 用户不了解按钮功能
- 复杂操作缺少引导
- 需要快速的上下文帮助
### 设计原则
1. **简洁至上** - 去除不必要的动画,使用扁平化设计
2. **功能独立** - 帮助功能不影响主操作流程
3. **易于理解** - 直观的图标和交互模式
4. **现代美学** - 符合Material Design和Fluent Design趋势
---
## 设计方案
我们提供了5种不同的设计方案可根据实际场景选择使用
### 方案1增强型工具提示 (Enhanced Tooltip)
**特点:**
- 渐变色彩背景,视觉效果出众
- 支持标题、描述、快捷键、注意事项
- 带有脉冲动画的提示图标
- 响应式设计,移动端友好
**适用场景:**
- ✅ 简单操作,需要快速了解功能
- ✅ 不希望占用额外页面空间
- ✅ 信息量较少的提示
**效果预览:**
```
[按钮] (i) ← 脉冲动画图标
↓ 悬停
┌────────────────────────┐
│ 新增主机 │
│ 向系统中添加新的主机... │
│ 快捷键: Ctrl+N │
│ 注意: 请确保IP不冲突 │
└────────────────────────┘
```
---
### 方案2智能帮助面板 (Smart Help Panel) ⭐ 推荐
**特点:**
- 侧边抽屉式设计,信息完整
- 实时显示当前悬停按钮的详细信息
- 包含使用场景、操作步骤、注意事项等
- 支持查看所有可用操作的快速索引
- 点击"?"图标直接打开帮助面板
**适用场景:**
- ✅ 复杂业务操作,需要详细说明
- ✅ 新用户培训和引导
- ✅ 功能较多,需要分步骤引导
**交互流程:**
```
1. 悬停按钮 → 出现"?"图标
2. 点击"?" → 打开右侧帮助面板
3. 显示详细内容:
- 功能说明
- 使用场景
- 操作步骤
- 注意事项
- 快捷键
- 权限要求
```
**特殊优化:**
- 面板打开时,鼠标离开按钮不会清空内容
- 点击"所有可用操作"卡片可切换内容
- 自动展开"当前操作"区域
---
### 方案3悬浮展开卡片 (Hover Expand Card)
**特点:**
- 精美的悬浮卡片设计
- 滑入动画,视觉流畅
- 分层信息展示
- 使用React Portal渲染永不被遮挡
**适用场景:**
- ✅ 需要展示较多信息
- ✅ 不想打断操作流程
- ✅ 希望信息就近显示
**技术实现:**
```jsx
// 使用Portal避免z-index遮挡问题
import { createPortal } from 'react-dom'
{createPortal(renderCard(), document.body)}
```
---
### 方案4智能引导 (Smart Guide)
**特点:**
- 简洁扁平设计,独立帮助图标
- 点击查看弹窗式详细引导
- 包含步骤式操作说明
**适用场景:**
- ✅ 需要详细引导,但不希望干扰主流程
- ✅ 功能上线初期的用户引导
- ✅ 复杂操作的分步说明
**设计对比:**
```
旧版(已废弃):脉冲动画徽章,过于复杂
新版:简洁帮助图标,点击查看详情
┌────────────┐ ┌─┐
│ 新增主机 │ │?│ ← 简洁优雅
└────────────┘ └─┘
```
---
### 方案5底部固定提示栏 (Bottom Hint Bar)
**特点:**
- 固定底部位置,不遮挡操作区域
- 实时更新,流畅切换
- 三种主题可选(渐变、浅色、深色)
**适用场景:**
- ✅ 需要始终可见的提示信息
- ✅ 不希望被tooltip遮挡操作区域
- ✅ 简单的实时信息展示
---
## 组件API
### ButtonWithTip
增强型工具提示按钮组件。
**Props:**
```typescript
interface ButtonWithTipProps {
label: string // 按钮文本
icon?: ReactNode // 按钮图标
type?: 'primary' | 'default' // 按钮类型
danger?: boolean // 是否为危险按钮
disabled?: boolean // 是否禁用
onClick?: () => void // 点击回调
size?: 'small' | 'middle' | 'large'
showTipIcon?: boolean // 是否显示提示图标
tip?: {
title?: string // 提示标题
description?: string // 详细描述
shortcut?: string // 快捷键
notes?: string[] // 注意事项
placement?: 'top' | 'bottom' | 'left' | 'right'
}
}
```
**使用示例:**
```jsx
import ButtonWithTip from '@/components/ButtonWithTip/ButtonWithTip'
<ButtonWithTip
label="新增主机"
icon={<PlusOutlined />}
type="primary"
tip={{
title: '新增主机',
description: '向系统中添加新的主机终端设备',
shortcut: 'Ctrl+N',
notes: ['请确保IP地址不与现有主机冲突', 'MAC地址必须唯一']
}}
onClick={handleAdd}
/>
```
---
### ActionHelpPanel
智能帮助面板组件方案2
**Props:**
```typescript
interface ActionHelpPanelProps {
visible: boolean // 是否显示面板
onClose: () => void // 关闭回调
currentAction?: { // 当前操作信息
title: string
icon: ReactNode
description: string
scenarios?: string[] // 使用场景
steps?: string[] // 操作步骤
warnings?: string[] // 注意事项
shortcut?: string // 快捷键
permission?: string // 权限要求
badge?: {
text: string
color: string
}
}
allActions?: Array<Action> // 所有可用操作
placement?: 'left' | 'right' // 面板位置
onActionSelect?: (action: Action) => void // 选择操作回调
}
```
**使用示例:**
```jsx
import ActionHelpPanel from '@/components/ActionHelpPanel/ActionHelpPanel'
const [showPanel, setShowPanel] = useState(false)
const [currentAction, setCurrentAction] = useState(null)
// 在按钮外层添加hover和点击事件
<div
onMouseEnter={() => setCurrentAction(actionsConfig.add)}
onMouseLeave={() => !showPanel && setCurrentAction(null)}
>
<Button>新增主机</Button>
<button onClick={() => setShowPanel(true)}>?</button>
</div>
<ActionHelpPanel
visible={showPanel}
onClose={() => setShowPanel(false)}
currentAction={currentAction}
allActions={Object.values(actionsConfig)}
onActionSelect={(action) => setCurrentAction(action)}
/>
```
---
### ButtonWithHoverCard
悬浮展开卡片按钮组件方案3
**Props:**
```typescript
interface ButtonWithHoverCardProps {
label: string
icon?: ReactNode
type?: 'primary' | 'default'
danger?: boolean
disabled?: boolean
onClick?: () => void
size?: 'small' | 'middle' | 'large'
cardInfo?: {
title: string
icon: ReactNode
description: string
scenarios?: string[]
quickTips?: string[]
warnings?: string[]
shortcut?: string
badge?: { text: string; color: string }
}
}
```
**技术要点:**
- 使用 `createPortal` 渲染卡片到 `document.body`
- 使用 `useRef` 获取按钮位置
- 避免z-index遮挡问题
---
### ButtonWithGuide
智能引导按钮组件方案4
**Props:**
```typescript
interface ButtonWithGuideProps {
label: string
icon?: ReactNode
type?: 'primary' | 'default'
danger?: boolean
disabled?: boolean
onClick?: () => void
size?: 'small' | 'middle' | 'large'
guide?: {
title: string
icon: ReactNode
description: string
steps?: string[]
scenarios?: string[]
warnings?: string[]
shortcut?: string
permission?: string
badge?: { text: string; color: string }
}
}
```
**特点:**
- 简洁的帮助图标(不影响按钮文字)
- 点击打开弹窗式详细引导
- 包含步骤式说明使用Ant Design Steps组件
---
### BottomHintBar
底部固定提示栏组件方案5
**Props:**
```typescript
interface BottomHintBarProps {
visible: boolean
hintInfo?: {
title: string
icon: ReactNode
description: string
quickTip?: string
warning?: string
shortcut?: string
badge?: { text: string; color: string }
}
onClose?: () => void
theme?: 'light' | 'dark' | 'gradient'
}
```
**使用示例:**
```jsx
import BottomHintBar from '@/components/BottomHintBar/BottomHintBar'
const [showHint, setShowHint] = useState(false)
const [hintInfo, setHintInfo] = useState(null)
<div
onMouseEnter={() => {
setHintInfo(actionConfig)
setShowHint(true)
}}
onMouseLeave={() => setShowHint(false)}
>
<Button>操作按钮</Button>
</div>
<BottomHintBar
visible={showHint}
hintInfo={hintInfo}
theme="gradient"
/>
```
---
## 使用指南
### 快速开始
1. **选择合适的方案**
根据使用场景选择组件:
| 场景 | 推荐方案 |
|------|---------|
| 简单列表页面,快速提示 | 方案1 增强型工具提示 |
| 复杂后台系统,详细引导 | 方案2 智能帮助面板 ⭐ |
| 数据密集页面,信息丰富 | 方案3 悬浮展开卡片 |
| 新功能上线,用户引导 | 方案4 智能引导 |
| 操作频繁,始终可见 | 方案5 底部固定提示栏 |
2. **导入组件**
```jsx
// 方案1
import ButtonWithTip from '@/components/ButtonWithTip/ButtonWithTip'
// 方案2
import ActionHelpPanel from '@/components/ActionHelpPanel/ActionHelpPanel'
// 方案3
import ButtonWithHoverCard from '@/components/ButtonWithHoverCard/ButtonWithHoverCard'
// 方案4
import ButtonWithGuide from '@/components/ButtonWithGuide/ButtonWithGuide'
// 方案5
import BottomHintBar from '@/components/BottomHintBar/BottomHintBar'
```
3. **配置操作信息**
建议将操作配置统一管理:
```jsx
const actionsConfig = {
add: {
title: '新增主机',
icon: <PlusOutlined />,
description: '向系统中添加新的主机终端设备',
scenarios: [
'当有新设备需要接入系统管理时',
'需要扩展终端设备数量时'
],
steps: [
'点击"新增主机"按钮',
'填写主机基本信息',
'选择主机所属分组',
'保存并等待主机上线'
],
warnings: [
'请确保IP地址不与现有主机冲突',
'MAC地址必须唯一且格式正确'
],
shortcut: 'Ctrl+N',
permission: '管理员权限',
badge: { text: '常用', color: 'blue' }
},
// ... 其他操作
}
```
---
### 方案2完整实现示例
```jsx
import { useState } from 'react'
import { Button } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import ActionHelpPanel from '@/components/ActionHelpPanel/ActionHelpPanel'
function MyPage() {
const [showHelpPanel, setShowHelpPanel] = useState(false)
const [currentAction, setCurrentAction] = useState(null)
// 处理悬停
const handleHover = (actionKey) => {
if (!showHelpPanel) {
setCurrentAction(actionsConfig[actionKey])
}
}
// 处理离开
const handleLeave = () => {
if (!showHelpPanel) {
setCurrentAction(null)
}
}
// 处理点击
const handleHelpClick = (e, actionKey) => {
e.stopPropagation()
setCurrentAction(actionsConfig[actionKey])
setShowHelpPanel(true)
}
return (
<div>
{/* 按钮区域 */}
<div
className="button-wrapper"
onMouseEnter={() => handleHover('add')}
onMouseLeave={handleLeave}
>
<Button type="primary" icon={<PlusOutlined />}>
新增主机
</Button>
<button
className="help-icon"
onClick={(e) => handleHelpClick(e, 'add')}
>
?
</button>
</div>
{/* 帮助面板 */}
<ActionHelpPanel
visible={showHelpPanel}
onClose={() => setShowHelpPanel(false)}
currentAction={currentAction}
allActions={Object.values(actionsConfig)}
onActionSelect={(action) => setCurrentAction(action)}
/>
</div>
)
}
```
---
## 最佳实践
### 1. 内容编写规范
**功能描述:**
- 用简洁的语言描述功能1-2句话
- 突出重点和目的
- 避免技术术语
**使用场景:**
- 列举2-4个实际使用场景
- 使用"当...时"的句式
- 帮助用户理解何时使用
**操作步骤:**
- 按实际操作顺序编写
- 每步一句话,清晰明确
- 使用动词开头
**注意事项:**
- 危险操作必须有明确警告
- 使用醒目的颜色标记
- 提供实际的使用建议
### 2. 性能优化
```jsx
// ✅ 使用useMemo缓存配置
const actionsConfig = useMemo(() => ({
add: { ... },
delete: { ... }
}), [])
// ✅ 防止不必要的重渲染
const handleHover = useCallback((key) => {
if (!showPanel) {
setCurrentAction(actionsConfig[key])
}
}, [showPanel, actionsConfig])
// ✅ 面板打开时避免hover更新
if (!showPanel) {
setCurrentAction(null)
}
```
### 3. 可访问性
```jsx
// 添加title属性
<button className="help-icon" title="查看帮助">
?
</button>
// 添加aria标签
<Button aria-label="新增主机">
新增主机
</Button>
// 快捷键支持
useEffect(() => {
const handleKeyPress = (e) => {
if (e.ctrlKey && e.key === 'n') {
handleAdd()
}
}
window.addEventListener('keydown', handleKeyPress)
return () => window.removeEventListener('keydown', handleKeyPress)
}, [])
```
### 4. 响应式适配
```css
/* 移动端隐藏某些提示 */
@media (max-width: 768px) {
.help-icon {
display: none;
}
.hover-info-card {
width: 100%;
left: 0 !important;
transform: translateY(-50%);
}
}
```
---
## 更新日志
### v1.2.0 (2025-11-17)
**新增:**
- ✨ 新增 `ButtonWithGuide` 组件,替代复杂的徽章设计
- ✨ 方案2添加 `onActionSelect` 回调,支持点击卡片切换内容
**修复:**
- 🐛 修复方案2点击"?"后内容消失的问题
- 🐛 修复方案2"所有可用操作"卡片无法点击的问题
- 🐛 修复方案3悬浮卡片被Card遮挡使用Portal
- 🐛 修复菜单图标,从 `GlobalOutlined` 改为 `BlockOutlined`
**优化:**
- 💄 简化方案4设计去掉复杂的脉冲动画
- 💄 方案2面板打开时不响应鼠标hover事件
- 💄 提升整体视觉一致性
### v1.1.0 (2025-11-17)
**新增:**
- ✨ 新增 `ActionHelpPanel` 智能帮助面板组件
- ✨ 新增 `BottomHintBar` 底部提示栏组件
- ✨ 方案2添加点击"?"图标直接打开面板功能
**修复:**
- 🐛 修复 `ButtonWithTip` 的 Tooltip overlayClassName 警告
- 🐛 修复 `AppSider` 的 findDOMNode 警告(使用 items 配置)
- 🐛 修复方案5底部提示栏鼠标移动时闪烁的问题
**优化:**
- 💄 为方案2按钮添加悬停时的"?"图标提示
- 💄 提升方案3悬浮卡片的 z-index 和阴影效果
### v1.0.0 (2025-11-17)
**初始版本:**
- 🎉 发布5种按钮扩展设计方案
- 📦 提供完整的组件API和使用文档
- 📝 提供详细的设计指南和最佳实践
---
## 技术架构
### 依赖项
```json
{
"react": "^18.2.0",
"react-dom": "^18.2.0",
"antd": "^5.x",
"@ant-design/icons": "^5.x"
}
```
### 目录结构
```
src/components/
├── ButtonWithTip/
│ ├── ButtonWithTip.jsx
│ └── ButtonWithTip.css
├── ActionHelpPanel/
│ ├── ActionHelpPanel.jsx
│ └── ActionHelpPanel.css
├── ButtonWithHoverCard/
│ ├── ButtonWithHoverCard.jsx
│ └── ButtonWithHoverCard.css
├── ButtonWithGuide/
│ ├── ButtonWithGuide.jsx
│ └── ButtonWithGuide.css
└── BottomHintBar/
├── BottomHintBar.jsx
└── BottomHintBar.css
src/pages/
└── AllButtonDesigns.jsx # 演示页面
docs/
└── components/
└── ButtonExtensions.md # 本文档
```
---
## 常见问题
### Q1: 如何选择合适的方案?
**A:** 根据以下因素选择:
- **信息量**:少 → 方案1多 → 方案2/3
- **复杂度**:简单 → 方案1/5复杂 → 方案2/4
- **使用频率**:频繁 → 方案5偶尔 → 方案1/3
- **用户类型**:新手 → 方案2/4熟练 → 方案1/5
### Q2: 可以混合使用多种方案吗?
**A:** 可以。建议:
- 同一页面使用统一的方案
- 不同页面可以使用不同方案
- 核心操作使用方案2次要操作使用方案1
### Q3: 如何自定义样式?
**A:** 所有组件都支持自定义样式:
```jsx
// 通过className
<ButtonWithTip className="my-custom-button" />
// 通过style
<ButtonWithTip style={{ marginRight: 16 }} />
// 修改CSS变量
:root {
--tip-primary-gradient: linear-gradient(...);
}
```
### Q4: 移动端如何适配?
**A:** 所有组件都内置了响应式支持:
- 方案1移动端隐藏提示图标
- 方案2面板宽度自适应
- 方案3卡片居中显示
- 方案5提示栏自适应布局
---
**最后更新:** 2025-11-17
**文档版本:** v1.2.0