-
-
Notifications
You must be signed in to change notification settings - Fork 40
Features
Zephyr 提供了一套完整的代理管理功能集,涵盖实时流量监控、智能节点选择、高级安全防护与跨平台适配。本文档对每一项核心功能进行详细的技术说明,并通过 Mermaid 图表直观展示数据流与处理逻辑。
Zephyr 内置了一套完全自研的实时流量可视化引擎,零第三方图表库依赖,基于原生 Canvas 2D API 从零构建双色面积图,提供流畅、低开销的实时网络流量展示。
流量数据从 Mihomo 内核出发,经过 HTTP Streaming 传输、逐行解析、滑动窗口缓冲,最终由 Canvas 2D 渲染引擎绘制为贝塞尔曲线面积图。以下时序图展示了完整的数据流转过程:
%%{init: {'themeVariables': {'fontSize': '10px', 'actorTextColor': '#ccc', 'signalColor': '#666', 'labelTextColor': '#999', 'labelBoxBkgColor': '#333', 'labelBoxBorderColor': '#555', 'lineColor': '#666', 'actorBkg': '#333', 'actorBorder': '#555', 'actorTextColor': '#ccc', 'signalTextColor': '#ccc', 'noteBkgColor': '#333', 'noteTextColor': '#ccc', 'noteBorderColor': '#555'}}}%%
sequenceDiagram
participant MC as Mihomo Core
participant HS as HTTP Stream<br/>(/traffic)
participant WS as websocket.js<br/>(ReadableStream)
participant SW as 滑动窗口<br/>(60 数据点)
participant TC as modules/traffic-chart.js<br/>(渲染引擎)
participant CV as Canvas 2D<br/>(贝塞尔面积图)
MC->>HS: GET /traffic (chunked JSON)
activate HS
loop 持续推送 (每秒约 1 次)
HS-->>WS: {"up": 1024, "down": 51200}
WS->>WS: TextDecoder 解码
WS->>WS: 按换行符分割
WS->>SW: JSON.parse(data)
SW->>SW: pushToSlidingWindow()
SW->>SW: 移除最旧数据点 (窗口 > 60)
SW->>TC: 通知数据更新
TC->>TC: requestAnimationFrame 调度
TC->>CV: 清除画布
TC->>CV: 绘制下载面积图 (紫色)
TC->>CV: 绘制上传面积图 (蓝色)
CV-->>TC: 渲染完成
end
Note over HS,WS: 连接断开时触发指数退避重连
WS->>HS: 自动重连 (delay = min(1s * 2^attempt, 30s))
流量数据通过 HTTP Streaming(非 WebSocket)从 Mihomo 内核的 /traffic 端点获取。与 WebSocket 方案相比,HTTP Streaming 具备更低的协议开销和更简洁的断线重连逻辑。
// 伪代码:HTTP Streaming 数据采集流程
const response = await fetch("http://127.0.0.1:9090/traffic");
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const text = decoder.decode(value, { stream: true });
const lines = text.split("\n").filter(Boolean);
for (const line of lines) {
const data = JSON.parse(line);
// data.up -> 上传速度 (bytes/s)
// data.down -> 下载速度 (bytes/s)
pushToSlidingWindow(data);
}
}| 特性 | 说明 |
|---|---|
| 双通道面积图 | 紫色表示下载流量,蓝色表示上传流量,半透明填充叠加 |
| 贝塞尔曲线平滑 | 数据点之间使用贝塞尔曲线插值,避免折线的视觉生硬感 |
| 60 点滑动窗口 | 保留最近 60 个采样点,旧数据自动移出视口 |
requestAnimationFrame 节流 |
渲染频率与显示器刷新率同步,避免无效重绘 |
| DPR 适配 | Canvas 物理像素按 devicePixelRatio 缩放,高分屏下保持锐利 |
// 伪代码:DPR 适配与 Canvas 初始化
const canvas = document.getElementById("traffic-chart");
const ctx = canvas.getContext("2d");
const rect = canvas.getBoundingClientRect();
const dpr = window.devicePixelRatio || 1;
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
ctx.scale(dpr, dpr);
// 后续绘制使用 CSS 像素坐标,Canvas 自动映射到物理像素自动根据数值大小切换显示单位,保持界面简洁:
| 速度范围 | 显示格式 | 示例 |
|---|---|---|
| < 1024 B/s | XXX B/s |
512 B/s |
| < 1024 KB/s | X.XX KB/s |
86.42 KB/s |
| >= 1024 KB/s | X.XX MB/s |
3.14 MB/s |
以下决策树展示了速度值从原始字节到格式化显示的完整转换逻辑:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[输入:速度值<br/>bytes/s] --> B{值 < 1024?}
B -->|是| C[显示为 B/s<br/>格式:XXX B/s]
B -->|否| D[值除以 1024<br/>转为 KB/s]
D --> E{值 < 1024?}
E -->|是| F[显示为 KB/s<br/>保留 2 位小数<br/>格式:X.XX KB/s]
E -->|否| G[值再除以 1024<br/>转为 MB/s]
G --> H[显示为 MB/s<br/>保留 2 位小数<br/>格式:X.XX MB/s]
style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
style B fill:#3B82F6,stroke:#2563EB,color:#fff
style E fill:#3B82F6,stroke:#2563EB,color:#fff
style C fill:#10B981,stroke:#059669,color:#fff
style F fill:#10B981,stroke:#059669,color:#fff
style H fill:#10B981,stroke:#059669,color:#fff
采用指数退避重连策略,在连接中断时自动恢复,同时避免对内核造成请求风暴:
| 参数 | 值 | 说明 |
|---|---|---|
| 初始延迟 | 1 秒 | 首次重连等待时间 |
| 最大延迟 | 30 秒 | 退避上限 |
| 最大重试次数 | 15 次 | 超过后停止重连并提示用户 |
| 解析错误阈值 | 连续 10 次 | 触发强制重连(应对流格式异常) |
退避公式:delay = min(initial * 2^attempt, max_delay)
以下流程图展示了 HTTP Streaming 连接建立、数据接收循环及断线重连的完整处理逻辑:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[构造 Streaming URL<br/>http://127.0.0.1:9090/traffic] --> B[调用 fetch 发起请求]
B --> C[获取 Response.body<br/>ReadableStream]
C --> D[创建 TextDecoder]
D --> E[进入数据读取循环]
E --> F[reader.read 读取 chunk]
F --> G{stream done?}
G -->|是| H[触发指数退避重连<br/>delay = min 1s * 2^attempt, 30s]
H --> I{重试次数 > 15?}
I -->|是| J[停止重连<br/>提示用户连接中断]
I -->|否| B
G -->|否| K[TextDecoder 解码 chunk]
K --> L[按换行符分割文本]
L --> M[逐行 JSON.parse]
M --> N{解析成功?}
N -->|否| O[错误计数 +1]
O --> P{连续错误 > 10?}
P -->|是| Q[强制重连<br/>重置错误计数]
Q --> B
P -->|否| E
N -->|是| R[pushToSlidingWindow]
R --> S[移除最旧数据点<br/>窗口保持 60 个]
S --> T[通知渲染引擎更新]
T --> U[requestAnimationFrame 调度绘制]
U --> E
style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
style B fill:#3B82F6,stroke:#2563EB,color:#fff
style E fill:#3B82F6,stroke:#2563EB,color:#fff
style H fill:#F59E0B,stroke:#D97706,color:#fff
style Q fill:#EF4444,stroke:#DC2626,color:#fff
style J fill:#EF4444,stroke:#DC2626,color:#fff
style R fill:#10B981,stroke:#059669,color:#fff
style T fill:#10B981,stroke:#059669,color:#fff
Zephyr 提供了直观、高效的节点选择体验,结合响应式布局、延迟可视化与 3D 交互效果,让用户在海量节点中快速定位最优选择。
从加载节点列表到最终切换代理,整个交互流程涉及前端 UI 渲染、Mihomo API 调用和界面状态同步。以下流程图展示了完整的节点选择链路:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[加载节点列表] --> B[GET /proxies API]
B --> C[解析代理组与节点数据]
C --> D[渲染节点卡片网格]
D --> E{用户操作}
E -->|点击节点卡片| F[调用 switchProxy API]
E -->|鼠标悬停 300ms| G[展开节点列表]
E -->|滚轮滚动| H[切换当前选中节点]
F --> I[PUT /proxies/group_name]
I --> J[Mihomo 内核切换代理]
J --> K[返回切换结果]
K --> L[更新 UI 状态]
L --> M[刷新延迟标签颜色编码]
M --> N[同步托盘菜单状态]
G --> O[显示完整节点列表]
O --> P[展示延迟标签与节点名称]
H --> Q[更新首页节点选择器显示]
Q --> N
style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
style F fill:#3B82F6,stroke:#2563EB,color:#fff
style J fill:#10B981,stroke:#059669,color:#fff
style N fill:#F59E0B,stroke:#D97706,color:#fff
节点列表采用 1-4 列自适应网格,根据窗口宽度与屏幕分辨率动态调整列数:
| 窗口宽度 | 列数 | 适用场景 |
|---|---|---|
| < 640px | 1 列 | 窄窗口 / 小屏显示器 |
| 640px - 1024px | 2 列 | 标准窗口 |
| 1024px - 1536px | 3 列 | 大屏显示器 |
| > 1536px | 4 列 | 超宽屏 / 4K 显示器 |
节点卡片上的延迟标签通过颜色直观反映连接质量:
| 延迟范围 | 颜色 | 含义 |
|---|---|---|
| < 200ms | 绿色 | 体验优良,适合实时应用 |
| 200ms - 500ms | 黄色 | 可用,可能有轻微延迟 |
| > 500ms | 红色 | 延迟较高,不适合实时应用 |
| 测试中 | 灰色 + 加载动画 | 正在测量延迟 |
| 不可达 | 红色 + 超时标记 | 节点无法连接 |
支持三种排序方式,通过节点面板顶部的排序按钮一键循环切换:
- 默认排序 -- 按 Mihomo 内核返回的原始顺序
- 按延迟排序 -- 延迟从低到高,不可达节点排末尾
- 按名称排序 -- 按节点名称的字典序排列
节点卡片在鼠标悬停时呈现 3D 透视旋转效果,通过 CSS perspective + rotateX/Y 实现,requestAnimationFrame 节流确保流畅:
/* 伪代码:3D 悬浮效果核心样式 */
.node-card {
perspective: 1000px;
transform-style: preserve-3d;
transition: transform 0.15s ease-out;
}// 伪代码:鼠标跟踪 3D 旋转
card.addEventListener("mousemove", (e) => {
requestAnimationFrame(() => {
const rect = card.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
card.style.transform =
`rotateY(${x * 15}deg) rotateX(${-y * 15}deg) scale(1.02)`;
});
});以下时序图展示了节点轮盘(Roulette)选择的完整交互流程,从用户点击代理胶囊到最终同步托盘菜单的全链路:
%%{init: {'themeVariables': {'fontSize': '10px', 'actorTextColor': '#ccc', 'signalColor': '#666', 'labelTextColor': '#999', 'labelBoxBkgColor': '#333', 'labelBoxBorderColor': '#555', 'lineColor': '#666', 'actorBkg': '#333', 'actorBorder': '#555', 'actorTextColor': '#ccc', 'signalTextColor': '#ccc', 'noteBkgColor': '#333', 'noteTextColor': '#ccc', 'noteBorderColor': '#555'}}}%%
sequenceDiagram
participant U as 用户
participant UI as 前端 UI
participant RO as 轮盘组件<br/>(Roulette)
participant API as Mihomo API
participant TM as 托盘菜单
U->>UI: 点击代理胶囊
activate UI
UI->>RO: 渲染轮盘遮罩层
activate RO
RO->>API: GET /proxies/{group_name}
activate API
API-->>RO: 返回节点列表
deactivate API
RO->>RO: 渲染可滚动节点列表
RO-->>U: 展示轮盘界面
U->>RO: 点击目标节点
activate RO
RO->>UI: 调用 switchProxy(group, node)
activate UI
UI->>API: PUT /proxies/{group_name}
activate API
API->>API: Mihomo 切换代理节点
API-->>UI: 返回切换结果
deactivate API
UI-->>RO: 切换成功
deactivate UI
RO->>RO: 更新当前激活节点显示
RO->>RO: 关闭轮盘遮罩层
RO-->>U: 显示切换成功反馈
deactivate RO
UI->>TM: 同步托盘菜单节点状态
deactivate UI
-
滚动动画节流:所有滚动相关动画均通过
requestAnimationFrame节流
Zephyr 提供功能完善的订阅管理系统,支持多种订阅格式、客户端伪装与灵活的下载策略。订阅下载采用三级回退策略,确保在各种网络环境下都能成功获取订阅。
从 URL 验证到最终写入文件,订阅下载涵盖 SSRF 防护、多策略回退、内容解析、安全清理和加密存储等多个环节。以下流程图展示了完整的处理链路:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[用户输入订阅 URL] --> B[SSRF 防护验证]
B --> C{URL 合法?}
C -->|否| ERR1[拒绝请求]
C -->|是| D[第一优先级:直连下载]
D --> E{下载成功?}
E -->|是| K
E -->|否| F[第二优先级:Mihomo 代理下载]
F --> G{下载成功?}
G -->|是| K
G -->|否| H[第三优先级:系统代理下载]
H --> I{下载成功?}
I -->|是| K
I -->|否| ERR2[返回下载失败错误]
K[Base64 检测] --> L{内容为 Base64?}
L -->|是| M[Base64 解码]
L -->|否| N[直接使用原始内容]
M --> O
N --> O[YAML 解析]
O --> P{解析成功?}
P -->|否| ERR3[返回解析错误]
P -->|是| Q[清除危险键]
Q --> R[移除 script / script-path]
Q --> S[移除 provider.path]
R --> T[加密存储元数据]
S --> T
T --> U[get_machine_key 获取密钥]
U --> V[obfuscate_string AES-256-GCM 加密 URL]
V --> W[写入配置文件]
W --> X[write_file_secure 设置 0o600 权限]
X --> Y[返回配置信息]
style B fill:#EF4444,stroke:#DC2626,color:#fff
style D fill:#3B82F6,stroke:#2563EB,color:#fff
style F fill:#8B5CF6,stroke:#7C3AED,color:#fff
style H fill:#F59E0B,stroke:#D97706,color:#fff
style Q fill:#EF4444,stroke:#DC2626,color:#fff
style T fill:#10B981,stroke:#059669,color:#fff
style ERR1 fill:#991B1B,color:#fff
style ERR2 fill:#991B1B,color:#fff
style ERR3 fill:#991B1B,color:#fff
| 格式 | 处理方式 | 说明 |
|---|---|---|
| Clash YAML | 直接解析 | 标准 Mihomo / Clash 配置格式 |
| Base64 编码 | 自动检测并解码 | 兼容 V2Ray / Shadowrocket 等分享链接格式 |
自动检测逻辑:当响应内容不包含 YAML 关键标识(proxies: 和 port:)时,尝试 Base64 解码。解码后还会验证结果是否为包含 proxies: 的有效 YAML。
支持自定义 User-Agent 请求头,内置多个流行客户端的版本信息查询:
| 客户端 | 说明 |
|---|---|
| Clash Verge | 模拟 Clash Verge 客户端请求 |
| Mihomo Party | 模拟 Mihomo Party 客户端请求 |
| FlClash | 模拟 FlClash 客户端请求 |
| Shadowrocket | 模拟 Shadowrocket 客户端请求 |
| 自定义 | 用户可输入任意 UA 字符串 |
自动解析订阅响应中的 subscription-userinfo 头部字段,展示流量使用进度:
subscription-userinfo: upload=1073741824; download=3221225472; total=107374182400; expire=1735689600
| 字段 | 说明 |
|---|---|
upload |
已用上传流量(字节) |
download |
已用下载流量(字节) |
total |
总流量额度(字节) |
expire |
到期时间(Unix 时间戳) |
- 批量更新:一键更新所有已添加的订阅
-
拖拽导入:支持将
.yaml/.yml文件直接拖拽到订阅页面导入
Zephyr 支持通过 TUN 虚拟网卡实现系统级透明代理,接管所有网络流量,无需手动配置系统代理。macOS 平台由于权限模型限制,需要通过 osascript 进行提权操作。
以下流程图展示了 macOS 平台上 TUN 模式从检查状态到最终激活的完整提权与启动过程:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[用户请求启用 TUN] --> B[检查 CORE_STARTING 状态]
B --> C{内核正在启动?}
C -->|是| ERR1[返回:内核启动中,请稍后]
C -->|否| D[检查 TUN_MODE_ACTIVE 状态]
D --> E{TUN 已激活?}
E -->|是| F[执行关闭 TUN 流程]
E -->|否| G[停止当前 Mihomo 进程]
G --> K[构造 osascript 提权命令]
K --> L[弹出系统授权对话框]
L --> M{用户确认授权?}
M -->|取消| N[返回:用户取消]
M -->|确认| O[以 root 权限启动 Mihomo]
O --> P[轮询等待 root 进程启动]
P --> Q{检测到 root 进程?}
Q -->|否 - 超过 30s| R[返回:提权超时]
Q -->|是| S[HTTP 健康检查 API 端口]
S --> T{端口可达?}
T -->|否 - 重试 10 次| U[等待 300ms 后重试]
U --> S
T -->|是| V[设置 TUN_MODE_ACTIVE = true]
V --> W[更新托盘图标为红色]
W --> X[通知前端 TUN 状态已更新]
X --> Y[TUN 模式激活完成]
style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
style K fill:#F59E0B,stroke:#D97706,color:#fff
style O fill:#EF4444,stroke:#DC2626,color:#fff
style V fill:#10B981,stroke:#059669,color:#fff
style Y fill:#10B981,stroke:#059669,color:#fff
style ERR1 fill:#991B1B,color:#fff
style ERR2 fill:#991B1B,color:#fff
| 平台 | 权限获取方式 | 说明 |
|---|---|---|
| macOS |
osascript 提权 |
通过 AppleScript 弹出授权对话框,用户确认后以 root 身份启动 |
| Windows | 标准权限 | 直接调用系统 API 创建 TUN 接口 |
| Linux | 标准权限 | 通过 CAP_NET_ADMIN 或 root 权限创建 TUN 接口 |
系统托盘图标实时反映当前网络状态:
| 状态 | 图标颜色 | 说明 |
|---|---|---|
| TUN 激活 | 红色 | 系统级透明代理已启用 |
| 系统代理 | 黄色 | 仅系统代理模式运行 |
| 直连 / 未启用 | 默认色 | 无代理或直连模式 |
Zephyr 实现了一套多层纵深防御体系,覆盖网络请求安全、供应链安全、数据加密存储、文件系统防护等多个维度。其中 SSRF(服务端请求伪造)防护是网络请求安全的核心组件。
针对 SSRF 攻击,Zephyr 实现了从 URL 解析到重定向跟踪的完整防护链。每次网络请求(包括重定向跳转)都经过严格的校验,最多跟踪 5 次重定向。以下流程图展示了完整的 SSRF 防护决策链:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[解析目标 URL] --> B{协议为<br/>HTTP/HTTPS?}
B -->|否| ERR1[拒绝:<br/>仅允许 HTTP 和 HTTPS]
B -->|是| C[提取主机名]
C --> D{主机名为<br/>私有地址?}
D -->|是| ERR2[拒绝:<br/>localhost / .local / .test 等]
D -->|否| E[DNS 预解析]
E --> F{解析结果为<br/>私有 IP?}
F -->|是| ERR3[拒绝:<br/>RFC 1918 / 环回 / 链路本地]
F -->|否| G[DNS Pinning<br/>固定解析结果]
G --> H[发起 HTTP 请求]
H --> I{收到重定向?}
I -->|否| J[返回响应内容]
I -->|是| K{重定向次数<br/>≤ 5?}
K -->|否| ERR4[拒绝:<br/>重定向次数超过上限]
K -->|是| L[验证重定向目标 URL]
L --> M{重定向协议<br/>合法?}
M -->|否| ERR5[拒绝:<br/>非法重定向协议]
M -->|是| N{重定向主机名<br/>为私有地址?}
N -->|是| ERR6[拒绝:<br/>重定向到私有主机]
N -->|否| O[DNS 预解析重定向目标]
O --> P{重定向 IP<br/>为私有?}
P -->|是| ERR7[拒绝:<br/>重定向到私有 IP]
P -->|否| H
style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
style E fill:#F59E0B,stroke:#D97706,color:#fff
style G fill:#3B82F6,stroke:#2563EB,color:#fff
style H fill:#10B981,stroke:#059669,color:#fff
style J fill:#10B981,stroke:#059669,color:#fff
style ERR1 fill:#991B1B,color:#fff
style ERR2 fill:#991B1B,color:#fff
style ERR3 fill:#991B1B,color:#fff
style ERR4 fill:#991B1B,color:#fff
style ERR5 fill:#991B1B,color:#fff
style ERR6 fill:#991B1B,color:#fff
style ERR7 fill:#991B1B,color:#fff
| 防护层 | 机制 | 说明 |
|---|---|---|
| DNS 解析验证 | 预解析 + IP 校验 | 在发起请求前先解析域名,验证目标 IP |
| 私有 IP 拦截 | CIDR 匹配 | 拦截指向 RFC 1918 / 环回 / 链路本地地址的请求 |
| 重定向链校验 | 最多 5 次跟踪 | 跟踪 HTTP 重定向链,每跳均执行 IP 校验 |
| 协议白名单 | HTTP/HTTPS only | 仅允许 http 和 https 协议 |
| DNS Pinning |
reqwest::resolve 固定 IP |
防止 DNS Rebinding(TOCTOU)攻击 |
IPv4 检测范围:
| 范围 | CIDR | 说明 |
|---|---|---|
| 私有地址 | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 | RFC 1918 私有网络 |
| 环回地址 | 127.0.0.0/8 | 本机回环 |
| 链路本地 | 169.254.0.0/16 | 自动分配地址 |
| 广播地址 | 255.255.255.255 | 网络广播 |
| 未指定 | 0.0.0.0 | 通配绑定地址 |
| 文档用途地址 | 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 | RFC 5737 文档与示例用途(TEST-NET-1/2/3) |
IPv6 检测范围:
| 范围 | CIDR | 说明 |
|---|---|---|
| 环回地址 | ::1 | 本机回环 |
| 未指定 | :: | 通配绑定 |
| 唯一本地地址 | fc00::/7 | IPv6 私有网络(ULA) |
| 链路本地 | fe80::/10 | IPv6 链路本地 |
订阅下载环节实施多层校验,防止恶意配置注入:
| 校验项 | 策略 | 说明 |
|---|---|---|
| SHA256 校验 | 哈希比对 | 验证下载文件的完整性 |
| 可信域名白名单 | 域名匹配 | 仅允许从已知可信域名下载内核更新(updater.rs TRUSTED_HOSTS),订阅下载使用 IP 级别 SSRF 防护 |
| 大小限制 | 10MB | 超过限制的文件直接丢弃 |
| 路径遍历防护 | 5 轮 URL 解码 + 文件名净化 | 防止目录穿越攻击 |
敏感数据(如订阅链接、认证信息)使用 AES-256-GCM 加密存储:
| 参数 | 值 | 说明 |
|---|---|---|
| 加密算法 | AES-256-GCM | 认证加密,同时保证机密性与完整性 |
| 密钥派生 | PBKDF2-HMAC-SHA256 | 从用户密码派生加密密钥 |
| 迭代次数 | 100,000 次 | 有效抵御暴力破解 |
| 密钥绑定 | 机器标识 | 密钥与当前设备绑定,防止配置文件迁移泄露 |
| 平台 | 权限设置 | 说明 |
|---|---|---|
| Unix (macOS/Linux) | 0600 |
仅文件所有者可读写 |
| Windows | DACL | 通过 Windows 自由访问控制列表限制访问 |
为防止命令被滥用或误操作,关键命令均设有频率限制:
| 命令 | 限流间隔 | 说明 |
|---|---|---|
start_core |
3 秒 | 防止内核频繁启停 |
download_sub |
5 秒 | 防止订阅下载过于频繁 |
exempt_uwp_apps |
5 分钟 | UWP 环回免除操作较重,需较长冷却 |
加载外部配置时,自动清除以下危险字段,防止代码注入:
-
script/script-path-- 可能导致任意代码执行 -
provider中的path字段 -- 可能导致路径遍历
Zephyr 的所有配置修改均支持热重载,无需重启 Mihomo 内核即可即时生效。配置更新通过 Tauri IPC 从前端传递到 Rust 后端,经过安全键保护、YAML 递归合并后写入文件,并通过 PATCH API 通知内核重新加载。
以下时序图展示了从用户在前端修改配置到最终生效的完整交互过程,涵盖 Tauri IPC 调用、安全键保护机制和 Mihomo API 通知:
%%{init: {'themeVariables': {'fontSize': '10px', 'actorTextColor': '#ccc', 'signalColor': '#666', 'labelTextColor': '#999', 'labelBoxBkgColor': '#333', 'labelBoxBorderColor': '#555', 'lineColor': '#666', 'actorBkg': '#333', 'actorBorder': '#555', 'actorTextColor': '#ccc', 'signalTextColor': '#ccc', 'noteBkgColor': '#333', 'noteTextColor': '#ccc', 'noteBorderColor': '#555'}}}%%
sequenceDiagram
participant UI as 前端 UI
participant IPC as Tauri IPC
participant CM as config_manager<br/>(Rust 后端)
participant FS as 文件系统
participant API as Mihomo API<br/>(PATCH /configs)
UI->>IPC: invoke("update_config", {patch})
IPC->>CM: update_config(patch) 调用
Note over CM: Step 1: JSON 转 YAML
CM->>CM: serde_json::Value<br/>转为 serde_yaml::Value
Note over CM: Step 2: 保存安全键
CM->>CM: 备份 external-controller
CM->>CM: 备份 secret
Note over CM: Step 3: 递归合并
CM->>CM: merge_yaml(existing, new, depth=0)
Note over CM: 深度限制 50 层<br/>null 值表示删除键
Note over CM: Step 4: 恢复安全键
CM->>CM: 写回 external-controller
CM->>CM: 写回 secret
Note over CM: Step 5: 写入文件
CM->>FS: 序列化为 YAML
CM->>FS: 写入 run_config.yaml
CM->>FS: 同步到订阅配置文件
Note over CM: Step 6: PATCH 热重载
CM->>API: PATCH /configs?force=true
API-->>CM: 200 OK
CM-->>IPC: Ok(())
IPC-->>UI: resolve
Note over UI: UI 刷新配置显示
merge_yaml 函数实现了深度递归合并,支持嵌套结构的精确更新和键值删除:
// 伪代码:merge_yaml 递归合并实现
fn merge_yaml(base: &mut Value, overlay: &Value, depth: u32) {
// 深度限制:防止栈溢出攻击
if depth > 50 {
return;
}
if let (Value::Mapping(base_map), Value::Mapping(overlay_map)) = (base, overlay) {
for (key, value) in overlay_map {
if value.is_null() {
// null 值表示删除该键
base_map.remove(key);
} else if let Some(existing) = base_map.get_mut(key) {
// 递归合并嵌套结构
merge_yaml(existing, value, depth + 1);
} else {
// 新增键值对
base_map.insert(key.clone(), value.clone());
}
}
} else {
// 非映射类型:直接覆盖
*base = overlay.clone();
}
}配置更新过程中,external-controller 和 secret 等安全关键字段会被临时备份并在合并后恢复,防止用户配置意外覆盖安全设置:
| 安全键 | 保护原因 | 恢复值 |
|---|---|---|
external-controller |
防止 API 绑定到非 loopback 地址 | 127.0.0.1:{port} |
secret |
防止移除 API 认证 | 随机生成的 32 个字母数字字符(Alphanumeric);如果原配置中无 secret,则不会自动添加新 secret |
PATCH /configs?force=true
Content-Type: application/json
{
"dns": {
"enable": true,
"fake-ip": true,
"nameserver": ["8.8.8.8", "1.1.1.1"]
}
}
force=true 参数确保配置被强制重载,绕过内部缓存。
Zephyr 支持对代理节点进行快速延迟测试,帮助用户评估各节点的连接质量。
通过 Mihomo RESTful API 对指定节点发起延迟探测:
GET /proxies/{proxy_name}/delay?url=http://www.gstatic.com/generate_204&timeout=5000
| 参数 | 值 | 说明 |
|---|---|---|
| 测试 URL | http://www.gstatic.com/generate_204 |
Google 204 端点,轻量可靠 |
| 超时时间 | 5000ms | 单次测试超时阈值 |
| 并发策略 | 并行请求 | 多节点同时测试,缩短总耗时 |
以下流程图展示了并发延迟测试的完整调度过程,从用户触发到结果展示的全链路:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[用户触发延迟测试] --> B[UI 进入乐观加载状态]
B --> C[显示加载动画<br/>所有节点标签置灰]
C --> D[收集待测节点列表]
D --> E[并行发起 API 调用]
E --> F1[GET /proxies/node_1/delay]
E --> F2[GET /proxies/node_2/delay]
E --> F3[GET /proxies/node_N/delay]
F1 --> G1[返回延迟结果]
F2 --> G2[返回延迟结果]
F3 --> G3[返回延迟结果]
G1 --> H[异步汇总结果]
G2 --> H
G3 --> H
H --> I[逐个更新延迟标签]
I --> J[颜色编码刷新<br/>绿色 < 200ms / 黄色 < 500ms / 红色 > 500ms]
J --> K{用户已启用排序?}
K -->|是| L[按延迟重新排序节点]
K -->|否| M[保持当前顺序]
L --> N[测试完成]
M --> N
style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
style B fill:#3B82F6,stroke:#2563EB,color:#fff
style E fill:#3B82F6,stroke:#2563EB,color:#fff
style H fill:#F59E0B,stroke:#D97706,color:#fff
style J fill:#10B981,stroke:#059669,color:#fff
style N fill:#10B981,stroke:#059669,color:#fff
延迟测试采用乐观 UI 模式 -- 用户触发测试后,界面立即进入"测试中"状态并展示加载动画,无需等待首个结果返回。这种设计消除了请求延迟带来的感知等待时间。
测试完成后,延迟数值实时更新至节点卡片,并同步触发颜色编码刷新(绿/黄/红)。
Zephyr 提供三种代理运行模式,通过三段式滑块控件一键切换,适配不同的使用场景。
| 模式 | 说明 | 适用场景 |
|---|---|---|
| Rule(规则分流) | 根据 Mihomo 配置中的规则集进行智能分流 | 日常使用,推荐模式 |
| Global(全局代理) | 所有流量均通过代理服务器转发 | 需要全部流量走代理的场景 |
| Direct(直连) | 所有流量直接发送,不经过代理 | 排查问题、访问本地服务 |
通过 Mihomo RESTful API 实时切换:
PATCH /configs
Content-Type: application/json
{
"mode": "rule"
}
三段式滑块控件带有平滑动画过渡效果,当前激活模式高亮显示。切换操作即时生效,无需重启内核。
Zephyr 基于 Tauri v2 的跨平台能力,在 Windows、macOS 和 Linux 上提供一致的功能体验,同时针对各平台特性进行深度适配。
| 平台 | 格式 | 说明 |
|---|---|---|
| Windows | NSIS (.exe) + MSI (.msi) | NSIS 为主推格式,MSI 适合企业部署 |
| macOS | DMG | Apple Silicon + Intel 通用二进制(Universal Binary) |
| Linux | DEB + AppImage + RPM | 覆盖 Debian/Ubuntu、Fedora/RHEL 及通用发行版 |
- 系统代理设置:通过注册表原子写入配置系统代理,确保写入的原子性与一致性
-
UWP 环回免除:自动为 UWP 应用添加环回免除规则,使 UWP 应用也能走代理
- 5 分钟限流防止频繁操作
- 操作前弹出用户确认对话框
以下流程图展示了 UWP 环回豁免的完整操作流程,从用户触发到规则生效的全链路:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[用户点击 UWP 环回豁免] --> B{限流检查<br/>距上次操作 > 5 分钟?}
B -->|否| C[提示操作过于频繁<br/>请稍后再试]
B -->|是| D[弹出确认对话框<br/>提示将执行 PowerShell 命令]
D --> E{用户确认?}
E -->|取消| F[操作取消]
E -->|确认| G[执行 PowerShell<br/>CheckNetIsolation 命令]
G --> H[自动豁免所有非框架 UWP 应用<br/>Get-AppxPackage | IsFramework -eq $false]
H --> K[逐个添加环回豁免规则<br/>CheckNetIsolation LoopbackExempt -a]
K --> L{所有规则添加成功?}
L -->|否| M[报告部分失败的应用]
L -->|是| N[全部豁免规则添加成功]
M --> O[刷新系统代理设置]
N --> O
O --> P[更新限流时间戳]
P --> Q[操作完成<br/>UWP 应用可正常走代理]
style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
style B fill:#F59E0B,stroke:#D97706,color:#fff
style G fill:#3B82F6,stroke:#2563EB,color:#fff
style K fill:#3B82F6,stroke:#2563EB,color:#fff
style Q fill:#10B981,stroke:#059669,color:#fff
style C fill:#6B7280,stroke:#4B5563,color:#fff
style F fill:#6B7280,stroke:#4B5563,color:#fff
- 通用二进制:单一代形同时支持 Apple Silicon (ARM64) 和 Intel (x86_64) 架构
-
TUN 提权:通过
osascript调用 AppleScript 弹出系统授权对话框
- 桌面环境检测:自动识别当前桌面环境并调用对应的代理配置工具:
| 桌面环境 | 配置工具 | 命令示例 |
|---|---|---|
| GNOME | gsettings |
gsettings set org.gnome.system.proxy mode 'manual' |
| KDE Plasma | kwriteconfig6 |
kwriteconfig6 --file kioslaverc --group "Proxy Settings" --key "ProxyType" 1 |
| XFCE | xfconf-query |
xfconf-query -c xfce4-proxy -p /mode -s manual |
- 窗口装饰:Linux 使用原生窗口装饰(有边框),Windows 和 macOS 使用无边框窗口
Zephyr 内置了可视化的自定义规则编辑器,无需手动编辑 YAML 即可管理代理规则。
- 14 种规则类型:DOMAIN、DOMAIN-SUFFIX、DOMAIN-KEYWORD、IP-CIDR、IP-CIDR6、GEOIP、GEOSITE、PROCESS-NAME、MATCH、SRC-IP-CIDR、SRC-PORT、DST-PORT、RULE-SET、USER-AGENT
- Shadowrocket 规则导入:支持从 Shadowrocket 格式的规则列表一键导入
- 可视化编辑:通过表单控件添加、编辑、删除、排序规则
-
热重载:规则修改后通过
PATCH /configs?force=true实时生效,无需重启内核
支持创建 TCP/UDP 端口转发隧道,将本地端口流量转发到指定代理节点:
| 参数 | 说明 |
|---|---|
| 协议 | TCP / UDP |
| 监听地址 | 本地绑定的 IP 地址 |
| 监听端口 | 本地监听端口号 |
| 目标地址 | 转发目标的 IP 或域名 |
| 目标端口 | 转发目标的端口号 |
| 代理节点 | 使用的代理节点名称 |
提供独立的 DNS 配置面板,支持覆盖 Mihomo 内核的默认 DNS 设置:
- Fake-IP 模式:启用后使用 Fake-IP 加速 DNS 解析
- 自定义 DNS 服务器:可配置独立的 nameserver 列表
- DNS 规则:支持按域名指定解析服务器
Zephyr 实现了一套递归渲染的动态配置引擎,用于管理 Mihomo 内核的复杂配置结构:
- 递归渲染:根据配置的嵌套结构自动生成对应的编辑控件
- 类型感知:根据值的类型(字符串、数字、布尔、数组、对象)自动选择合适的输入控件
- 实时 PATCH:配置修改通过 HTTP PATCH 请求实时推送至内核
PATCH /configs?force=true
Content-Type: application/json
{
"dns": {
"enable": true,
"fake-ip": true,
"nameserver": ["8.8.8.8", "1.1.1.1"]
}
}
基于 Tauri autostart 插件实现开机自动启动,支持 Windows、macOS 和 Linux 三平台。
Zephyr 内置了 Mihomo 内核版本检测与更新功能。当用户开启 auto_update 设置时,应用启动 5 秒后自动检查新版本;用户也可随时通过"检查更新"按钮手动触发。检测到新版本后,会弹出确认对话框,经用户确认后才执行下载与安装。
注意:不存在自动下载行为,所有更新均需用户手动确认。
以下流程图展示了完整的更新链路(ui.js:performCoreUpdate + updater.rs:update_core):
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[触发更新检查<br/>自动 5s 后 / 手动点击] --> B[调用 get_latest_version]
B --> C{网络请求成功?}
C -->|否| D[提示检查失败]
C -->|是| E[获取最新版本号]
E --> F{版本一致?}
F -->|是| G[提示已是最新版本]
F -->|否| H[弹出确认对话框<br/>showConfirmModal]
H --> I{用户确认?}
I -->|否| J[取消更新]
I -->|是| K[下载新版本二进制文件]
K --> L{下载成功?}
L -->|否| M[提示下载失败]
L -->|是| N[计算 SHA256 校验值]
N --> O{校验通过?}
O -->|否| P[删除损坏文件<br/>提示校验失败]
O -->|是| Q[解压二进制文件]
Q --> R[停止当前 Mihomo 进程]
R --> S[替换旧版二进制文件]
S --> T{替换成功?}
T -->|否| U[重试替换<br/>最多 5 次] --> V{重试成功?}
V -->|否| W[提示更新失败]
V -->|是| X
T -->|是| X[启动新版 Mihomo 内核]
X --> Y{内核健康检查通过?}
Y -->|是| Z[更新 UI 显示新版本号<br/>提示更新成功]
Y -->|否| W
style A fill:#8B5CF6,stroke:#7C3AED,color:#fff
style H fill:#F59E0B,stroke:#D97706,color:#fff
style K fill:#3B82F6,stroke:#2563EB,color:#fff
style N fill:#F59E0B,stroke:#D97706,color:#fff
style R fill:#EF4444,stroke:#DC2626,color:#fff
style X fill:#10B981,stroke:#059669,color:#fff
style Z fill:#10B981,stroke:#059669,color:#fff
style D fill:#6B7280,stroke:#4B5563,color:#fff
style G fill:#6B7280,stroke:#4B5563,color:#fff
style J fill:#6B7280,stroke:#4B5563,color:#fff
style M fill:#6B7280,stroke:#4B5563,color:#fff
style P fill:#6B7280,stroke:#4B5563,color:#fff
style W fill:#6B7280,stroke:#4B5563,color:#fff
Zephyr 内置了实时连接监控页面,提供对 Mihomo 内核所有活跃连接的细粒度可视化管理。
连接数据通过轮询 Mihomo RESTful API 的 /connections 端点获取,采用 delta 累积追踪算法精确计算每个连接的实时速率和累计流量:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'sequence': {'messageAlign': 'center'}}}%%
sequenceDiagram
participant Timer as 轮询定时器<br/>(2s 间隔)
participant API as api.js<br/>getConnections()
participant Mihomo as Mihomo Core<br/>/connections
participant Acc as 累积器<br/>(connAccumulators)
participant UI as connections.js<br/>渲染引擎
Timer->>API: 页面可见时触发
API->>Mihomo: GET /connections<br/>(Bearer secret)
Mihomo-->>API: 连接列表 JSON<br/>(download/upload 为累计值)
API-->>Acc: Phase 1: 检测死亡连接<br/>→ 归档到 closedConnections
Acc-->>Acc: Phase 2: delta 计算<br/>dlDelta = max(0, curDl - prevDl)<br/>speed = delta / deltaTime
Acc-->>UI: Phase 3: 更新统计栏<br/>+ 渲染连接列表
Note over UI: 详情面板打开时<br/>仅更新数值 span<br/>不重建 DOM
Mihomo API 返回的 download / upload 字段是连接建立以来的累计字节数,而非瞬时速率。Zephyr 通过以下算法精确追踪:
// 每次轮询时更新累积器
const dt = (now - acc.prevTs) / 1000; // 距上次轮询的秒数
const dlDelta = Math.max(0, curDl - acc.prevDl); // 正向 delta 防护
acc.dl += dlDelta; // 累积总下载量
acc.dlSpeed = dlDelta / dt; // 瞬时下载速率 (bytes/sec)
acc.prevDl = curDl; // 记录本次基线
acc.prevTs = now;-
正向 delta 防护:
Math.max(0, ...)防御 Mihomo 计数器重置或 API 异常导致的负值 -
边界保护:
dt > 0.05防止轮询过快导致速率计算失真 - 死亡连接归档:当连接从 API 响应中消失时,自动归档到关闭历史(上限 200 条)
| 功能 | 说明 |
|---|---|
| 实时轮询 | 2 秒间隔轮询,仅页面可见时触发,离开自动暂停 |
| Active / Closed 标签 | 活跃连接与关闭历史分页展示,一键切换 |
| 搜索过滤 | 支持按主机名、目标 IP、端口、规则、链路、进程名搜索 |
| 多列排序 | 7 列可排序(Host / Rule / Chains / ↓Speed / ↓Total / ↑Speed / ↑Total),三态循环(降序 → 升序 → 关闭) |
| 连接详情面板 | 点击连接行弹出详情浮层,显示完整元数据(进程、类型、来源、网络、持续时间) |
| 详情面板实时刷新 | 活跃连接的详情面板在每次轮询时仅更新数值 span,不重建 DOM |
| 批量关闭 | 一键关闭所有活跃连接 |
| 清除历史 | 一键清空关闭连接历史记录 |
| 统计栏 | 顶部 4 格统计:总连接数 / 总下载量 / 总上传量 / 活跃连接数 |
连接监控页面中所有来自 Mihomo API 的动态数据均通过 escapeHtml() 函数转义后插入 DOM,包括连接行、详情面板、搜索过滤等场景。escapeHtml() 采用 textContent → innerHTML 模式,并内置 LRU 缓存(上限 500 条)优化高频轮询场景下的性能。
Zephyr 内置了 Mihomo 内核日志实时查看页面,支持日志流式读取、搜索过滤和自动滚动。
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'sequence': {'messageAlign': 'center'}}}%%
sequenceDiagram
participant Timer as 轮询定时器<br/>(1s 间隔)
participant API as api.js<br/>readCoreLog()
participant Rust as Rust 后端<br/>read_core_log
participant File as 日志文件<br/>(mihomo-*.log)
participant UI as logs.js<br/>渲染引擎
Timer->>API: 页面可见时触发
API->>Rust: invoke("read_core_log", offset, limit)
Rust->>File: seek(offset) + read(500行)
File-->>Rust: 日志文本行
Rust-->>API: { lines, rotated, offset }
API-->>UI: Phase 1: rotated? → 重置缓冲区
UI-->>UI: Phase 2: 追加新行到环形缓冲区<br/>(上限 2000 行)
UI-->>UI: Phase 3: 渲染到 DOM<br/>(仅增量更新)
| 功能 | 说明 |
|---|---|
| 实时轮询 | 1 秒间隔轮询,仅页面可见时触发,离开自动暂停 |
| 增量读取 | 通过 offset 参数实现增量读取,避免重复传输已读日志 |
| 日志轮转检测 | 当 offset > file_size 时自动检测日志轮转,重置缓冲区 |
| 搜索过滤 | 支持实时搜索高亮,匹配文本用 <mark> 标签标记 |
| 自动滚动 | 默认自动滚动到底部,用户手动上滚时暂停自动滚动 |
| 环形缓冲区 | 内存中最多保留 2000 行,超限自动截断旧日志 |
| 懒加载 | 通过动态 import() 按需加载,离开页面时 destroyLogsPage() 清理资源 |
| 行数限制 | 后端硬性上限 2000 行/次请求,防止内存溢出 |
-
无路径遍历风险:日志路径由后端
MihomoState.last_log_path自动生成(系统临时目录 + 固定前缀),不接受任何用户路径输入 -
XSS 防护:日志文本通过独立的轻量级
escapeHtml函数转义(字符串映射表,零 DOM 分配),搜索高亮的<mark>标签基于已转义文本插入 - 信息隔离:日志仅在本地 Tauri 窗口中显示,不写入外部存储、不发送到远程服务器
Zephyr 的前端界面完全基于原生 JavaScript 与 Tailwind CSS 构建,不依赖任何前端框架,实现了极致轻量与高度定制化的视觉体验。
全局采用 Glassmorphism(玻璃拟态)设计语言:
/* 玻璃拟态核心样式 */
.glass-card {
background: rgba(255, 255, 255, 0.02); /* 半透明背景 */
backdrop-filter: blur(16px); /* 背景模糊 */
-webkit-backdrop-filter: blur(16px);
border-radius: var(--radius-lg); /* 大圆角 */
border: 1px solid var(--border-primary);
box-shadow: 0 4px 24px -8px rgba(0, 0, 0, 0.2);
}| 模式 | 说明 |
|---|---|
| 深色模式 | 深色背景 + 浅色文字,适合夜间使用 |
| 浅色模式 | 浅色背景 + 深色文字,适合日间使用 |
| Auto | 跟随系统主题自动切换 |
提供 5 种预设主题色,同时支持通过取色器自定义任意颜色:
| 预设色 | 色值 | 视觉感受 |
|---|---|---|
| 薰衣草紫 | #8B5CF6 |
优雅、科技感 |
| 海洋蓝 | #0A84FF |
沉稳、专业 |
| 翡翠绿 | #34C759 |
自然、清新 |
| 玫瑰红 | #FF2D55 |
活力、热情 |
| 琥珀橙 | #FF9500 |
温暖、活力 |
主题色通过 CSS 变量 --color-accent 全局生效,所有强调色元素(按钮、链接、选中态等)自动跟随切换。
内置三种尺寸的 iOS 风格 Toggle 开关组件:
| 尺寸 | 适用场景 |
|---|---|
| 小 (SM) | 列表项内嵌开关 |
| 中 (MD) | 设置面板选项 |
| 大 (LG) | 独立功能开关 |
支持在 10% - 100% 范围内调节应用窗口不透明度,用户可根据个人偏好或桌面壁纸搭配调整透明度。
当节点名称过长超出容器宽度时,自动启用水平滚动动画:
/* 节点名称滚动动画 */
@keyframes text-scroll {
0% { transform: translateX(0); }
15% { transform: translateX(0); }
85% { transform: translateX(calc(-100% + 120px)); }
100% { transform: translateX(calc(-100% + 120px)); }
}
.group:hover .scrolling-text {
animation: text-scroll 4s linear infinite alternate;
}
.scrolling-text-container {
mask-image: linear-gradient(to right, black 80%, transparent 100%);
}通过 mask-image 渐变遮罩实现文字两端的淡出效果,滚动动画自然流畅。
内置轻量级通知系统,支持四种通知级别。通知超时按是否有标题区分:有标题的通知 4 秒自动消失,无标题的通知 3 秒自动消失。
| 级别 | 用途 |
|---|---|
info |
一般信息提示 |
success |
操作成功反馈 |
warning |
警告信息 |
error |
错误信息 |
所有下拉菜单组件通过预定义的 DOM 容器元素挂载,避免被父容器的 overflow: hidden 裁切,确保在复杂布局中始终正确显示。
| 平台 | 窗口样式 | 说明 |
|---|---|---|
| Windows | 无边框 | 自定义标题栏,完全掌控窗口外观 |
| macOS | 无边框 | 自定义标题栏,原生拖拽区域 |
| Linux | 原生窗口装饰 | 使用系统提供的窗口边框和标题栏,保证兼容性 |
返回 Home