利用延迟实现复杂动画
在某些场景中需要将动画效果的进度使用 js 控制,如果是简单的动画,自是不难,但比较复杂的动画效果,使用 js 控制进度就比较麻烦了。比如下面的例子。
BOX
css
@keyframes move {
0% {
transform: translate(-100px, 0) rotate(0deg) scale(1);
}
50% {
transform: translate(0px, -30px) rotate(180deg) scale(1.5);
}
100% {
transform: translate(100px, 0) rotate(360deg) scale(1);
}
}
.box {
/* 加上 paused 使动画暂停 */
animation: move linear forwards 1s paused;
/*
这时候设置动画延迟为 -0.5s,是不是代表了动画已经进行了 0.5s,
那使用 js 控制动画延迟,不就控制了动画进度嘛。
*/
animation-delay: -0.5s;
}
如果有多个动画需要同时进度,可以将一个 css 变量,放在它们共同的父元素上,然后使用 js 控制这个 css 变量,这样就可以控制多个动画的进度了。
css
.box {
--delay: 0;
}
.box .animation1 {
animation: move1 linear forwards 1s paused;
animation-delay: var(--delay);
}
.box .animation2 {
animation: move2 linear forwards 1s paused;
animation-delay: var(--delay);
}
.box .animation3 {
animation: move3 linear forwards 1s paused;
animation-delay: var(--delay);
}
js
// 使用 js 控制 --delay 的值
boxDom.style.setProperty('--delay', `-${input.value}s`)
上面 demo 的代码如下:
Details
vue
<template>
<demo>
<div class="container">
<div class="animation-box flex-center">
<div class="box flex-center" ref="boxRef">BOX</div>
</div>
<div class="range-box flex-center">
<input
type="range"
min="0"
max="1"
step="0.01"
value="0.5"
ref="rangeRef"
@input="setDelay"
/>
</div>
</div>
</demo>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const boxRef = ref<HTMLDivElement>()
const rangeRef = ref<HTMLInputElement>()
const setDelay = () => {
boxRef.value?.style.setProperty('--delay', `-${rangeRef.value?.value}s`)
}
onMounted(setDelay)
</script>
<style scoped>
.container {
display: flex;
flex-direction: column;
align-items: center;
}
.animation-box {
margin-top: 20px;
height: 100px;
}
.box {
--delay: 0;
background-color: plum;
color: #fff;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 50px;
animation: move linear forwards 1s paused;
animation-delay: var(--delay);
}
.range-box {
margin-top: 1rem;
}
@keyframes move {
0% {
transform: translate(-100px, 0) rotate(0deg) scale(1);
}
50% {
transform: translate(0px, -20px) rotate(180deg) scale(1.5);
}
100% {
transform: translate(100px, 0) rotate(360deg) scale(1);
}
}
</style>
基于这个原理,可以将一些比较复杂的动画效果,通过 js 与滚动、加载进度等结合,实现一些比较炫酷的效果。