按功能与层级组织 · 同一组件提供多框架代码,复制即用
输入即过滤、↑↓ 移动、回车确认、Esc 关闭。焦点始终留在输入框,选中项用 aria-activedescendant 指出去——一旦把焦点移到列表项上,读屏用户每按一次方向键都会听到整个列表被重读。分组标题不参与键盘循环,跳过的逻辑放在拍平后的一维数组里做,不在渲染时判断。
光标停在卡上时,一层径向光斑跟着走,同时按光标在卡内的相对位置给 ±6° 的倾斜。两个量都写成 CSS 变量,由 requestAnimationFrame 节流后直接写进 style,不触发 React 重渲染——用 state 存坐标的话,鼠标每移动一像素就重渲染一次子树,长列表里会直接掉帧。触屏上不启用倾斜,卡片就是一张静态卡。
三档并排,用边框粗细与阴影把推荐档抬起来,价格用等宽数字(tabular-nums)对齐——不加这条,¥0 和 ¥399 的小数点会错位,三张卡的价签看起来像没对齐。billing 参数让月付与年付共用同一套 DOM:年付只换数字与角标,不另做一套卡片。