Animate动画时空机制
重要通知
动画的实现原理,就是在时间维度上对空间(X方向、Y方向、Z方向)进行不同值的变换。
基本概况
简介与核心思想
动画: 移动、缩放、旋转 为了衡量画面切换速度,引入了每秒帧数 FPS(Frames Per Second)的概念,是指每秒画面重绘的次数。FPS 越大,则动画效果越平滑,当 FPS 小于 20 时,一般就能明显感受到画面的卡滞现象
60fps(每秒帧数) 浏览器每帧16ms
3D旋转轮播图 | 相册图
https://www.jq22.com/demo/jquery3dlb201801292252
https://www.jq22.com/demo/jquery3Dlbt201801160003/
https://www.jq22.com/demo/jQuery3dLbt201709270842/
https://www.jq22.com/demo/jquery3d20151116/
https://www.jq22.com/demo/jquery-3dlb20150817/
https://www.jq22.com/demo/jquerylbt202109061025/
https://www.jq22.com/demo/jQuery-xc-150422204120/
html5酷炫的3D签到墙动画特效: https://www.17sucai.com/preview/1/2017-10-09/3D/index.html
http://47.99.130.140/project/admin/#/project/admin/home/other/loading
事件
transitionend:
Anime.js、Velocity.js等动画库
三大动画时间事件
window.setInterval
在浏览器中,setTimeout()/setInterval() 的每调用一次定时器的最小间隔是4ms
- [注意] Window系统下表现为15毫秒;Forefix浏览器表现为10毫秒;Chrome浏览器表现为1毫秒
var intervalID = setInterval(func, [delay, arg1, arg2, ...]);
var intervalID = setInterval(function[, delay]);
var intervalID = setInterval(code, [delay]);
WindowTimers.clearInterval(intervalID);
执行
let time = 0;
const interval = window.setInterval(() => {
time += 1;
if (time >= 2) {
window.clearInterval(interval);
}
console.info("time: ", time);
}, 1000);
window.setTimeout
在浏览器中,setTimeout()/setInterval() 的每调用一次定时器的最小间隔是4ms 最小延迟时间:
var timeoutID = scope.setTimeout(function[, delay, arg1, arg2, ...]);
var timeoutID = scope.setTimeout(function[, delay]);
var timeoutID = scope.setTimeout(code[, delay]);
window.clearTimeout(timeoutID);
- window.setImmediate: 该特性是非标准的,请尽量不要在生产环境中使用它!
- 该方法用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数。
- [注意] Window系统下表现为15毫秒;Forefix浏览器表现为10毫秒;Chrome浏览器表现为1毫秒
var immediateID = setImmediate(func, [param1, param2, ...]);
var immediateID = setImmediate(func);
window.clearImmediate(immediateID);
- 正常遍历输出
// 可以遍历输出: 0 1 2 3 4
for (var i = 0; i < 5; i++) {
console.log(new Date, i);
}
- 同步和异步代码的区别、变量作用域、闭包
缺陷: 不能分别遍历出i的不同值
async function Case1() {
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
console.log('out', i);
}
- 改造输出5 -> 0,1,2,3,4 闭包
async function Case2() {
for (var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
})(i);
}
console.log('out', i);
}
setTimeout API接口
IE9 及其更早版本不支持
async function Case3() {
for (var i = 0; i < 5; i++) {
setTimeout(function(i) {
console.log(new Date, i);
}, 1000, i);
}
console.log('out', i);
}
requestAnimationFrame(Fn)
- 浏览器在下次重绘之前调用指定的回调函数更新动画,回调函数执行次数通常是每秒 60 次。
- 该时间戳是一个十进制数,单位为毫秒,最小精度为 1ms(1000μs)。
window.requestAnimationFrame(Fn)
window.requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame;
window.cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
兼容浏览器解决方案
;(function () {
var lastTime = 0
var vendors = ['ms', 'moz', 'webkit', 'o']
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']
window.cancelAnimationFrame =
window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function (callback, element) {
var currTime = new Date().getTime()
var timeToCall = Math.max(0, 16 - (currTime - lastTime))
var id = window.setTimeout(function () {
callback(currTime + timeToCall)
}, timeToCall)
lastTime = currTime + timeToCall
return id
}
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function (id) {
clearTimeout(id)
}
})()
window.cancelAnimationFrame()
播放器案例
// 播放器对象
let initRequestAnimation = null;
// 播放序列控制器
const playerControl = {
paused: true, // 播放/暂停状态
durations: 0, // 总时长
prevDuration: 0, // 上次进度值,节流机制
currentDuration: 0, // 进度值
durationsText: "", // 总时长00:00:00文本
processText: "" // 进度时长00:00:00文本
};
// 时间序列控制器变量
const timingControl = {
startPlayTimestamp: 0, // 开始播放时的当前时间戳, 精确度与单位为毫秒级
accumulateTimestamp: 0, // 上一个暂停播放时的播放累积时长的时间戳, 精确度与单位为毫秒级,适于节流问题,否则一秒会执行60次
currentTimestamp: 0 // 截止目前的累积播放时间戳, 精确度与单位为毫秒级
};
// 自动播放控制器
async function updateDurationListener() {
const { startPlayTimestamp, accumulateTimestamp } = timingControl;
const timestamp = performance.now();
// 计算从播放开始时 到 当前时间戳的播放时长
const stageTimestamp = timestamp - startPlayTimestamp;
// 计算整体播放的累积时长 时间戳
timingControl.currentTimestamp = accumulateTimestamp + stageTimestamp;
// 计算整体播放的累积时长 总秒数
const currentSeconds = Math.floor(timingControl.currentTimestamp / 1000);
playerControl.currentDuration = currentSeconds;
// 节流机制,禁止一秒内执行60次,限制一秒执行一次
if (playerControl.currentDuration !== playerControl.prevDuration) {
playerControl.prevDuration = playerControl.currentDuration;
// 播放业务
await updateActionByDurations();
}
}
// 播放控制器
const requestAnimationFrame = window.requestAnimationFrame;
const cancelAnimationFrame = window.cancelAnimationFrame;
async function startRequestAnimation() {
initRequestAnimation.value = requestAnimationFrame(async function animate() {
initRequestAnimation.value = requestAnimationFrame(animate);
await updateDurationListener();
});
}
async function stopRequestAnimation() {
cancelAnimationFrame(initRequestAnimation.value);
// 暂停业务
pauseAction();
}
/**
* 根据播放累积时长同步更新业务
*/
async function updateActionByDurations() {
//
}
// 暂停演示 业务
async function pauseAction() {
cancelAnimationFrame(initRequestAnimation.value);
playerControl.paused = true;
// 清除开始播放时的时间戳
timingControl.startPlayTimestamp = 0;
// 记录暂停时已经播放的累积时长
timingControl.accumulateTimestamp = playerControl.currentDuration * 1000;
await manageAudio(false);
}
CSS3 动画与相关类库
Animate.css
代码示例
<html>
<body>
<h1 class="animate__animated animate__bounce"></h1>
<h2 class="animate__animated animate__delay-2s"></h2>
<h3 class="animate__animated"></h3>
<h4 class="animate__animated"></h4>
<h5 class="animate__animated"></h5>
<h6 class="animate__animated"></h6>
</body>
</html>
延迟
animate__delay-2s # 2s
animate__delay-3s # 3s
animate__delay-4s # 4s
animate__delay-5s # 5s
速度
animate__slow # 2s
animate__slower # 3s
animate__fast # 800ms
animate__faster # 500ms
重复
animate__repeat-1 # 1
animate__repeat-2 # 2
animate__repeat-3 # 3
animate__infinite # infinite
时间周期需要自己写CSS
.animate__animated.animate__bounce {
--animate-duration: 2s;
}
/* This changes all the animations globally */
:root {
--animate-duration: 800ms;
--animate-delay: 0.9s;
}
源码原理
@keyframes backInUp {
0% {
-webkit-transform: translateY(1200px) scale(0.7);
transform: translateY(1200px) scale(0.7);
opacity: 0.7;
}
80% {
-webkit-transform: translateY(0px) scale(0.7);
transform: translateY(0px) scale(0.7);
opacity: 0.7;
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
}
.animate__backInUp {
animation-name: backInUp;
}
bounce.js
- 官网: <>
- GitHub: https://github.com/tictail/bounce.js
Effeckt.css
move.js
- 官网: <>
- GitHub: https://github.com/visionmedia/move.js
Dynamics.js
Dynamics.js是用于创建基于物理的动画的 JavaScript 库,能为你提供9种标准的动效,你可以制定其中的持续时间、频率、预期尺寸和强度等数据,创造出符合物理效果的动效。
TweenMax.js
TweenMax.js: 适用于移动端和现代互联网的超高性能专业级动画插件, Tweenmax是GreenSock 动画平台的核心,配合其他插件,可动画CSS属性、滤镜效果、 颜色、 声音、 色彩、 帧、 饱和度、 对比度、 色调、 色系、 亮度、 贝塞尔等。
- 官网: https://www.tweenmax.com.cn/
tweenJS
- GitHub: https://github.com/tweenjs/tween.js
- 文档: http://tweenjs.github.io/tween.js/
- 用户指南: http://tweenjs.github.io/tween.js/docs/user_guide.html
- 动画类型: https://tweenjs.github.io/tween.js/examples/03_graphs.html
文件类型
UMD : tween.umd.js
AMD : tween.amd.js
CommonJS : tween.cjs.js
ES6 Module : tween.es.js
代码示例
import { TWEEN } from '/Animate/tweenJS/dist/tween.module.min.js';
requestAnimationFrame(animate() {
requestAnimationFrame(animate)
TWEEN.update()
});
// 初始状态
const coords = {x: 0, y: 0};
const tween = new TWEEN.Tween(coords)
// 目标状态
.to({x: 300, y: 200}, 1000)
// 延时执行时间
.delay(1000)
// 动画特征类型
.easing(TWEEN.Easing.Quadratic.Out)
// 状态变化处理函数
.onUpdate(() => {
box.style.setProperty('transform', `translate(${coords.x}px, ${coords.y}px)`)
})
// 完成事件
.onComplete(() => {
console.log('完成');
})
// 停止事件
.onStop(() => {
console.log('停止');
})
// 重复次数
.repeat(10)
// 每次重复延迟时间
.repeatDelay(1000)
// 启动动画
.start();
API接口
var exports = {
Easing: Easing,
Group: Group,
Interpolation: Interpolation,
now: now$1,
Sequence: Sequence,
nextId: nextId,
Tween: Tween,
VERSION: VERSION,
getAll: getAll,
removeAll: removeAll,
add: add,
remove: remove,
update: update,
};
动画类型 | Easing
每个效果都分三个缓动方式,分别是: easeIn: 从0开始加速的缓动,也就是先慢后快;easeOut: 减速到0的缓动,也就是先快后慢;easeInOut: 前半段从0开始加速,后半段减速到0的缓动。
- Linear: 线性匀速运动效果;
- Quadratic: 二次方的缓动(t^2);
- Cubic: 三次方的缓动(t^3);
- Quartic: 四次方的缓动(t^4);
- Quintic: 五次方的缓动(t^5);
- Sinusoidal: 正弦曲线的缓动(sin(t));
- Exponential: 指数曲线的缓动(2^t);
- Circular: 圆形曲线的缓动(sqrt(1-t^2));
- Elastic: 指数衰减的正弦曲线缓动;
- Back: 超过范围的三次方缓动((s+1)t^3 – st^2);
- Bounce: 指数衰减的反弹缓动。
TWEEN控制
start和stop Tween.start和Tween.stop分别用于控制tween动画的开始和结束。 对于已经结束和没有开始的动画,Tween.stop方法不起作用。Tween.start方法同样接收一个时间参数。如果你使用了该参数,tween动画将在延时该时间数后才开始动画。否则它将立刻开始动画 update: 可以通过TWEEN.update方法来执行动画的更新。
chain: 如果你想制作多个多行,例如: 一个动画在另一个动画结束后开始。可以通过chain方法来使实现。如下的代码,tweenB 在 tweenA 之后开始动画: tweenA.chain(tweenB): 可以像下面这样制作一个无限循环的动画: tweenA.chain(tweenB);tweenB.chain(tweenA);
repeat: 如果你想制作循环动画可以使用chain来实现,但是更好的方法是使用repeat方法。它接收一个用于描述你想循环多少次的参数: tween.repeat(10); // repeats 10 times and stops tween.repeat(Infinity); // repeats forever 永久执行循环动画
yoyo: 这个函数只在你使用repeat方法是起作用。当它被激活时,tween 的效果类似yoyo效果。该效果是动画会在开始或结束处向反方向反弹。 delay: delay方法用于控制动画之间的延时 ``` tween.delay(1000); tween.start(); onStart: tween开始动画前的回调函数。 onStop: tween结束动画后的回调函数。 onUpdate: 在tween每次被更新后执行。 onComplete: 在tween动画全部结束后执行。
Loading
DIV+CSS3动画 | Loading : http://www.h-ui.net/icon/loading.shtml 炫酷的Loading效果插件(还包括其他多功能): https://shnhz.github.io/shn-ui/#/component/epic-spinners HTML5+CSS3 最酷的 loading 效果收集 https://www.runoob.com/w3cnote/free-html5-css3-loaders-preloaders.html https://www.jq22.com/yanshi4405
https://www.17sucai.com/pins/demo-show?id=32053 https://www.17sucai.com/pins/demo-show?id=28013 30种CSS3炫酷页面预加载loading动画特效 https://www.17sucai.com/preview/869565/2017-11-17/cssLoading/index.html
53种css3 loading白色加载图标动画特效 https://www.17sucai.com/pins/demo-show?id=24122 纯css3彩色的loading加载图标动画特效 https://www.17sucai.com/pins/demo-show?id=25577 纯css3音阶波浪loading加载动画特效 https://www.17sucai.com/pins/demo-show?id=22606 纯css3精美的loading网页加载动画特效 https://www.17sucai.com/pins/demo-show?id=23717
html5 SVG绘图动画制作页面加载loading绘图动画效果 https://www.17sucai.com/pins/demo-show?id=4160
GSAP动画库
- 官网: https://greensock.com/
- 文档: https://greensock.com/docs/
- NPM: https://www.npmjs.com/package/gsap
- GSAP 3 备忘单: https://greensock.com/cheatsheet/
- Club Plugins: https://greensock.com/docs/v3/Installation
- 插件列表: https://greensock.com/gsap-plugins/
- CSSPlugin: https://greensock.com/docs/v3/GSAP/CorePlugins/CSSPlugin
- Animate Eases复杂缓动演示效果: https://greensock.com/docs/v3/Eases
- TweenMax: https://www.tweenmax.com.cn/index.html
- 经典案例: https://greensock.com/showcase/
简介与核心思想
GSAP,即,是现代网络动画的标准,一个强大的 JavaScript 工具集,可将开发人员变成动画超级英雄,GSAP 是地球上最快的全功能脚本动画工具。
Tween(补间)
Tween(缓动)文档: https://greensock.com/docs/v3/GSAP/Tween
gsap.to()
gsap.to(".box", { rotation: 27, x: 100, duration: 1 });
- gsap.from()
- gsap.fromTo()
Timeline(时间线)
- Timeline(时间轴)文档: https://greensock.com/docs/v3/GSAP/Timeline
// 创建时间线实例
const tl = gsap.timeline();
tl.to(".box1", {duration: 2, x: 100})
.to(".box2", {duration: 1, y: 200})
.to(".box3", {duration: 3, rotation: 360});
//WITH Timelines (cleaner, more versatile)
var tl = gsap.timeline({repeat: 2, repeatDelay: 1});
tl.to("#id", {x: 100, duration: 1});
tl.to("#id", {y: 50, duration: 1});
tl.to("#id", {opacity: 0, duration: 1});
// then we can control the whole thing easily...
tl.pause();
tl.resume();
tl.seek(1.5);
tl.reverse();
- gsap.pause()
- gsap.play()
- gsap.progress()
- gsap.restart()
- gsap.resume()
- gsap.reverse()
- gsap.seek()
- gsap.time()
- gsap.duration()
- gsap.timeScale()
- gsap.kill()
GreenSock 动画平台核心工具
插件列表
SplitText: 将文本块拆分为行、单词和字符,使您能够轻松地为每个部分制作动画。| https://greensock.com/docs/v3/Plugins/SplitText Draggable: 添加拖放任何元素的能力。| https://greensock.com/docs/v3/Plugins/Draggable MorphSVGPlugin: 复杂 SVG 路径的平滑变形。| https://greensock.com/morphSVG/ | https://greensock.com/docs/v3/Plugins/MorphSVGPlugin DrawSVGPlugin: 动画 SVG 笔划的长度和位置。 | https://greensock.com/drawSVG/ | https://greensock.com/docs/v3/Plugins/DrawSVGPlugin MotionPathPlugin: 沿路径为任何元素设置动画。| https://greensock.com/docs/v3/Plugins/MotionPathPlugin GSDevTools Inertia MotionPathHelper
PhysicsProps ScrambleText
Physics2D
https://www.tweenmax.com.cn/Physics2DPlugin/ Physics2DPlugin 是GreenSock 动画平台用于进行物理动画的拓展插件,包括重力、速度、加速度、摩擦力动画等等。
FLIP
https://aerotwist.com/blog/flip-your-animations/
kuteJS
官网: http://thednp.github.io/kute.js/
Lottie
官网: http://airbnb.io/lottie/#/
- 安装配置
npm install lottie-web
- 代码示例
<script src="https://test.ysunlight.com/ServerCore/source/lottie-web/lottie.min.js" type="text/javascript"></script>
const lottieAnim = lottie.loadAnimation({
container: element, // the dom element that will contain the animation
renderer: 'canvas',
loop: true,
autoplay: true,
path: 'https://labs.nearpod.com/bodymovin/demo/markus/halloween/markus.json',
animationData: animationData, // the animation data
rendererSettings: {
context: canvasContext, // the canvas context
scaleMode: 'noScale',
clearCanvas: false,
progressiveLoad: false, // Boolean, only svg renderer, loads dom elements when needed. Might speed up initialization for large number of elements.
hideOnTransparent: true //Boolean, only svg renderer, hides elements when opacity reaches 0 (defaults to true)
}
});
方法
lottie.play(): lottie.stop(): lottie.pause(): lottie.setLocationHref(locationHref):
lottie.setSpeed(): lottie.setDirection(): lottie.goToAndStop(value, isFrame): 跳到某个时刻/帧并停止 lottie.goToAndPlay(value, isFrame): 跳到某个时刻/帧并播放 lottie.playSegments(segments, forceFlag): 以帧为单位,播放指定片段 lottie.setSubframe(flag): lottie.searchAnimations(): lottie.loadAnimation(): lottie.destroy(): lottie.registerAnimation(): lottie.setQuality():
事件 Events
onComplete: onLoopComplete: onEnterFrame: onSegmentStart:
钩子函数
complete: loopComplete: enterFrame: segmentStart: config_ready: 完成初始配置后 data_failed: 当无法加载动画的一部分时 loaded_images: 当所有图像加载成功或错误时 data_ready: 当动画的所有部分都已加载时 DOMLoaded: 将元素添加到DOM时 destroy: 当动画挂载对象销毁时
// 代码示例
lottieAnim.addEventListener('data_ready', () => {
//
});