组件/设计工程概念手册/90ms+90ms 确认律动与物理弹簧引擎

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)的时间插值函数。 如果在用户拖拽抽屉或移动卡片的过程中发生手势打断(例如用户突然反向滑动),过渡会从当前位置按固定时长重新走一条曲线,速度直接换成新曲线起点的斜率,与打断前的速度 v⃗0\vec{v}_0 无关:

  • 起点平缓的曲线(如 ease-in-out)会先急停,再重新加速。
  • 起点陡峭的曲线(如 TuffEx 的 ease-out-strong)反而会猛地加速。

两种情况速度都发生突变,运动轨迹出现机械的折断感,丧失物理真实感。

TuffEx 二阶阻尼弹簧物理引擎

需要在打断时保住速度、又由 JS 逐帧绘制的动效,TuffEx 交给 stepSpring 推进,例如 TxSlider 拖过头后的回弹、TxMorph 与 TxTransitionSmoothSize 的尺寸形变,以及 TxLiquid。它积分的是二阶阻尼振荡微分方程(xx 为相对目标的位移): md2xdt2+cdxdt+kx=0m \frac{d^2x}{dt^2} + c \frac{dx}{dt} + k x = 0

  • 刚度(Stiffness kk):控制弹簧形变后的回弹爆发力。
  • 阻尼(Damping cc):控制振荡衰减,消除反复晃动。
  • 质量(Mass mm):赋予卡片物理惯性。

stepSpring 用半隐式欧拉法积分,每 1/240 秒算一个子步。手势打断时只换目标,当前的位置与速度原样带过去,产生如同真实弹簧拉伸回弹般的丝滑跟手体验。

示例加载中...