列表动画
2024年9月26日大约 3 分钟
列表动画
由右向左
效果展示
由右向左
<template>
<div class="animation-list">
<div class="list-right-to-left">
<div
class="list-item"
v-for="(item, index) in listTotal"
:key="index"
:style="{ 'animation-delay': index * 0.1 + 's' }"
></div>
</div>
</div>
</template>
<script>
const { ref, onBeforeUnmount } = Vue;
export default {
setup() {
const listTotal = ref(0);
function startAnimation() {
listTotal.value = 0;
setTimeout(() => {
listTotal.value = 6;
}, 300);
}
setInterval(() => {
startAnimation();
}, 3000);
startAnimation();
onBeforeUnmount(() => {
clearInterval(interval);
});
return {
listTotal,
};
},
};
</script>
<style scoped>
@keyframes right-to-left {
from {
margin-left: 100%;
width: 0;
opacity: 0;
}
to {
margin-left: 0%;
width: 100%;
opacity: 1;
}
}
.animation-list {
display: flex;
justify-content: center;
position: relative;
.animation-btn {
width: 4em;
height: 28px;
position: absolute;
top: 10px;
left: 10px;
}
.list-right-to-left {
width: 200px;
height: 240px;
overflow: hidden;
.list-item {
height: 30px;
margin-bottom: 12px;
width: 200px;
background: LightSlateGray;
border-radius: 5px;
animation: right-to-left 0.6s ease-in-out;
animation-fill-mode: forwards;
opacity: 0;
}
}
}
</style>
实现思路
- 列表动画开始之前,先将列表元素隐藏
opacity: 0
; - 动画开始时,将列表元素移到可视区域外
margin-left: 100%
,并且将宽度设置为 0width: 0
; - 动画进行时,将列表元素移到可视区域
margin-left: 0%
,将透明度还原opacity: 1
,将宽度还原width: 100%
; - 动画结束时,保持最后一帧的状态
animation-fill-mode: forwards
。
实现代码
@keyframes right-to-left {
from {
margin-left: 100%;
width: 0;
opacity: 0;
}
to {
margin-left: 0%;
width: 100%;
opacity: 1;
}
}
由下向上
效果展示
由下向上
<template>
<div class="animation-list">
<div class="list-bottom-to-top">
<div
class="list-item"
v-for="(item, index) in listTotal"
:key="index"
:style="{ 'animation-delay': index * 0.1 + 's' }"
></div>
</div>
</div>
</template>
<script>
const { ref, onBeforeUnmount } = Vue;
export default {
setup() {
const listTotal = ref(0);
function startAnimation() {
listTotal.value = 0;
setTimeout(() => {
listTotal.value = 6;
}, 300);
}
const interval = setInterval(() => {
startAnimation();
}, 3000);
startAnimation();
onBeforeUnmount(() => {
clearInterval(interval);
});
return {
listTotal,
};
},
};
</script>
<style scoped>
@keyframes bottom-to-top {
from {
margin-top: 100%;
height: 0;
opacity: 0;
}
to {
margin-top: 0%;
height: 30px;
opacity: 1;
}
}
.animation-list {
display: flex;
justify-content: center;
position: relative;
.animation-btn {
width: 4em;
height: 28px;
position: absolute;
top: 10px;
left: 10px;
}
.list-bottom-to-top {
width: 200px;
height: 240px;
overflow: hidden;
.list-item {
height: 30px;
margin-bottom: 12px;
width: 200px;
background: LightSlateGray;
border-radius: 5px;
animation: bottom-to-top 0.6s ease-in-out;
animation-fill-mode: forwards;
opacity: 0;
}
}
}
</style>
实现思路
- 列表动画开始之前,先将列表元素隐藏
opacity: 0
; - 动画开始时,将列表元素移到可视区域外
margin-bottom: 100%
,并且将高度设置为 0height: 0
; - 动画进行时,将列表元素移到可视区域
margin-bottom: 0%
,将透明度还原opacity: 1
,将高度还原height: 30px
; - 动画结束时,保持最后一帧的状态
animation-fill-mode: forwards
。
实现代码
@keyframes bottom-to-top {
from {
margin-top: 100%;
height: 0;
opacity: 0;
}
to {
margin-top: 0%;
height: 30px;
opacity: 1;
}
}
交错
效果展示
交错
<template>
<div class="animation-list">
<div class="list-crossed">
<div
class="list-item"
v-for="(item, index) in listTotal"
:key="index"
:style="{
'animation-delay': index * 0.1 + 's',
'animation-name': index % 2 === 0 ? 'crossed-rb' : 'crossed-lb',
}"
></div>
</div>
</div>
</template>
<script>
const { ref, onBeforeUnmount } = Vue;
export default {
setup() {
const listTotal = ref(0);
function startAnimation() {
listTotal.value = 0;
setTimeout(() => {
listTotal.value = 6;
}, 300);
}
const interval = setInterval(() => {
startAnimation();
}, 3000);
startAnimation();
onBeforeUnmount(() => {
clearInterval(interval);
});
return {
listTotal,
};
},
};
</script>
<style scoped>
@keyframes crossed-rb {
from {
margin-left: 100%;
margin-top: 100%;
width: 0;
height: 0;
opacity: 0;
}
to {
margin-left: 0%;
margin-top: 0%;
width: 100%;
height: 30px;
opacity: 1;
}
}
@keyframes crossed-lb {
from {
margin-right: 100%;
margin-top: 100%;
width: 0;
height: 0;
opacity: 0;
}
to {
margin-right: 0%;
margin-top: 0%;
width: 100%;
height: 30px;
opacity: 1;
}
}
.animation-list {
display: flex;
justify-content: center;
position: relative;
.animation-btn {
width: 4em;
height: 28px;
position: absolute;
top: 10px;
left: 10px;
}
.list-crossed {
width: 200px;
height: 240px;
overflow: hidden;
.list-item {
height: 30px;
margin-bottom: 12px;
width: 200px;
background: LightSlateGray;
border-radius: 5px;
animation-duration: 0.6s;
animation-timing-function: ease-in-out;
animation-fill-mode: forwards;
opacity: 0;
}
}
}
</style>
实现思路
- 列表动画开始之前,先将列表元素隐藏
opacity: 0
; - 动画开始时,将列表元素移到可视区域外
margin-bottom: 100%; margin-top: 100%;
,并且将高度和宽度设置为 0height: 0; width: 0
; - 动画进行时,将列表元素移到可视区域
margin-bottom: 0%; margin-top: 0%
,将透明度还原opacity: 1
,将高度和宽度还原height: 30px; width: 100%
; - 动画结束时,保持最后一帧的状态
animation-fill-mode: forwards
。
实现代码
@keyframes crossed-rb {
from {
margin-left: 100%;
margin-top: 100%;
width: 0;
height: 0;
opacity: 0;
}
to {
margin-left: 0%;
margin-top: 0%;
width: 100%;
height: 30px;
opacity: 1;
}
}
@keyframes crossed-lb {
from {
margin-right: 100%;
margin-top: 100%;
width: 0;
height: 0;
opacity: 0;
}
to {
margin-right: 0%;
margin-top: 0%;
width: 100%;
height: 30px;
opacity: 1;
}
}