mirror of
https://github.com/hi2shark/nazhua.git
synced 2026-01-11 22:50:42 +08:00
✨ 让AI写了一个烟花和新年快乐的灯笼
This commit is contained in:
parent
d3e549cad0
commit
3ede341f3d
@ -66,6 +66,7 @@ module.exports = {
|
||||
'no-param-reassign': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'no-unsafe-optional-chaining': 'off',
|
||||
'max-classes-per-file': 'off',
|
||||
'max-len': ['warn', 120],
|
||||
'vue/max-len': ['warn', 120],
|
||||
'object-property-newline': ['error', {
|
||||
|
||||
@ -5,6 +5,8 @@ window.$$nazhuaConfig = {
|
||||
// buyBtnText: '购买', // 购买按钮文案
|
||||
// customBackgroundImage: '', // 自定义的背景图片地址
|
||||
// lightBackground: true, // 启用了浅色系背景图,会强制关闭点点背景
|
||||
// showFireworks: true, // 是否显示烟花,建议开启浅色系背景
|
||||
// showLantern: true, // 是否显示灯笼
|
||||
// listServerItemTypeToggle: true, // 服务器列表项类型切换
|
||||
// listServerItemType: 'row', // 服务器列表项类型 card/row row列表模式移动端自动切换至card
|
||||
// listServerStatusType: 'progress', // 服务器状态类型--列表
|
||||
|
||||
158
src/components/fireworks.vue
Normal file
158
src/components/fireworks.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<canvas
|
||||
ref="canvas"
|
||||
class="fireworks-canvas"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
} from 'vue';
|
||||
|
||||
const canvas = ref(null);
|
||||
let ctx = null;
|
||||
let particles = [];
|
||||
let rockets = [];
|
||||
let animationFrameId = null;
|
||||
|
||||
class Particle {
|
||||
constructor(x, y, color) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.color = color;
|
||||
this.velocity = {
|
||||
x: (Math.random() - 0.5) * 8,
|
||||
y: (Math.random() - 0.5) * 12 - 8,
|
||||
};
|
||||
this.alpha = 1;
|
||||
this.decay = 0.02;
|
||||
}
|
||||
|
||||
draw() {
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
|
||||
ctx.fillStyle = `rgba(${this.color}, ${this.alpha})`;
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
update() {
|
||||
this.velocity.y += 0.1;
|
||||
this.x += this.velocity.x;
|
||||
this.y += this.velocity.y;
|
||||
this.alpha -= this.decay;
|
||||
}
|
||||
}
|
||||
|
||||
function createFirework(x, y) {
|
||||
const colors = [
|
||||
'255, 0, 0',
|
||||
'0, 255, 0',
|
||||
'0, 0, 255',
|
||||
'255, 255, 0',
|
||||
'255, 0, 255',
|
||||
'0, 255, 255',
|
||||
];
|
||||
const color = colors[Math.floor(Math.random() * colors.length)];
|
||||
for (let i = 0; i < 80; i += 1) {
|
||||
particles.push(new Particle(x, y, color));
|
||||
}
|
||||
}
|
||||
|
||||
class Rocket {
|
||||
constructor() {
|
||||
this.x = Math.random() * canvas.value.width;
|
||||
this.y = canvas.value.height;
|
||||
this.targetY = canvas.value.height * 0.5;
|
||||
this.speed = 15;
|
||||
this.trail = [];
|
||||
this.maxTrailLength = 5;
|
||||
}
|
||||
|
||||
draw() {
|
||||
// 绘制火箭尾迹
|
||||
ctx.beginPath();
|
||||
this.trail.forEach((pos, index) => {
|
||||
ctx.fillStyle = `rgba(255, 200, 0, ${index / this.trail.length})`;
|
||||
ctx.fillRect(pos.x, pos.y, 2, 2);
|
||||
});
|
||||
|
||||
// 绘制火箭本体
|
||||
ctx.fillStyle = 'rgba(255, 220, 0, 1)';
|
||||
ctx.fillRect(this.x, this.y, 3, 3);
|
||||
}
|
||||
|
||||
update() {
|
||||
this.trail.push({
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
});
|
||||
if (this.trail.length > this.maxTrailLength) {
|
||||
this.trail.shift();
|
||||
}
|
||||
this.y -= this.speed;
|
||||
if (this.y <= this.targetY) {
|
||||
createFirework(this.x, this.y);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function animate() {
|
||||
ctx.clearRect(0, 0, canvas.value.width, canvas.value.height);
|
||||
|
||||
// 更新和绘制火箭
|
||||
rockets = rockets.filter((rocket) => {
|
||||
rocket.draw();
|
||||
return rocket.update();
|
||||
});
|
||||
|
||||
// 更新和绘制粒子
|
||||
particles = particles.filter((particle) => particle.alpha > 0);
|
||||
particles.forEach((particle) => {
|
||||
particle.draw();
|
||||
particle.update();
|
||||
});
|
||||
|
||||
// 发射新的火箭
|
||||
if (Math.random() < 0.03 && rockets.length < 3) {
|
||||
rockets.push(new Rocket());
|
||||
}
|
||||
|
||||
animationFrameId = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
function resizeCanvas() {
|
||||
if (canvas.value) {
|
||||
canvas.value.width = window.innerWidth;
|
||||
canvas.value.height = window.innerHeight;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
ctx = canvas.value.getContext('2d');
|
||||
resizeCanvas();
|
||||
window.addEventListener('resize', resizeCanvas);
|
||||
animate();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', resizeCanvas);
|
||||
if (animationFrameId) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fireworks-canvas {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 8;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
257
src/components/lantern.vue
Normal file
257
src/components/lantern.vue
Normal file
@ -0,0 +1,257 @@
|
||||
<template>
|
||||
<div class="lantern-container">
|
||||
<div class="lantern-group right-group">
|
||||
<div class="deng-box">
|
||||
<div class="deng">
|
||||
<div class="xian" />
|
||||
<div class="deng-a">
|
||||
<div class="deng-b">
|
||||
<div class="deng-t">快</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shui shui-a">
|
||||
<div class="shui-c" />
|
||||
<div class="shui-b" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="deng-box deng-box--2">
|
||||
<div class="deng">
|
||||
<div class="xian" />
|
||||
<div class="deng-a">
|
||||
<div class="deng-b">
|
||||
<div class="deng-t">乐</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shui shui-a">
|
||||
<div class="shui-c" />
|
||||
<div class="shui-b" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lantern-group left-group">
|
||||
<div class="deng-box">
|
||||
<div class="deng">
|
||||
<div class="xian" />
|
||||
<div class="deng-a">
|
||||
<div class="deng-b">
|
||||
<div class="deng-t">新</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shui shui-a">
|
||||
<div class="shui-c" />
|
||||
<div class="shui-b" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="deng-box deng-box--2">
|
||||
<div class="deng">
|
||||
<div class="xian" />
|
||||
<div class="deng-a">
|
||||
<div class="deng-b">
|
||||
<div class="deng-t">年</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shui shui-a">
|
||||
<div class="shui-c" />
|
||||
<div class="shui-b" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 灯笼组件
|
||||
// 由AI生成
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lantern-container {
|
||||
position: fixed;
|
||||
top: calc(var(--layout-header-height) + 5px);
|
||||
width: 100%;
|
||||
z-index: 50;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.lantern-group {
|
||||
position: fixed;
|
||||
top: 70px;
|
||||
animation: swing 3s infinite ease-in-out;
|
||||
transform-origin: 50% -10px;
|
||||
|
||||
&.left-group {
|
||||
left: 40px;
|
||||
animation-delay: -1.5s;
|
||||
|
||||
.deng-box:nth-child(2) {
|
||||
margin-top: -12px;
|
||||
|
||||
.deng {
|
||||
animation: swing-extra 2s infinite ease-in-out;
|
||||
animation-delay: -0.5s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.right-group {
|
||||
right: 30px;
|
||||
animation-delay: -0.5s;
|
||||
|
||||
.deng-box:nth-child(2) {
|
||||
|
||||
.deng {
|
||||
animation: swing-extra 2s infinite ease-in-out;
|
||||
animation-delay: -1s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.deng {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.deng-box {
|
||||
position: relative;
|
||||
top: -40px;
|
||||
|
||||
&:first-child {
|
||||
z-index: 2;
|
||||
.deng {
|
||||
margin-bottom: 23px;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.deng {
|
||||
position: relative;
|
||||
width: 120px;
|
||||
height: 90px;
|
||||
margin: 50px;
|
||||
background: rgba(216, 0, 15, 0.8);
|
||||
border-radius: 50% 50%;
|
||||
transform-origin: 50% -100px;
|
||||
animation: swing 3s infinite ease-in-out;
|
||||
box-shadow: -5px 5px 50px 4px rgba(250, 108, 0, 1);
|
||||
}
|
||||
|
||||
.deng-a {
|
||||
width: 100px;
|
||||
height: 90px;
|
||||
background: rgba(216, 0, 15, 0.1);
|
||||
margin: 12px 8px 8px 10px;
|
||||
border-radius: 50% 50%;
|
||||
border: 2px solid #dc8f03;
|
||||
}
|
||||
|
||||
.deng-b {
|
||||
width: 45px;
|
||||
height: 90px;
|
||||
background: rgba(216, 0, 15, 0.1);
|
||||
margin: -4px 8px 8px 26px;
|
||||
border-radius: 50% 50%;
|
||||
border: 2px solid #dc8f03;
|
||||
}
|
||||
|
||||
.xian {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 60px;
|
||||
width: 2px;
|
||||
height: 20px;
|
||||
background: #dc8f03;
|
||||
}
|
||||
|
||||
.shui-a {
|
||||
position: relative;
|
||||
width: 5px;
|
||||
height: 20px;
|
||||
margin: -5px 0 0 59px;
|
||||
transform-origin: 50% -45px;
|
||||
background: #ffa500;
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
|
||||
.shui-b {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
left: -2px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #dc8f03;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.shui-c {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
left: -2px;
|
||||
width: 10px;
|
||||
height: 35px;
|
||||
background: #ffa500;
|
||||
border-radius: 0 0 0 5px;
|
||||
}
|
||||
|
||||
.deng:before {
|
||||
position: absolute;
|
||||
top: -7px;
|
||||
left: 29px;
|
||||
height: 12px;
|
||||
width: 60px;
|
||||
content: " ";
|
||||
display: block;
|
||||
z-index: 999;
|
||||
border-radius: 5px 5px 0 0;
|
||||
border: solid 1px #dc8f03;
|
||||
background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
|
||||
}
|
||||
|
||||
.deng:after {
|
||||
position: absolute;
|
||||
bottom: -7px;
|
||||
left: 10px;
|
||||
height: 12px;
|
||||
width: 60px;
|
||||
content: " ";
|
||||
display: block;
|
||||
margin-left: 20px;
|
||||
border-radius: 0 0 5px 5px;
|
||||
border: solid 1px #dc8f03;
|
||||
background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
|
||||
}
|
||||
|
||||
.deng-t {
|
||||
font-family: 华文行楷, Arial, Lucida Grande, Tahoma, sans-serif;
|
||||
font-size: 3.2rem;
|
||||
color: #ffd000;
|
||||
line-height: 85px;
|
||||
text-align: center;
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
@keyframes swing {
|
||||
0% { transform: rotate(-6deg) }
|
||||
50% { transform: rotate(6deg) }
|
||||
100% { transform: rotate(-6deg) }
|
||||
}
|
||||
|
||||
@keyframes swing-extra {
|
||||
0% { transform: rotate(-3deg) }
|
||||
50% { transform: rotate(3deg) }
|
||||
100% { transform: rotate(-3deg) }
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
.lantern-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -12,6 +12,12 @@
|
||||
<slot />
|
||||
<layout-footer />
|
||||
</div>
|
||||
<template v-if="config.nazhua.showFireworks">
|
||||
<fireworks />
|
||||
</template>
|
||||
<template v-if="config.nazhua.showLantern">
|
||||
<lantern />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -21,6 +27,8 @@
|
||||
*/
|
||||
import { computed } from 'vue';
|
||||
import config from '@/config';
|
||||
import Fireworks from '@/components/fireworks.vue';
|
||||
import Lantern from '@/components/lantern.vue';
|
||||
import LayoutHeader from './components/header.vue';
|
||||
import LayoutFooter from './components/footer.vue';
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user