动画引擎原理 总览待审核
magnetic · swipe-to-dismiss · follow

手势进阶:磁吸、跟随、滑动消除

拖拽惯性是把松手速度交给弹簧顺势抛出;这里是它的另一面——把持续的指针位置 接到动画值上。三个手势共用同一套零件:pointerdown / move / up 取输入、 createSpring 平滑逼近目标、createDecay 接住松手速度。区别只在于「目标是什么、谁来接管」。

磁吸按钮 (magnetic)

指针进入按钮一定半径内,按钮被弹簧吸向指针:目标偏移 = (指针 − 中心) × 一个比例系数。指针离开半径, 目标偏移归零,弹簧把它弹回原位。弹簧的 from 始终是当前位置、to 是当下目标,所以目标随指针连续变化时也不会跳。

悬停靠近我
指针距中心 目标偏移 状态 空闲

hover 跟随

小圆点用弹簧平滑跟随指针,不是瞬移:每帧把弹簧目标更新为最新指针位置,值朝它逼近。欠阻尼参数下会带轻微 延迟与过冲——指针骤停时圆点冲过一点再收回。调小 stiffness 让跟随更「黏」,调小 damping 放大过冲。

指针 圆点滞后

滑动消除 (swipe-to-dismiss)

水平拖动卡片,松手时用最近两帧的位移 ÷ 时间估出速度。若位移或速度超过阈值,把这个速度交给 createDecay,卡片顺着惯性甩出屏幕并淡出;否则用 createSpring 弹回原位。阈值判定决定走哪条路, 一旦判定「消除」,后续就是无目标的惯性滑行。

水平拖动我 甩过阈值 → 滑出消失
当前位移 0px 松手速度 判定
磁吸 = 弹簧 from 当前、to 目标:目标随指针连续移动,而 from 取实时位置,因此目标突变也不会让按钮瞬跳—— 弹簧自然把这段差值演化掉。滑动消除的关键是阈值判定:松手速度由最近两帧位移 ÷ 时间估得, 位移或速度任一过阈值即判「消除」,把松手速度作为初速度交给 decay(无目标、只有摩擦)甩出并淡出; 未过阈值则交给 spring 弹回 0。两条路的分叉点就在松手那一刻的一次比较。
@vega/anim — 磁吸的弹簧逼近 + 滑动消除的阈值分叉

  

松手抛出的惯性来源见拖拽惯性;弹簧的过冲与回弹形态见弹簧; 跟随时不断改目标、由弹簧从当前位置与速度接管下一段,正是中断重定向讲的「速度接管」。