nex_design/docs/components/ButtonExtension.md

752 lines
17 KiB
Markdown
Raw Permalink Normal View History

2025-11-18 07:38:15 +00:00
# 按钮扩展组件设计文档
> **版本:** 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