雪花组件(vue3)

3,566 阅读1分钟
  • 效果展示 image.png
  • 组件代码
<template>
	<div class="snow-container">
		<!-- 雪花元素 -->
		<div 
			v-for="(snowflake, index) in snowflakes" 
			:key="snowflake.id" 
			:style="snowflake.style" 
			class="snowflake"
		></div>
	</div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

// 雪花数组
const snowflakes = ref([]);
let interval;

// 生成唯一ID
const generateId = () => {
	return Date.now() + Math.random();
};

// 创建雪花
function createSnowflake() {
	const id = generateId();
	const horizontalMove = (Math.random() - 0.5) * 100; // 随机左右漂移范围
	const animationName = Math.random() > 0.5 ? 'fall linear infinite' : `fall linear infinite, sway ${Math.random() * 4 + 2}s ease-in-out infinite alternate`;
	
	const snowflake = {
		id,
		style: {
			left: `${Math.random() * 100}%`, // 随机水平位置
			fontSize: `${Math.random() * 20 + 10}px`, // 随机大小(10px - 30px)
			animationDuration: `${Math.random() * 5 + 5}s`, // 随机动画时长(5s - 10s)
			animationDelay: `${Math.random() * 5}s`, // 随机动画延迟(0s - 5s)
			// 随机决定是否添加左右漂移效果
			animation: animationName
		},
	};
	
	snowflakes.value.push(snowflake);

	// 雪花飘落后移除,使用parseFloat解析动画时长
	setTimeout(() => {
		snowflakes.value = snowflakes.value.filter(item => item.id !== id);
	}, parseFloat(snowflake.style.animationDuration) * 1000);
}

// 定时生成雪花,限制总数以优化性能
onMounted(() => {
	// 每100ms生成一个雪花,但限制总数不超过200个
	interval = setInterval(() => {
		if (snowflakes.value.length < 200) {
			createSnowflake();
		}
	}, 100);
});

// 组件卸载时清除定时器
onUnmounted(() => {
	if (interval) {
		clearInterval(interval);
	}
	// 清空雪花数组
	snowflakes.value = [];
});
</script>

<style scoped>
.snow-container {
	position: relative;
	width: 100%;
	height: 100vh;
	overflow: hidden;
	background: url(http://mms0.baidu.com/it/u=4004612276,3764837023&fm=253&app=138&f=JPEG?w=889&h=500) no-repeat;
    background-size: 100% 100%;
	/* background: #0a2a43; */
}

.snowflake {
	position: absolute;
	top: -5%;
	color: #fff; /* 雪花颜色 */
	user-select: none; /* 禁止选中 */
	text-shadow: 0 0 8px rgba(255, 255, 255, 0.7); /* 添加发光效果 */
	will-change: transform; /* 优化动画性能 */
	opacity: 0.8; /* 稍微透明 */
}

@keyframes fall {
	0% {
		transform: translateY(0) rotate(0deg);
		opacity: 0.8;
	}
	100% {
		transform: translateY(100vh) rotate(360deg);
		opacity: 0.2;
	}
}

/* 水平摆动动画 */
@keyframes sway {
	0% {
		transform: translateX(0) translateY(0) rotate(0deg);
	}
	100% {
		transform: translateX(50px) translateY(100vh) rotate(360deg);
	}
}
</style>





  • 使用
<div class="login-container">
       <SnowModule />
</div>
import SnowModule from './component/snow.vue'