mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-19 06:58:57 +08:00
186 lines
9.1 KiB
Markdown
186 lines
9.1 KiB
Markdown
# HyperLinkButton 超链接按钮
|
||
|
||
## 概述
|
||
|
||
超链接按钮(HyperLinkButton)是一个外观类似超链接的按钮控件,支持点击后自动打开浏览器导航到指定 URI。它继承了 Button 的所有能力(尺寸、图标、加载状态、命令绑定),但视觉上呈现为链接文本的样式,用于需要跳转或导航的场景。
|
||
|
||
HyperLinkButton 对应 Ant Design `Button` 的 `type="link"` 变体,但在 AtomUI 中被提取为一个独立的控件类,提供了更丰富的链接交互能力(如 `NavigateUri` 自动导航、`IsVisited` 已访问状态跟踪)。
|
||
|
||
---
|
||
|
||
## 设计原理
|
||
|
||
### Ant Design 的链接按钮设计
|
||
|
||
Ant Design 的按钮体系中,`Button type="link"` 是视觉权重最低的按钮变体——无背景、无边框,仅保留链接色文字。它的设计意图是**暗示导航而非操作**,适合放在内容流中作为跳转入口。在 Web 环境中,Ant Design 通过 `href` 属性支持真实的超链接导航。
|
||
|
||
### AtomUI 的扩展设计
|
||
|
||
AtomUI 将链接按钮提取为独立的 `HyperLinkButton` 控件,主要基于以下考量:
|
||
|
||
1. **桌面端导航需求**:桌面应用同样有「打开浏览器」的导航需求,需要 `NavigateUri` + `Launcher.LaunchUriAsync` 集成
|
||
2. **已访问状态**:Web 浏览器天然支持 `:visited` 伪类,桌面端需要显式实现 `IsVisited` 属性和对应的伪类
|
||
3. **关注点分离**:链接按钮的颜色体系(`ColorLink` 系列)和交互模式(导航而非操作)与普通 Button 有本质区别,独立为专用控件更清晰
|
||
|
||
| 扩展能力 | 实现方式 | 设计动机 |
|
||
|---|---|---|
|
||
| **真实导航** | `NavigateUri` 属性 + `Launcher.LaunchUriAsync` | 桌面端的超链接跳转,对齐 Ant Design 的 `href` |
|
||
| **已访问状态** | `IsVisited` 属性 + `:visited` 伪类 | 跟踪链接是否已被点击过,可进行视觉区分 |
|
||
| **三种尺寸** | `ISizeTypeAware` 接口 + `SizeType` 共享属性 | 与全局尺寸体系一致 |
|
||
| **危险样式** | `IsDanger` 属性 + `:danger` 伪类 | 红色链接,适用于危险操作(删除、移除等) |
|
||
| **幽灵模式** | `IsGhost` 属性 | 背景透明,适用于有色背景场景 |
|
||
| **加载状态** | `IsLoading` 属性 + `LoadingOutlined` 图标 | 旋转图标 + 降低不透明度,用于异步操作等待 |
|
||
| **图标支持** | `Icon` 属性(`PathIcon` 类型) | 在链接文本前显示图标 |
|
||
| **过渡动画** | `IMotionAwareControl` + `Transitions` | 前景色、背景色平滑过渡 |
|
||
| **Design Token** | 复用 `ButtonToken` 作用域 | 间距和字体 Token 与 Button 共享,颜色使用链接色系 |
|
||
|
||
### 导航机制
|
||
|
||
当设置 `NavigateUri` 属性后,点击按钮触发以下流程:
|
||
|
||
1. 调用 `OnClick()` 基类方法(触发 `Click` 事件和 `Command` 执行)
|
||
2. 检查 `NavigateUri` 是否不为 `null`
|
||
3. 通过 `TopLevel.GetTopLevel(this).Launcher.LaunchUriAsync(uri)` 异步打开系统默认浏览器
|
||
4. 导航成功后自动将 `IsVisited` 设为 `true`,激活 `:visited` 伪类
|
||
|
||
> **注意**:即使设置了 `NavigateUri`,`Click` 事件和 `Command` 仍然会正常触发。`NavigateUri` 是额外的导航行为,不会替代 Button 的基本点击机制。
|
||
|
||
---
|
||
|
||
## 功能详解
|
||
|
||
### 链接导航(NavigateUri)
|
||
|
||
通过 `NavigateUri` 属性设置目标 URI:
|
||
|
||
- 支持任意 URI 格式(`https://`、`mailto:`、`file://` 等)
|
||
- 点击后异步调用系统 Launcher 打开默认程序
|
||
- 导航成功后 `IsVisited` 自动设为 `true`
|
||
- 导航失败(如无效 URI)时 `IsVisited` 保持不变
|
||
|
||
### 已访问状态(IsVisited)
|
||
|
||
- 导航成功后自动设置
|
||
- 可通过 `:visited` 伪类在样式中进行视觉区分
|
||
- 可手动设置 `IsVisited = true/false` 来控制状态
|
||
- 可通过数据绑定持久化已访问记录
|
||
|
||
### 危险样式(IsDanger)
|
||
|
||
通过 `IsDanger` 属性启用红色链接样式:
|
||
- 正常态使用 `ColorError`
|
||
- 悬浮态使用 `ColorErrorHover`
|
||
- 按下态使用 `ColorErrorActive`
|
||
- 图标颜色同步切换
|
||
|
||
### 加载状态(IsLoading)
|
||
|
||
当 `IsLoading = true` 时:
|
||
1. `:loading` 伪类被激活
|
||
2. 原图标隐藏,替换为旋转的 `LoadingOutlined` 图标
|
||
3. 整体不透明度降至 `SharedToken.OpacityLoading`
|
||
|
||
### 过渡动画
|
||
|
||
HyperLinkButton 在加载时配置以下过渡动画:
|
||
- `Background`:背景色渐变过渡
|
||
- `Foreground`:前景色(文本色)渐变过渡
|
||
|
||
通过 `IsMotionEnabled` 属性可控制是否启用过渡动画。
|
||
|
||
---
|
||
|
||
## 与 Ant Design 规范的对齐程度
|
||
|
||
| 特性 | Ant Design (React) | AtomUI (Avalonia) | 对齐情况 |
|
||
|---|---|---|---|
|
||
| 链接样式 | ✅ `Button type="link"` | ✅ `HyperLinkButton` | ✅ 完全对齐 |
|
||
| 三种尺寸 `size` | ✅ `large / medium / small` | ✅ `SizeType` 属性 | ✅ 完全对齐 |
|
||
| 图标 `icon` | ✅ ReactNode | ✅ `Icon` 属性(`PathIcon`) | ✅ 完全对齐 |
|
||
| 危险样式 `danger` | ✅ 布尔属性 | ✅ `IsDanger` 属性 | ✅ 完全对齐 |
|
||
| 加载中 `loading` | ✅ 布尔属性 | ✅ `IsLoading` 属性 | ✅ 完全对齐 |
|
||
| 禁用 `disabled` | ✅ 布尔属性 | ✅ `IsEnabled` 属性 | ✅ 完全对齐 |
|
||
| 真实导航 `href` | ✅ `href` + `target` | ✅ `NavigateUri` | ✅ 完全对齐(桌面端通过系统 Launcher) |
|
||
| 已访问状态 | — (浏览器原生) | ✅ `IsVisited` + `:visited` 伪类 | ✅ AtomUI 扩展 |
|
||
| 幽灵模式 `ghost` | ✅ 布尔属性 | ✅ `IsGhost` 属性 | ✅ 完全对齐 |
|
||
|
||
---
|
||
|
||
## 继承关系
|
||
|
||
```
|
||
Avalonia.Controls.Primitives.TemplatedControl
|
||
└── Avalonia.Controls.ContentControl
|
||
└── Avalonia.Controls.Button (ICommandSource, IClickableControl)
|
||
└── AtomUI.Controls.Commons.AbstractHyperLinkButton (ISizeTypeAware, IMotionAwareControl)
|
||
└── AtomUI.Desktop.Controls.HyperLinkButton
|
||
```
|
||
|
||
### 跨平台架构
|
||
|
||
HyperLinkButton 遵循 AtomUI 的两层控件模型:
|
||
|
||
| 层级 | 类 | 职责 |
|
||
|---|---|---|
|
||
| **基类**(`AtomUI.Controls`) | `AbstractHyperLinkButton` | 设备无关的共享行为:属性定义、导航逻辑、伪类管理、过渡动画配置 |
|
||
| **桌面端**(`AtomUI.Desktop.Controls`) | `HyperLinkButton` | 注册 `ButtonToken` 作用域,桌面端特定的主题和样式 |
|
||
|
||
**各层级职责划分:**
|
||
|
||
| 层级 | 提供的能力 |
|
||
|---|---|
|
||
| `Avalonia.Controls.Button` | 指针交互 → Click 事件、`ICommand` 绑定、`IsPressed` 状态、`HotKey` 快捷键、`Flyout` 弹出 |
|
||
| `AbstractHyperLinkButton` | `NavigateUri` + `Launcher` 导航、`IsVisited` 已访问追踪、`SizeType` 尺寸、`IsDanger` / `IsGhost` / `IsLoading` 状态、`Icon` 图标、`IsMotionEnabled` 动画开关、伪类管理 |
|
||
| `HyperLinkButton` | `ButtonToken` 作用域注册(复用 Button 的间距/字体 Token) |
|
||
|
||
**实现的共享接口:**
|
||
|
||
| 接口 | 定义位置 | 作用 |
|
||
|---|---|---|
|
||
| `ISizeTypeAware` | `AtomUI.Controls.Shared` | 支持 `SizeType`(Small / Middle / Large)三种尺寸切换 |
|
||
| `IMotionAwareControl` | `AtomUI.Controls.Shared` | 支持动画开关,控制过渡动画的启用/禁用 |
|
||
|
||
---
|
||
|
||
## 源码位置
|
||
|
||
| 层级 | 文件路径 | 说明 |
|
||
|---|---|---|
|
||
| 基类 | `src/AtomUI.Controls/Buttons/AbstractHyperLinkButton.cs` | 设备无关基类(行为、属性、导航逻辑) |
|
||
| 伪类常量 | `src/AtomUI.Controls/Buttons/ButtonPseudoClass.cs` | 共享伪类定义(与 Button 共用) |
|
||
| 控件类 | `src/AtomUI.Desktop.Controls/Buttons/HyperLinkButton.cs` | 桌面端具体实现 |
|
||
| 主题模板 | `src/AtomUI.Desktop.Controls/Buttons/Themes/HyperLinkButtonTheme.axaml` | ControlTheme AXAML |
|
||
| 模板常量 | `src/AtomUI.Desktop.Controls/Buttons/Themes/ButtonThemeConstants.cs` | 模板部件名称常量(与 Button 共用) |
|
||
| Gallery 使用 | `controlgallery/AtomUIGallery/ShowCases/Views/General/AboutUsPage.axaml` | 实际使用示例 |
|
||
|
||
---
|
||
|
||
## 模板结构
|
||
|
||
HyperLinkButton 采用简洁的单层 Border + StackPanel 布局:
|
||
|
||
```
|
||
Border#Frame ← 主框架(承载 Padding、CornerRadius)
|
||
└── StackPanel#PART_MainInfoLayout ← 内容布局容器(水平排列、居中对齐)
|
||
├── LoadingOutlined#PART_LoadingIcon ← 加载旋转图标(默认隐藏,:loading 时显示)
|
||
├── IconPresenter#PART_ButtonIcon ← 按钮图标展示器(默认显示,:loading 时隐藏)
|
||
└── ContentPresenter#PART_ContentPresenter ← 文本内容
|
||
```
|
||
|
||
**与 Button 模板的区别:**
|
||
- **无波纹层**:HyperLinkButton 不使用 `WaveSpiritDecorator`(链接按钮不需要点击波纹)
|
||
- **无阴影层**:链接按钮无阴影效果
|
||
- **无焦点指示器层**:使用更简洁的焦点样式
|
||
- **背景始终透明**:正常态和幽灵态背景均为透明
|
||
|
||
### 模板部件常量
|
||
|
||
HyperLinkButton 复用 `ButtonThemeConstants` 中的常量:
|
||
|
||
| 常量名 | 值 | 说明 |
|
||
|---|---|---|
|
||
| `ButtonThemeConstants.MainInfoLayoutPart` | `"PART_MainInfoLayout"` | 内容布局面板 |
|
||
| `ButtonThemeConstants.LoadingIconPart` | `"PART_LoadingIcon"` | 加载旋转图标 |
|
||
| `ButtonThemeConstants.ButtonIconPart` | `"PART_ButtonIcon"` | 按钮图标展示器 |
|
||
| `ButtonThemeConstants.ContentPresenterPart` | `"PART_ContentPresenter"` | 内容展示器 |
|