前端动画实现
最近实在太忙了,没有时间写博客,贴一波最近学的动画代码敷衍一下
演示地址
动画演示
实现下述动画效果:
- 控制小球匀速移动
- 控制小球暂停
- 控制小球动画终止
- 控制小球动画倒序播放
- 控制小球速度
<script>
function animate({easing,draw,duration}){//动画函数
let start = performance.now();
let speed = 1 //倍速
//动画状态
let state = 'cancle';
let condition = 'order'
//动画播放进度
let timeFraction = 0
let pauseTimeFraction = 0;
const run = function(){
requestAnimationFrame(function animate(time){
if( state === 'pause'){
pauseTimeFraction = timeFraction;
start = performance.now();
}
else{
console.log("开始执行动画了");
let tmpProgress = ((time - start) / duration) * speed;
if(condition === 'reverse'){
tmpProgress = -tmpProgress
}
timeFraction = pauseTimeFraction + tmpProgress
if(timeFraction > 1) timeFraction = 1;
if(timeFraction < 0) timeFraction = 0;
let progress = easing(timeFraction);
draw(progress);
if(state === 'cancle'){
return
}else{
if(condition === 'order'){
if(timeFraction < 1){
requestAnimationFrame(animate);
}else{
cancle()
}
}else{
if(timeFraction > 0){
requestAnimationFrame(animate);
}else{
cancle()
}
}
}
}
})
}
// run()
return{
play(){
console.log("执行动画");
state = 'run'
timeFraction = pauseTimeFraction
start = performance.now();
run()
},
pause(){
console.log("暂停动画");
state = 'pause'
start = performance.now();
},
cancle(){
console.log("终止动画");
state = 'cancle'
condition = 'order'
speed = 1
timeFraction = 0
pauseTimeFraction = 0
start = performance.now();
run()
},
reverse(){
console.log("倒序执行动画");
condition = 'reverse'
pauseTimeFraction = timeFraction
start = performance.now();
},
playRate(Speed){
console.log("切换动画倍速");
speed = Speed
start = performance.now();
pauseTimeFraction = timeFraction
run()
}
}
}
const ball = document.querySelector('.ball'); //获取球的dom节点
const draw = (progress) => {//画笔函数 使得球水平匀速运动
ball.style.transform = `translate(${progress}px,0)` //核心代码,控制球的偏移量
}
const animation = animate({
duration:2000,
easing(timeFraction){
return timeFraction*200;
},
draw
})
//通过使用闭包的特性控制函数内部变量
const play = () => {
animation.play()
}
const pause = () => {//暂停动画
animation.pause()
}
const cancle = () => {//暂停动画
animation.cancle()
}
const reverse = () => {//倒序执行动画
animation.reverse()
}
const playRate = (speed) => {//切换动画倍速
animation.playRate(speed)
}
</script>
完整代码如下
html
完整代码如下
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="container">
<div class="axisX"></div>
<div class="axisY"></div>
<div class="ball"></div>
<div class="button-container">
<div class="button" onClick="play()">play</div>
<div class="button" onClick="pause()">pause</div>
<div class="button" onClick="cancle()">cancle</div>
<div class="button" onClick="reverse()">reverse</div>
<div class="button" onClick="playRate(2)">切换2倍速</div>
</div>
</div>
</body>
</html>
function animate({easing,draw,duration}){//动画函数
let start = performance.now();
let speed = 1 //倍速
//动画状态
let state = 'cancle';
let condition = 'order'
//动画播放进度
let timeFraction = 0
let pauseTimeFraction = 0;
const run = function(){
requestAnimationFrame(function animate(time){
if( state === 'pause'){
pauseTimeFraction = timeFraction;
start = performance.now();
}
else{
console.log("开始执行动画了");
let tmpProgress = ((time - start) / duration) * speed;
if(condition === 'reverse'){
tmpProgress = -tmpProgress
}
timeFraction = pauseTimeFraction + tmpProgress
if(timeFraction > 1) timeFraction = 1;
if(timeFraction < 0) timeFraction = 0;
let progress = easing(timeFraction);
draw(progress);
if(state === 'cancle'){
return
}else{
if(condition === 'order'){
if(timeFraction < 1){
requestAnimationFrame(animate);
}else{
cancle()
}
}else{
if(timeFraction > 0){
requestAnimationFrame(animate);
}else{
cancle()
}
}
}
}
})
}
// run()
return{
play(){
console.log("执行动画");
state = 'run'
timeFraction = pauseTimeFraction
start = performance.now();
run()
},
pause(){
console.log("暂停动画");
state = 'pause'
start = performance.now();
},
cancle(){
console.log("终止动画");
state = 'cancle'
condition = 'order'
speed = 1
timeFraction = 0
pauseTimeFraction = 0
start = performance.now();
run()
},
reverse(){
console.log("倒序执行动画");
condition = 'reverse'
pauseTimeFraction = timeFraction
start = performance.now();
play()
},
playRate(Speed){
console.log("切换动画倍速");
speed = Speed
start = performance.now();
pauseTimeFraction = timeFraction
run()
}
}
}
const ball = document.querySelector('.ball'); //获取球的dom节点
const draw = (progress) => {//画笔函数 使得球水平匀速运动
ball.style.transform = `translate(${progress}px,0)` //核心代码,控制球的偏移量
}
const animation = animate({
duration:2000,
easing(timeFraction){
return timeFraction*200;
},
draw
})
//通过使用闭包的特性控制函数内部变量
const play = () => {
animation.play()
}
const pause = () => {//暂停动画
animation.pause()
}
const cancle = () => {//暂停动画
animation.cancle()
}
const reverse = () => {//倒序执行动画
animation.reverse()
}
const playRate = (speed) => {//切换动画倍速
animation.playRate(speed)
}
body {
margin: 0;
padding: 0;
}
#container {
position: absolute;
width: 100%;
height: 100vh;
}
.axisX {
height: 2px;
background: black;
width: 100%;
position: absolute;
top: 60%;
transform: translate(0, -1px);
}
.axisY {
width: 2px;
background: black;
height: 100vh;
position: absolute;
left: 50%;
transform: translate(-1px, 0);
}
.ball {
position: absolute;
width: 40px;
height: 40px;
border-radius: 20px;
background: red;
top: calc(60% - 20px);
left: calc(50% - 20px);
}
.ball::before {
content: "";
position: absolute;
left: 10px;
top: 10px;
background: yellow;
width: 10px;
height: 10px;
border-radius: 5px;
}
.button-container {
position: absolute;
bottom: 50px;
left: 100px;
}
.button {
cursor: pointer;
border: 2px solid black;
padding: 10px 20px;
font-size: 20px;
display: inline-block;
}
.button:hover {
background: gray;
}