基于真实 DOM 还原 Skeleton 的工程思考
在前端开发中,Skeleton(骨架屏)是提升用户感知性能的重要手段。常见做法是单独写一套灰色占位组件,但这种方法存在一些明显的问题: 骨架屏和真实 UI 结构脱节,修改 UI 需要额外同步 skeleton; 文字行高和布局难以精准还原,容易出现错位; 页面渲染过程中容易出现布局抖动(CLS)。 本文分享我在组件库中对骨架屏的思考,以及如何通过与组件耦合的方式实现精准还原。 --- 传统 Skeleton 的问题 常见的实现方式是页面层写一套假的 Skeleton,例如: 这种方式存在几个问题: 结构脱节\ \ 骨架屏和真实组件是两个平行的版本,修改组件必须同步改 skeleton。 布局不精确\ \ 文字、行高、padding、响应式高度等都可能不一致,导致骨架屏和实际内容错位。 维护成本高\ \ 组件库或页面升级时,需要额外维护 skeleton 组件。 --- 我的方法:Skeleton 与组件结构耦合 我的核心思路是: 骨架屏应该是组件的一种状态,而不是独立组件。
把 Better Auth 跑在 Cloudflare Workers + D1 上踩了哪些坑
最近在给自己的站点接入用户系统,技术栈是 Cloudflare Workers(Hono)+ D1 + Better Auth。本以为照着文档走一遍就行,结果一路踩了三个连环坑,每个坑都有独立的报错,记录一下排查过程。 --- 坑一:注册/登录线上 503,本地完全正常 这是最难受的一个坑,因为本地开发一切正常,推上线就 503,让人摸不着头脑。 报错(wrangler tail) 原因:scrypt 是 CPU 杀手 Better Auth 默认用 scrypt 做密码哈希。scrypt 由 Colin Percival 在 2009 年设计,核心目标就是让暴力破解在计算资源上代价极高——它同时消耗大量 CPU 和内存,即便是现代 GPU 也很难并行加速。 这个特性在传统服务器上是优点,但在 Cloudflare Workers 上就成了致命问题: Workers 免费套餐单次请求 CPU 时限只有 10ms(付费套餐也只有 30ms) scrypt 在 Node.
从 "组件外也能改 Zustand 状态" 聊到它的底层原理
这次对 Zustand 的理解升级,其实是从一个很简单的问题开始的: 为什么我可以在组件外面通过 修改状态,而且组件里的值还能自动更新? 一开始我一直以为 Zustand 是基于 React Context 实现的。既然是基于 Context,那它应该只能在组件树里用,离开组件就没法工作。但实际测试下来发现: 在组件外调用 完全没问题 组件内通过 订阅的值也会自动更新 根本不需要 Provider(在默认用法下) 这让我意识到,我对 Zustand 的理解是错的。 一、Zustand 不是基于 React Context 很多人(包括我)会自然地把“全局状态管理”跟 React Context 绑定在一起。 但 Zustand 的默认实现,其实完全不依赖 React Context。 如果你这样创建一个 store: 这个 做的事情本质上是: 在内存里创建一个 store 对象 这个对象内部维护: 当前 state 一组 listeners(订阅者) getState setState subscribe
从 shadcn/ui Button 到可定制 loading 的业务按钮
在前端开发中,按钮是最常用的组件之一。shadcn/ui 提供了默认的 Button 组件,但在实际业务中,它存在一些不足: 默认按钮没有 loading 状态 无法阻止重复点击 loader 样式无法自定义,不适应不同主题 为了解决这些问题,我在 shadcn/ui Button 的基础上,封装了一个业务 Button 组件。 组件设计 核心目标: 增加 loading 状态 当按钮正在处理请求时显示 loader 自动禁用按钮,防止重复提交 支持 loader 样式自定义 通过 可以修改 loader 样式,例如深色模式下反色 继承原生 Button 属性 保留所有原生属性,如 , , 安全点击逻辑 当按钮处于 loading 或 disabled 时,阻止点击事件 核心代码 使用示例 为 true 时显示 loader 按钮禁用,防止重复点击 loader 样式可通过 自定义 总结 这个业务 Button 组件解决了 shadcn/ui 默认 Button 的不足: 增加 loading 状态 loader 可自定义样式 自动禁用点击,
秒杀系统中的前端倒计时设计
秒杀活动倒计时,看起来很简单:几秒、几分钟倒计时而已。但实际上,如果设计不好,会出现倒计时跳秒、提前结束、或者被用户改本地时间作弊的情况。今天就聊聊前端秒杀倒计时的思路和最佳实践。 倒计时的核心目标 准:显示的时间尽量和服务器同步,不能因为本地时间不准就“提前开始”或者“晚结束”。 顺滑:数字滚动、翻牌动画要流畅,不要跳秒。 安全:倒计时只是给用户看的,不能决定是否能下单,真正权限还是服务器说了算。 时间基准怎么搞 别完全靠本地时间,像 这种,用户一改系统时间就不准了。 靠谱做法:加载页面的时候拿一次服务器时间,然后算个偏差: 如果想更精准,还可以用 SSE 或 WebSocket,服务器实时推送时间,倒计时就完全跟服务器走。 SSE授时的典型实现 服务端 (Node.js 示例) 前端 (React 示例)