前言
由于自己很喜欢ant motion的文字动画,vue里又找不到合适的封装好的,所以找到了几个参考的简单的封装了一个组件,适用于各种标题的文字入场动画,复制即用。
使用示例
<TextAnimate style="color: #1899ff; font-size: 50px" :mode="1">
this is a animate 1
</TextAnimate>
// 1000毫秒后执行动画
<TextAnimate style="color: #1899ff; font-size: 50px" :mode="1" :delay="1000">
this is a animate 1
</TextAnimate>
效果演示
入场动画1
入场动画2
入场动画3
入场动画4
入场动画5
vue2版本
<script>
export default {
props: {
/**
* 动画模式
*/
mode: {
type: Number, default: 1 },
/**
* 延迟动画时间 1000=1s
*/
delay: {
type: Number, default: 0 },
},
data() {
return {
text: "",
};
},
mounted() {
this.text = this.$slots.default[0].text;
},
computed: {
animateName() {
const animateClassData = {
1: "one",
2: "two",
3: "three",
4: "four",
5: "five",
};
return animateClassData[this.mode] || "one";
},
},
};
</script>
<template>
<div
class="animate"
:class="animateName"
:style="{ '--delay': `${delay / 1000}s` }"
>
<template v-for="item in text.split('')">
<span style="white-space: pre">{
{
item }}</span>
</template>
</div>
</template>
<style lang="scss" scoped>
.one {
span {
opacity: 0;
transform: translate(-150px, 0) scale(0.3);
animation: leftRight 0.5s forwards;
}
@keyframes leftRight {
40% {
transform: translate(50px, 0) scale(0.7);
opacity: 1;
}
60% {
}
80% {
transform: translate(0) scale(2);
opacity: 0;
}
100% {
transform: translate(0) scale(1);
opacity: 1;
}
}
}
.two {
span {
opacity: 0;
transform: translate(-150px, -50px) rotate(-180deg) scale(3);
animation: revolveScale 0.4s forwards;
}
@keyframes revolveScale {
60% {
transform: translate(20px, 20px) rotate(30deg) scale(0.3);
}
100% {
transform: translate(0) rotate(0) scale(1);
opacity: 1;
}
}
}
.three {
span {
opacity: 0;
transform: translate(200px, -100px) scale(2);
animation: ballDrop 0.3s forwards;
}
@keyframes ballDrop {
60% {
transform: translate(0, 20px) rotate(-180deg) scale(0.5);
}
100% {
transform: translate(0) rotate(0deg) scale(1);
opacity: 1;
}
}
}
.four {
span {
opacity: 0;
transform: rotate(-180deg) translate(150px, 0);
animation: twister 0.5s forwards;
}
@keyframes twister {
10% {
opacity: 1;
}
100% {
transform: rotate(0deg) translate(0);
opacity: 1;
}
}
}
.five {
span {
opacity: 0;
transform: translate(0, -100px) rotate(360deg) scale(0);
animation: revolveDrop 0.3s forwards;
}
@keyframes revolveDrop {
30% {
transform: translate(0, -50px) rotate(180deg) scale(1);
}
60% {
transform: translate(0, 20px) scale(0.8) rotate(0deg);
}
100% {
transform: translate(0) scale(1) rotate(0deg);
opacity: 1;
}
}
}
.animate {
span {
display: inline-block;
}
$n: 20;
@for $i from 1 through $n {
span:nth-of-type(#{
$i}) {
animation-delay: calc(0.05s * #{
$i - 1} + var(--delay));
}
}
}
</style>
vue3+ts版本
<script lang="ts" setup>
import {
computed, getCurrentInstance, onMounted, ref } from "vue";
const props = defineProps({
/**
* 动画模式
*/
mode: {
type: Number, default: 1 },
/**
* 延迟动画时间 1000=1s
*/
delay: {
type: Number, default: 0 },
});
const instance = getCurrentInstance();
const text = ref("");
onMounted(() => {
let arr = instance!.slots!.default?.()!;
text.value = arr[0].children as any;
});
/**
* 计算类名
*/
const animateName = computed(() => {
const animateClassData: Record<number, string> = {
1: "one",
2: "two",
3: "three",
4: "four",
5: "five",
};
return animateClassData[props.mode] || "one";
});
</script>
<template>
<div
class="animate"
:class="animateName"
:style="{ '--delay': `${delay / 1000}s` }"
>
<template v-for="item in text.split('')">
<span style="white-space: pre">{
{
item }}</span>
</template>
</div>
</template>
<style lang="scss" scoped>
.one {
span {
opacity: 0;
transform: translate(-150px, 0) scale(0.3);
animation: leftRight 0.5s forwards;
}
@keyframes leftRight {
40% {
transform: translate(50px, 0) scale(0.7);
opacity: 1;
}
60% {
}
80% {
transform: translate(0) scale(2);
opacity: 0;
}
100% {
transform: translate(0) scale(1);
opacity: 1;
}
}
}
.two {
span {
opacity: 0;
transform: translate(-150px, -50px) rotate(-180deg) scale(3);
animation: revolveScale 0.4s forwards;
}
@keyframes revolveScale {
60% {
transform: translate(20px, 20px) rotate(30deg) scale(0.3);
}
100% {
transform: translate(0) rotate(0) scale(1);
opacity: 1;
}
}
}
.three {
span {
opacity: 0;
transform: translate(200px, -100px) scale(2);
animation: ballDrop 0.3s forwards;
}
@keyframes ballDrop {
60% {
transform: translate(0, 20px) rotate(-180deg) scale(0.5);
}
100% {
transform: translate(0) rotate(0deg) scale(1);
opacity: 1;
}
}
}
.four {
span {
opacity: 0;
transform: rotate(-180deg) translate(150px, 0);
animation: twister 0.5s forwards;
}
@keyframes twister {
10% {
opacity: 1;
}
100% {
transform: rotate(0deg) translate(0);
opacity: 1;
}
}
}
.five {
span {
opacity: 0;
transform: translate(0, -100px) rotate(360deg) scale(0);
animation: revolveDrop 0.3s forwards;
}
@keyframes revolveDrop {
30% {
transform: translate(0, -50px) rotate(180deg) scale(1);
}
60% {
transform: translate(0, 20px) scale(0.8) rotate(0deg);
}
100% {
transform: translate(0) scale(1) rotate(0deg);
opacity: 1;
}
}
}
.animate {
span {
display: inline-block;
}
$n: 20;
@for $i from 1 through $n {
span:nth-of-type(#{
$i}) {
animation-delay: calc(0.05s * #{
$i - 1} + var(--delay));
}
}
}
</style>