deotalandAi/apps/frontend/src/views/home/bg.vue

257 lines
5.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="page-container">
<!-- 1. 新增星空 Canvas 背景 -->
<canvas ref="starCanvas" class="star-bg"></canvas>
<!-- 原有内容包裹层 (确保内容在背景之上) -->
<div class="content-wrapper">
<slot></slot>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
// 模拟原有数据
const links = [{ name: 'Home' }, { name: 'Showcase' }, { name: 'Docs' }];
// --- 星空背景逻辑开始 ---
const starCanvas = ref(null);
let ctx = null;
let animationFrameId = null;
let stars = [];
// 配置参数
const config = {
starCount: 150, // 星星数量
speedBase: 0.2, // 基础流速
starColor: 'rgba(255, 255, 255, 0.8)',
};
class Star {
constructor(width, height) {
this.width = width;
this.height = height;
this.init(true);
}
init(randomY = false) {
this.x = Math.random() * this.width;
// 如果是初始化Y轴随机如果是重置从底部出现
this.y = randomY ? Math.random() * this.height : this.height;
this.size = Math.random() * 2; // 星星大小
this.speed = Math.random() * 0.5 + config.speedBase; // 移动速度
this.opacity = Math.random();
this.fadeDir = Math.random() > 0.5 ? 0.01 : -0.01; // 闪烁方向
}
update() {
// 向上流动效果 (y 减小)
this.y -= this.speed;
// 闪烁效果
this.opacity += this.fadeDir;
if (this.opacity >= 1 || this.opacity <= 0.2) {
this.fadeDir = -this.fadeDir;
}
// 边界检查:如果飞出顶部,重置到底部
if (this.y < 0) {
this.init(false);
}
}
draw(context) {
context.beginPath();
context.arc(this.x, this.y, this.size, 0, Math.PI * 2);
context.fillStyle = `rgba(255, 255, 255, ${this.opacity})`;
context.fill();
}
}
const initStars = () => {
const canvas = starCanvas.value;
if (!canvas) return;
ctx = canvas.getContext('2d');
const resize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 重置星星
stars = [];
for (let i = 0; i < config.starCount; i++) {
stars.push(new Star(canvas.width, canvas.height));
}
};
window.addEventListener('resize', resize);
resize(); // 初始化尺寸
const animate = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
stars.forEach(star => {
star.update();
star.draw(ctx);
});
animationFrameId = requestAnimationFrame(animate);
};
animate();
};
onMounted(() => {
initStars();
});
onUnmounted(() => {
cancelAnimationFrame(animationFrameId);
window.removeEventListener('resize', () => {});
});
// --- 星空背景逻辑结束 ---
</script>
<style scoped>
/* 1. 核心背景样式 */
.page-container {
position: relative;
min-height: 100vh;
/* 深空渐变背景 */
background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
color: #ffffff; /* 确保文字在深色背景上可见 */
}
.star-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0; /* 放在最底层 */
pointer-events: none; /* 让鼠标事件穿透 Canvas */
}
/* 2. 内容层样式 (确保内容浮在星空上) */
.content-wrapper {
position: relative;
z-index: 1; /* 放在 Canvas 之上 */
}
/* --- 以下是页面基础排版样式,按需调整 --- */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 40px;
}
.nav-links a {
color: #ccc;
margin: 0 15px;
text-decoration: none;
}
.nav-links a:hover { color: #fff; }
.hero {
text-align: center;
padding: 80px 20px;
}
.hero h1 {
font-size: 3.5rem;
margin-bottom: 10px;
background: linear-gradient(to right, #fff, #a5b4fc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.subtitle {
font-size: 1.2rem;
color: #94a3b8;
margin-bottom: 30px;
}
.section {
max-width: 1000px;
margin: 60px auto;
text-align: center;
background: rgba(255, 255, 255, 0.03); /* 轻微的磨砂玻璃背景 */
backdrop-filter: blur(10px);
padding: 40px;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.btn-primary {
background: #6366f1;
color: white;
border: none;
padding: 10px 24px;
border-radius: 30px;
cursor: pointer;
font-weight: bold;
transition: transform 0.2s;
}
.btn-primary:hover { background: #4f46e5; transform: scale(1.05); }
.btn-outline {
background: transparent;
color: white;
border: 1px solid rgba(255,255,255,0.3);
padding: 10px 24px;
border-radius: 30px;
margin-right: 10px;
cursor: pointer;
}
/* 流程图样式 */
.demo-flow {
display: flex;
justify-content: space-around;
align-items: center;
margin-top: 30px;
flex-wrap: wrap;
gap: 10px;
}
.flow-item {
background: rgba(0,0,0,0.3);
padding: 10px;
border-radius: 8px;
font-size: 0.9rem;
border: 1px solid #333;
}
.flow-item.active {
border-color: #6366f1;
box-shadow: 0 0 15px rgba(99, 102, 241, 0.3);
}
/* 卡片网格 */
.card-grid {
display: flex;
gap: 20px;
justify-content: center;
margin-top: 30px;
}
.card {
width: 200px;
background: rgba(255,255,255,0.05);
border-radius: 12px;
overflow: hidden;
}
.card-img-placeholder {
height: 120px;
background: #2d3748;
}
.card-info {
padding: 10px;
text-align: left;
}
.footer {
margin-top: 100px;
border-top: 1px solid rgba(255,255,255,0.1);
padding: 40px;
display: flex;
justify-content: space-between;
color: #64748b;
}
</style>