JS easeInOutQuad缓动函数中(--t)表达式运算逻辑与公式推导
jQuery Easing easeInOutQuad 缓动函数 else 分支逻辑拆解
// jQuery Easing 内置 easeInOutQuad 源码 easeInOutQuad: function (t, b, c, d) { if ((t/=d/2) < 1) return c/2*t*t + b; return -c/2 * ((--t)*(t-2) - 1) + b; }
核心运算符运算顺序说明
- 前置自减运算符
--t优先级高于乘、减运算:执行时先将当前作用域内的t值减1,再用更新后的新值参与后续所有表达式计算,不存在旧值、新值混用的情况。 - 进入else分支前,
(t/=d/2)的复合赋值已经执行完毕:此时内部变量t已经被更新为「当前时间/半程时长」的值,范围为[1, 2](因为进入else意味着这个值不小于1,而原始t最大为d,除以d/2后最大值为2)。
else分支等价无简写写法推导
把前置自减、复合赋值全部替换为显式变量赋值,逻辑和原函数100%一致:
// else分支等价显式写法,无自减、无复合赋值 const tScaled = t / (d / 2); // 和if判断中的缩放逻辑完全一致 const tAdjusted = tScaled - 1; // 完全等价于原代码中--t的运算结果 return -c / 2 * (tAdjusted * (tAdjusted - 2) - 1) + b;
原代码用自减运算符只是代码简写,没有特殊逻辑,本质是将后半段缩放后范围为[1,2]的时间值偏移到[0,1]区间,和前半段的时间区间对齐,构造对称的缓动曲线。
计算逻辑验证
可以代入边界值验证正确性:
- 动画中点(t = d/2):tScaled = 1,tAdjusted = 0,代入计算得
-c/2 * (0*(0-2) -1) + b = b + c/2,和if分支在中点的计算结果完全一致,动画无断点。 - 动画终点(t = d):tScaled = 2,tAdjusted = 1,代入计算得
-c/2 * (1*(1-2) -1) + b = b + c,完全符合动画终点的预期值。
对表达式做代数化简后可以看出,后半段是和前半段对称的二次减速曲线,两段曲线在中点处值、斜率都连续,实现平滑的先加速后减速效果。
内容的提问来源于stack exchange,提问作者smpa01
相关产品推荐
相关产品推荐

