90ms+90ms 确认律动与物理弹簧引擎
为什么菜单点击后瞬间消失是错的?90ms+90ms 两拍式微交互确认律动与二阶阻尼物理弹簧引擎原理。
90ms+90ms 确认律动与物理弹簧引擎
点击反馈必须兼顾“确定感”与“极速流转”。TuffEx 总结了菜单动作确认节拍与连续物理弹簧动力学。
为什么菜单点击瞬间消失是错的?
在许多原生系统或网页中,用户在下拉菜单中点击某一项后,菜单在 0ms 内瞬间凭空消失。 用户常常会下意识地愣住一瞬:“我刚才真的点中那一行了吗?还是鼠标滑出去了?” 这种反馈缺失极大地削弱了界面的心理掌控感。
两拍式动作确认律动(90ms + 90ms)
TuffEx 的 TxDropdownItem 与 TxContextMenuItem 在点击后先走一段 两拍、合计约 180ms 的确认节拍,再关闭菜单:
[用户点击菜单项]
│
├─【拍子一:90ms】这一行的边框、底色和阴影全部变透明,撤掉悬停与焦点的高亮。
│
├─【拍子二:90ms】这一行切到 TxCardItem 的激活态,确认“已命中”。
│
└─【第二拍结束】派发 select 事件,然后关闭菜单。
两拍各由一个 90ms 的 setTimeout 推进;定时器不保证准点,实测每拍约 91ms。只有这次点击会关闭菜单(close-on-select)、并且 activation-feedback 开着(两者默认都开)时才走两拍,否则立即派发 select。当系统开启“减弱动态效果”时,同样立即执行。
贝塞尔曲线在手势打断下的缺陷
传统 CSS 贝塞尔曲线(如 ease-out、cubic-bezier)本质上是基于预设固定时长(Duration)的时间插值函数。
如果在用户拖拽抽屉或移动卡片的过程中发生手势打断(例如用户突然反向滑动),过渡会从当前位置按固定时长重新走一条曲线,速度直接换成新曲线起点的斜率,与打断前的速度 无关:
- 起点平缓的曲线(如
ease-in-out)会先急停,再重新加速。 - 起点陡峭的曲线(如 TuffEx 的
ease-out-strong)反而会猛地加速。
两种情况速度都发生突变,运动轨迹出现机械的折断感,丧失物理真实感。
TuffEx 二阶阻尼弹簧物理引擎
需要在打断时保住速度、又由 JS 逐帧绘制的动效,TuffEx 交给 stepSpring 推进,例如 TxSlider 拖过头后的回弹、TxMorph 与 TxTransitionSmoothSize 的尺寸形变,以及 TxLiquid。它积分的是二阶阻尼振荡微分方程( 为相对目标的位移):
- 刚度(Stiffness ):控制弹簧形变后的回弹爆发力。
- 阻尼(Damping ):控制振荡衰减,消除反复晃动。
- 质量(Mass ):赋予卡片物理惯性。
stepSpring 用半隐式欧拉法积分,每 1/240 秒算一个子步。手势打断时只换目标,当前的位置与速度原样带过去,产生如同真实弹簧拉伸回弹般的丝滑跟手体验。