
本文旨在深入探讨j*ascript中缓动函数(easing functions)的正确使用方法,解决动画时间管理中的常见问题。文章将重点阐述如何通过精确追踪动画的起始时间,并结合`requestanimationframe`,实现平滑、可控且从预期值开始的动画效果,避免因时间戳误用导致的动画异常。
在Web前端开发中,缓动函数是实现非线性动画效果的关键工具。它们允许动画在开始、中间或结束时加速或减速,从而使视觉体验更加自然和富有表现力。一个典型的缓动函数通常接受四个参数:
通过这些参数,缓动函数计算出在给定当前时间t时,动画属性应达到的精确值。
许多开发者在初次使用缓动函数时,可能会遇到一个普遍的问题:动画无法从预期的起始值(例如0)开始,而是跳到一个较大的值。这通常是由于对时间戳的误解和不当使用造成的。
例如,如果一个函数像下面这样尝试获取时间:
getEaseTimeVar() {
var timeStamp = performance.now();
this.#secondsPassed = (timeStamp - this.#oldTimeStamp) / 1000;
this.#oldTimeStamp = timeStamp;
return timeStamp;
}这个函数返回的是自页面加载以来(或performance.now()的参考点)的总时间。当动画在代码执行的早期启动时,t值相对较小,动画行为可能符合预期。然而,如果动画在页面加载后经过一段时间(例如5秒)才被触发,此时timeStamp已经是一个很大的值。如果直接将这个值作为缓动函数的t参数,动画会立即跳到一个较大的中间值,而不是从其b参数定义的起始值开始。
问题的核心在于,缓动函数中的t参数需要的是动画从开始至今的已逝时间,而不是程序运行的总时间。
要正确使用缓动函数,关键在于为每个独立的动画实例维护其自身的起始时间。当一个动画被触发时,我们需要记录下那一刻的精确时间作为该动画的startTime。之后,在动画的每一帧中,我们通过当前时间减去startTime来计算出动画的已逝时间animTime。
// 动画启动时 let startTime = performance.now(); // 在动画循环中 let animTime = performance.now() - startTime;
只有当animTime介于0和animDuration之间时,动画才应该进行。一旦animTime超过animDuration,动画就应该停止,或者将属性值设置为动画的最终目标值,以确保动画的完整性。
火龙果写作
用火龙果,轻松写作,通过校对、改写、扩展等功能实现高质量内容生产。
277
查看详情
以下是一个结合requestAnimationF
rame和精确时间管理来使用缓动函数的示例。我们将创建一个画布动画,点击画布时启动一个物体沿不同缓动曲线移动的动画。
// 定义缓动函数(来自 https://spicyyoghurt.com/tools/easing-functions)
// t: current time, b: beginning value, c: change in value, d: duration
const easeLinear = (t, b, c, d) => c * t / d + b;
const easeInOutQuad = (t, b, c, d) => (t /= d * 0.5) < 1 ? c * 0.5 * t * t + b : -c * 0.5 * ((t - 1) * (t - 3) - 1) + b;
// 动画状态变量
let animating = false; // 标记动画是否正在进行
let startTime; // 动画的起始时间
const animDuration = 2000; // 动画总时长,单位毫秒
// 获取Canvas上下文
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
// 为Canvas添加点击事件监听器,用于启动/重启动画
canvas.addEventListener("click", () => {
startTime = performance.now(); // 记录动画开始的时间
// 如果动画未进行,则启动requestAnimationFrame循环
if (!animating) {
requestAnimationFrame(mainLoop);
}
});
/**
* 主动画循环函数
* @param {DOMHighResTimeStamp} time - requestAnimationFrame 提供的当前时间戳
*/
function mainLoop(time) {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布
if (startTime !== undefined) { // 确保动画已启动
// 计算动画已逝时间
const animTime = time - startTime;
// 使用缓动函数计算当前帧的X和Y坐标
// X轴:使用线性缓动,从-20移动到 canvas.width + 40
const x = easeLinear(animTime, -20, canvas.width + 40, animDuration);
// Y轴:使用easeInOutQuad缓动,从20移动到 canvas.height - 40
const y = easeInOutQuad(animTime, 20, canvas.height - 40, animDuration);
// 绘制圆形
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI * 2);
ctx.fill();
// 判断动画是否仍在进行
if (animTime < animDuration) {
// 如果动画未结束,继续请求下一帧
requestAnimationFrame(mainLoop);
animating = true;
} else {
// 动画结束,将animating状态设为false
animating = false;
// 可选:确保动画最终位置准确
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(
easeLinear(animDuration, -20, canvas.width + 40, animDuration),
easeInOutQuad(animDuration, 20, canvas.height - 40, animDuration),
20, 0, Math.PI * 2
);
ctx.fill();
}
}
}对应的HTML和CSS:
<style>
canvas { border: 1px solid black; }
</style>
<p>点击画布以启动/重启动画。</p>
<canvas id="canvas" width="500" height="200"></canvas>代码解析:
为了更清晰地理解缓动函数的四个参数:
理解这些参数对于正确构建和使用缓动函数至关重要。
正确使用J*aScript缓动函数的核心在于对动画时间的精确管理。通过记录每个动画实例的独立startTime,并计算相对于该起始时间的animTime,我们可以确保动画始终从预期的起始值开始,并按照定义的缓动曲线平滑过渡。结合requestAnimationFrame,这种方法能够构建出高性能、视觉效果优秀的Web动画。掌握这一技巧,将使你在开发动态交互界面时更加得心应手。
以上就是深入理解J*aScript缓动函数:精确时间管理与动画实现的详细内容,更多请关注其它相关文章!
相关文章:
荒野行动PC版怎么注册_荒野行动PC版账号注册详细流程图文教程
天猫2025双十一0点秒杀攻略 天猫爆款抢购时间
C++如何实现一个装饰器模式_C++设计模式之动态地给对象添加额外职责
汽车之家官方网站官网入口_汽车之家网页版直接进入
文心一言怎样用批量生成做多版文案_文心一言用批量生成做多版文案【批量创作】
cad如何更改注释性对象的比例_cad注释性比例调整方法
服务端验证_j*ascript输入检查
Django模型中自动计算可用余额的实现方法
J*a最大堆Heapify方法修复:索引计算与边界条件深度解析
Win11文件资源管理器卡顿怎么修 Win11重置资源管理器进程优化响应速度【修复方法】
淘宝支付提示失败如何解决 淘宝支付流程优化方法
抖音网页版企业服务中心登录入口_抖音网页版企业登录平台
2026年CSGO开箱网站推荐 CSGO开箱平台精选
mc.js游戏直达 mc.js网页免下载版本秒进地址
QQ邮箱登录官网首页 腾讯QQ邮箱网页入口
解决Tabulator日期时间排序问题的专业指南
支付宝碰一碰设备是REDMI手机吗 博主拆机辟谣:处理器、内存都不一样
深入理解J*a编译器的兼容性选项:从-source到--release
Selenium Python中处理点击后新窗口加载冻结问题的策略与实践
Golang如何使用new_Go new分配内存机制讲解
微信网页版官方快速登录入口 微信网页版网页版账号直达
利用Bokeh CustomJS动态控制DataTable列可见性
Win11怎么设置开机NumLock亮 Win11修改注册表InitialKeyboardIndicators值
AWS EC2实例间SQL Server连接超时:安全组配置与故障排除指南
qq游戏免费畅玩入口_qq游戏电脑版快速启动
虚幻5科幻题材ARPG大作遭取消!本是《奇异人生》厂商新作
电脑屏幕颜色不舒服怎么办_Windows夜间模式与色彩校准教程【护眼技巧】
CSS Flexbox与媒体查询:实现响应式布局中元素的并排与堆叠
Lar*el表单中优雅地处理“返回”按钮以规避验证:最佳实践指南
Golang如何优化内存分配与垃圾回收_Golang内存管理与GC优化实践
如何有效阻止外部脚本意外修改内联样式的高度属性
极兔快递快件信息查询系统 极兔快递官网运单号追踪
钉钉视频会议画面卡顿如何解决 钉钉会议画面优化方法
php源码怎么在电脑上测试_电脑测试php源码方法步骤【教程】
响应式容器内容自动缩放与宽高比维持教程
C++如何解决segmentation fault_C++段错误调试与原因分析
单射、满射与双射的关系 一文理清所有逻辑
qq浏览器打开空白页怎么办 qq浏览器启动后显示白屏的解决教程
如何设置Windows Defender的定时扫描_计划任务实现自动杀毒【安全】
拼多多购物车商品数量无法修改如何处理 拼多多购物车操作优化方法
html网页设计源代码怎么运行_运行html网页设计源代码步骤【指南】
React/Next.js中实现列表项的动态选择与移动
如何在离线环境中使用Composer_Composer离线安装依赖包的技巧与策略
CSS实现侧边栏导航项全宽圆角悬停背景效果
C++如何生成随机数_C++ random库使用方法与范围设置
解决Bootstrap卡片顶部边距导致背景图下移的问题
解决 Vaadin 8 中大文件音频播放与定位时出现的 IOException
动漫共和国防屏蔽稳定域名-动漫共和国官方正版直达通道
C++的std::mdspan是什么_C++23中用于操作多维数组的非拥有视图
Python复杂任务中断策略:通过回调函数实现优雅停止