关于 frontend-ux
面向 Web3 前端开发者的 UX 规则指南,聚焦链上操作状态、地址与金额呈现、RPC 使用和错误反馈。
主要功能
- 01为链上操作设计独立待处理状态
- 02按连接、网络和授权状态安排操作
- 03规范地址验证、复制与展示
- 04显示代币金额的美元价值
- 05处理合约错误与主题样式
适用场景
- 01改进授权和交易按钮的状态反馈
- 02设计钱包地址输入与展示
- 03排查前端 RPC 轮询问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ austintgriffith/ ethskills --skill frontend-ux安装后在 Claude Code 中输入/frontend-ux确认已加载。
详细介绍
前端 UX 规则
你可能做错了什么
“按钮能用。” 按钮可以点击还不够。它必须立即禁用,显示清晰的待处理状态,并保持锁定,直到链上确认。
“地址只是字符串。” 地址体验需要验证、安全格式化、复制支持、区块浏览器链接,以及在可用时支持 ENS/名称解析。
“代币金额很明确。” 不带美元价值背景的原始代币数值会迫使用户猜测风险和价值。在金额重要的任何地方都应显示美元价值。
规则 1:每个与链上交互的按钮都需要独立的待处理状态
任何会触发链上交易的按钮都必须:
- 点击后立即禁用
- 显示加载动画 + 操作文本(
Approving...、Staking...) - 保持禁用,直到链上状态确认完成
- 完成后显示成功/错误反馈
// Separate loading state per action
const [isApproving, setIsApproving] = useState(false);
const [isStaking, setIsStaking] = useState(false);
<button
disabled={isApproving}
onClick={async () => {
setIsApproving(true);
try {
await sendApproveTx();
} catch (e) {
notifyError("Approval failed");
} finally {
setIsApproving(false); // always release — even on rejection
}
}}
>
{isApproving ? "Approving..." : "Approve"}
</button>
多个按钮绝不能共用一个 isLoading 状态。这会导致标签错误、禁用状态错误,以及重复提交。
对于授权流程:仅有 isPending 并不够。
当钱包返回交易哈希时,isPending 就会变为 false,此时链上尚未确认。此时会出现一个时间窗口:isPending = false,但授权额度尚未更新 → 按钮会在交易处理中重新启用,用户可能重复提交。
授权处理程序需要两个状态:approvalSubmitting(点击时设置,在 finally {} 中清除),用于覆盖钱包返回结果到确认之间的空档;以及 approveCooldown(确认后设置,4 秒后并重新获取数据时清除),用于覆盖确认到缓存更新之间的空档。两者都应加入 disabled 条件。必须使用 finally {}——否则交易被拒绝后,按钮会永久锁定。
规则 2:四状态操作流程
一次只显示一个主要操作:
1. Not connected -> Connect Wallet
2. Wrong network -> Switch Network
3. Needs approval -> Approve
4. Ready -> Execute action (Stake/Deposit/Swap/etc.)
关键细节:
- 错误网络检查必须先于授权/操作检查
- 绝不能同时显示“授权”和“执行”
- 授权状态必须来自最新的链上状态(不能只依赖过期的本地状态)
- 连接状态必须显示可点击的操作,而不是被动文本
规则 3:地址体验标准
每个显示的地址都应支持:
- ENS/名称解析(适用时)
- 区块浏览器链接
- 复制到剪贴板
- 安全截断 + 视觉标识(头像/blockie 可选)
每个地址输入框都应支持:
- 验证
- 粘贴规范化
- 在可用时支持 ENS/名称解析
如果你的 UI 工具包包含专用的地址组件,请使用它们。关键地址输入不要使用普通的自由文本框。
规则 4:显示代币金额的美元价值背景
向用户显示的每个代币/ETH 金额都应附带美元价值背景:
- 余额
- 输入(实时预览)
- 确认文本
- 仓位/投资组合摘要
<span>0.5 ETH (~$1,250.00)</span>
<span>1,000 TOKEN (~$4.20)</span>
不要只显示代币单位而不提供价值背景。
规则 5:RPC 可靠性与轮询
- 在生产环境中使用专用 RPC 提供商(不要只依赖偶然使用的公共回退)
- 将轮询间隔保持在响应及时的范围内(交互式应用通常约为 2-5 秒)
- 确保回退传输是有意配置的,并考虑速率限制
- 留意失控的请求模式(渲染循环、重复监听器、无限轮询)
健康基线:请求量低且稳定。QPS 突增或长期居高不下,通常意味着前端 Hook/配置存在问题。
规则 6:使用主题语义,而非硬编码的深色容器
不要硬编码忽略主题/系统偏好的整页深色背景。
使用语义化主题令牌/类,确保浅色/深色模式在以下方面保持一致:
- 页面背景
- 表面层
- 主要/次要文本
- 组件状态
如果你有意只支持深色模式,请移除或禁用不再适用的主题控件。
规则 7:合约错误转换
绝不能让用户看到原始的回滚选择器或遇到无提示的失败。
实现:
- 从 ABI/自定义错误中提取错误
- 将错误映射为易读的消息
- 处理钱包级错误(拒绝、Gas 问题)
- 安全的回退消息
- 在触发操作附近显示持久的行内错误 UI
try {
await sendTx();
} catch (e) {
setTxError(parseContractError(e));
}
规则 8:发布前的元数据和产品标识
正式发布前:
- Open Graph 图片 URL 是绝对 URL,且可通过线上域名访问(
https://...) - 正确设置 OG/Twitter 标题和描述
- 社交媒体预览图片有效,且不是本地或相对路径
- 移除模板默认品牌标识,或替换为项目标识
- 网站图标和标签页标题应体现应用身份
规则 9:易读的金额和小数
始终在合约单位和显示单位之间进行转换:
import { formatEther, formatUnits, parseEther, parseUnits } from "viem";
formatEther(weiAmount);
formatUnits(tokenAmount, tokenDecimals);
parseEther("1.5");
parseUnits("100", 6); // USDC-style 6 decimals
切勿显示原始基本单位金额,例如 1500000000000000000。
完成前:通过 feedback/SKILL.md 发送一行反馈,可以是问题或赞扬。