在站上闲逛发现一个非常有意思的loading效果,跟着大佬仿写了一下Vue版本的。
https://blog.csdn.net/tianjian4592/article/details/44538605
直接放源码
<script setup>
import {ref, defineProps, watch} from "vue";
const props = defineProps({
isShow: {
type: Boolean,
default: false
},
leafNum: {
type: Number,
default: 5
} // 叶子数量
})
const isLoading = ref(false);
const progressNum = ref(0);
let progress;
let leafIntervalArr; // 保存leaf的定时器
watch(() => props.isShow, () => {
if (!props.isShow) {
// 触发关闭loading的时候延迟1.4s关闭,确保动画完整
progressNum.value = 100;
clearInterval(progress);
setTimeout(() => {
isLoading.value = false;
progressNum.value = 0;
// 结束动画后清空定时器
for (let i = 0; i < leafIntervalArr.length; i++) {
clearInterval(leafIntervalArr[i]);
}
}, 1400)
} else {
isLoading.value = true;
setInterval(() => {
if (progressNum.value <= 90) {
progressNum.value += 1;
}
}, 300);
setTimeout(() => {
randomLeaf();
}, 1000)
}
})
function randomLeaf() {
leafIntervalArr = new Array(props.leafNum);
for (let i = 0; i < props.leafNum; i++) {
let leaf = document.createElement('img');
leaf.className = 'leaf';
leaf.src = '/src/assets/images/loading/leaf.png';
leaf.alt = '叶子';
console.log(document.querySelector('.loading-progress'));
document.querySelector('.loading-progress').appendChild(leaf);
// 随机时间 1~5s
setTimeout(() => {
let activeLeaf = document.querySelectorAll('.leaf')[i];
let x = 260, y = 0;
activeLeaf.style.left = x + "px"; //初始坐标x
activeLeaf.style.top = y + "px"; //初始坐标y
leafIntervalArr[i] = setInterval(function () {
x = x - 5; //运动速度
y = Math.floor(Math.sin(x / 260 * 2 * Math.PI) * Math.floor(Math.random() * 10)) + Math.floor(Math.random() * 10); //运动的高度
if (x < 0) x = 260;
activeLeaf.style.left = x + "px";
activeLeaf.style.top = y + "px";
activeLeaf.style.transform = "rotate(" + Math.floor(Math.random() * 360) + "deg)";
}, 100);
}, Math.floor(Math.random() * 5000) + 1);
}
}
</script>
<template>
<transition>
<div class="loading-container" v-if="isLoading">
<div class="loading-text">loading...</div>
<div class="loading-wrapper">
<div class="loading-progress">
<div class="loading-progress-content" :style="{width: progressNum + '%'}"></div>
<!-- 叶子区域 -->
</div>
<div class="loading-fan fan-container">
<img class="fan" :class="{'fan-close':progressNum === 100}"
src="../../assets/images/loading/fan.png" alt="风扇">
<img class="max" v-if="progressNum === 100" src="../../assets/images/loading/100.png"
alt="100%">
</div>
</div>
</div>
</transition>
</template>
<style scoped>
.loading-container {
width: 100vw;
height: 100vh;
background-color: #E3B12FD0;
display: flex;
justify-content: center;
align-content: center;
align-items: center;
flex-wrap: wrap;
position: fixed;
top: 0;
right: 0;
}
.loading-text {
width: 100%;
text-align: center;
font-size: 20px;
font-weight: bold;
color: rgb(255, 168, 0);
margin-bottom: 20px;
}
.loading-wrapper {
width: 300px;
height: 48px;
background-color: #EED385D2;
border-radius: 24px;
position: relative;
z-index: 9;
}
.loading-progress {
width: 260px;
height: 36px;
background-color: #EED385D2;
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
margin: 6px 0 6px 6px;
overflow: hidden;
position: absolute;
top: 0;
left: 0;
}
.loading-progress-content {
width: 0;
height: 36px;
background-color: rgb(255, 168, 0);
transition: all 0.5s;
position: relative;
z-index: 9;
}
.loading-fan {
width: 48px;
height: 48px;
border-radius: 50%;
background-color: rgb(251, 205, 81);
border: 3px solid rgba(255, 255, 255, 0.6);
box-sizing: border-box;
position: absolute;
top: 0;
right: 0;
z-index: 9;
}
.fan {
width: 36px;
height: 36px;
position: absolute;
top: 3px;
left: 4px;
animation: spin 2s infinite linear;
}
.fan-close {
animation: fanClose 1.3s 1 linear;
animation-fill-mode: forwards;
}
.max {
width: 36px;
height: 36px;
position: absolute;
top: 3px;
left: 3px;
animation: maxFont 1.3s 1 linear;
animation-fill-mode: forwards;
}
@keyframes spin {
from {
transform: rotate(360deg);
}
to {
transform: rotate(0deg);
}
}
@keyframes fanClose {
from {
transform: rotate(360deg) scale(1);
}
to {
transform: rotate(0deg) scale(0);
}
}
@keyframes maxFont {
from {
transform: scale(0);
}
to {
transform: scale(1);
}
}
</style>
<style>
.leaf {
width: 15px;
height: 15px;
position: absolute;
top: 0;
left: 260px;
z-index: 5;
transition: all 0.01s;
}
</style>
核心思想:
- css动画旋转风扇,根据时间慢慢增加进度条的宽度。
- 生成最大数量的叶子,随机事件、随机振幅、随机旋转角度从右向左沿正弦曲线运动