// 获取所有导航链接 const navLinks = document.querySelectorAll('.nav-link'); const sections = document.querySelectorAll('section'); // 点击导航链接时更新active类 navLinks.forEach(link => { link.addEventListener('click', function() { // 移除所有链接的active类 navLinks.forEach(l => l.classList.remove('active')); // 为当前点击的链接添加active类 this.classList.add('active'); }); }); // 滚动时更新active类 function updateActiveNavLink() { let currentSectionId = ''; sections.forEach(section => { const sectionTop = section.offsetTop; const sectionHeight = section.clientHeight; if (window.scrollY >= (sectionTop - 200) && window.scrollY < (sectionTop + sectionHeight - 200)) { currentSectionId = section.getAttribute('id'); } }); navLinks.forEach(link => { link.classList.remove('active'); if (link.getAttribute('href') === '#' + currentSectionId) { link.classList.add('active'); } }); } // 监听滚动事件,使用节流优化 let isScrolling; window.addEventListener('scroll', function() { // 清除之前的计时器 clearTimeout(isScrolling); // 设置一个新的计时器,在滚动停止后50毫秒执行 isScrolling = setTimeout(updateActiveNavLink, 50); }, false); // 页面加载时也执行一次 updateActiveNavLink(); window.addEventListener('load', function() { // 获取当前页面的域名或IP const currentHost = window.location.hostname; // 构建跳转URL (保持相同的协议和域名/IP) const portainerUrl = `${window.location.protocol}//${currentHost}:9000`; const giteaUrl = `${window.location.protocol}//${currentHost}:3000`; const grafanaUrl = `${window.location.protocol}//${currentHost}:3001`; const jenkinsUrl = `${window.location.protocol}//${currentHost}:9095`; const chatUrl = `${window.location.protocol}//${currentHost}/baseTalk`; // 设置链接的href属性和target属性,确保在新标签中打开 const portainerLink = document.getElementById('portainerLink'); const giteaLink = document.getElementById('giteaLink'); const grafanaLink = document.getElementById('grafanaLink'); const jenkinsLink = document.getElementById('jenkinsLink'); const chatLink = document.getElementById('chatLink'); if (portainerLink) { portainerLink.href = portainerUrl; portainerLink.target = '_blank'; } if (giteaLink) { giteaLink.href = giteaUrl; giteaLink.target = '_blank'; } if (grafanaLink) { grafanaLink.href = grafanaUrl; grafanaLink.target = '_blank'; } if (jenkinsLink) { jenkinsLink.href = jenkinsUrl; jenkinsLink.target = '_blank'; } if (chatLink) { chatLink.href = chatUrl; chatLink.target = '_blank'; } }); // 粒子背景效果 const canvas = document.getElementById('particleCanvas'); const ctx = canvas.getContext('2d'); // 设置画布大小 function setCanvasSize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } setCanvasSize(); window.addEventListener('resize', setCanvasSize); // 粒子类 class Particle { constructor() { this.x = Math.random() * canvas.width; this.y = Math.random() * canvas.height; this.size = Math.random() * 2 + 0.5; this.speedX = Math.random() * 0.5 - 0.25; this.speedY = Math.random() * 0.5 - 0.25; this.color = Math.random() > 0.5 ? '#00ffeb' : '#ff6b35'; this.alpha = Math.random() * 0.7 + 0.3; } update() { this.x += this.speedX; this.y += this.speedY; // 边界检测 if (this.x < 0 || this.x > canvas.width) this.speedX *= -1; if (this.y < 0 || this.y > canvas.height) this.speedY *= -1; } draw() { ctx.fillStyle = `${this.color}${Math.floor(this.alpha * 255).toString(16)}`; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); } } // 创建粒子数组 const particles = []; const particleCount = 150; for (let i = 0; i < particleCount; i++) { particles.push(new Particle()); } // 连接粒子效果 function connectParticles() { for (let a = 0; a < particles.length; a++) { for (let b = a; b < particles.length; b++) { const dx = particles[a].x - particles[b].x; const dy = particles[a].y - particles[b].y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100) { // 根据粒子颜色决定连接线颜色 const color = particles[a].color === '#00ffeb' && particles[b].color === '#00ffeb' ? '#00ffeb' : particles[a].color === '#ff6b35' && particles[b].color === '#ff6b35' ? '#ff6b35' : '#e0e0e0'; ctx.beginPath(); ctx.strokeStyle = `rgba(${hexToRgb(color).r}, ${hexToRgb(color).g}, ${hexToRgb(color).b}, ${0.1 - distance/1000})`; ctx.lineWidth = 0.5; ctx.moveTo(particles[a].x, particles[a].y); ctx.lineTo(particles[b].x, particles[b].y); ctx.stroke(); } } } } // 十六进制颜色转RGB function hexToRgb(hex) { // 移除#如果存在 hex = hex.replace('#', ''); // 解析RGB值 const r = parseInt(hex.substring(0, 2), 16); const g = parseInt(hex.substring(2, 4), 16); const b = parseInt(hex.substring(4, 6), 16); return { r, g, b }; } // 系统状态图表 const ctxChart = document.getElementById('systemChart').getContext('2d'); // 生成随机数据 function generateData() { return Array.from({length: 20}, () => Math.floor(Math.random() * 80) + 20); } const cpuData = generateData(); const memoryData = generateData(); const networkData = generateData(); const labels = Array.from({length: 20}, (_, i) => i); // 根据主题获取图表颜色配置 function getChartColors(theme) { switch(theme) { case 'cyber': return { cpuBorder: '#ff6b35', cpuBackground: 'rgba(255, 107, 53, 0.1)', memoryBorder: '#00ffeb', memoryBackground: 'rgba(0, 255, 235, 0.1)', networkBorder: '#e0e0e0', networkBackground: 'rgba(224, 224, 224, 0.1)', gridColor: 'rgba(255, 255, 255, 0.05)', tickColor: 'rgba(224, 224, 224, 0.7)', legendColor: 'rgba(224, 224, 224, 0.9)', tooltipBackground: 'rgba(10, 14, 23, 0.8)', tooltipText: '#e0e0e0', tooltipBorder: 'rgba(255, 255, 255, 0.1)' }; case 'minimal': return { cpuBorder: '#333333', // 深灰色 cpuBackground: 'rgba(51, 51, 51, 0.1)', memoryBorder: '#666666', // 中灰色 memoryBackground: 'rgba(102, 102, 102, 0.1)', networkBorder: '#999999', // 浅灰色 networkBackground: 'rgba(153, 153, 153, 0.1)', gridColor: 'rgba(0, 0, 0, 0.05)', tickColor: 'rgba(224, 224, 224, 0.7)', legendColor: 'rgba(224, 224, 224, 0.9)', tooltipBackground: 'rgba(10, 14, 23, 0.8)', tooltipText: '#e0e0e0', tooltipBorder: 'rgba(0, 0, 0, 0.1)' }; case 'gallery': return { cpuBorder: '#ff758f', // 粉色 cpuBackground: 'rgba(255, 117, 143, 0.1)', memoryBorder: '#4dabf7', // 蓝色 memoryBackground: 'rgba(77, 171, 247, 0.1)', networkBorder: '#333333', networkBackground: 'rgba(51, 51, 51, 0.1)', gridColor: 'rgba(0, 0, 0, 0.05)', tickColor: 'rgba(224, 224, 224, 0.7)', legendColor: 'rgba(224, 224, 224, 0.9)', tooltipBackground: 'rgba(10, 14, 23, 0.8)', tooltipText: '#e0e0e0', tooltipBorder: 'rgba(77, 171, 247, 0.2)' }; default: return getChartColors('cyber'); } } // 创建图表 function createSystemChart(theme) { const colors = getChartColors(theme); return new Chart(ctxChart, { type: 'line', data: { labels: labels, datasets: [ { label: 'CPU 使用率 (%)', data: cpuData, borderColor: colors.cpuBorder, backgroundColor: colors.cpuBackground, tension: 0.4, fill: true, borderWidth: 2, pointRadius: 0, // 设置为0移除圆点 pointHoverRadius: 0 // 设置为0移除悬停圆点 }, { label: '内存使用率 (%)', data: memoryData, borderColor: colors.memoryBorder, backgroundColor: colors.memoryBackground, tension: 0.4, fill: true, borderWidth: 2, pointRadius: 0, // 设置为0移除圆点 pointHoverRadius: 0 // 设置为0移除悬停圆点 }, { label: '网络流量 (MB/s)', data: networkData, borderColor: colors.networkBorder, backgroundColor: colors.networkBackground, tension: 0.4, fill: true, borderWidth: 2, pointRadius: 0, // 设置为0移除圆点 pointHoverRadius: 0 // 设置为0移除悬停圆点 } ] }, options: { responsive: true, maintainAspectRatio: false, scales: { x: { grid: { color: colors.gridColor }, ticks: { color: colors.tickColor } }, y: { grid: { color: colors.gridColor }, ticks: { color: colors.tickColor }, beginAtZero: true, max: 100 } }, plugins: { legend: { labels: { color: colors.legendColor } }, tooltip: { mode: 'index', intersect: false, backgroundColor: colors.tooltipBackground, titleColor: colors.tooltipText, bodyColor: colors.tooltipText, borderColor: colors.tooltipBorder, borderWidth: 1, boxPadding: 10, bodyPadding: 10 } }, interaction: { mode: 'nearest', axis: 'x', intersect: false }, animations: { tension: { duration: 1000, easing: 'linear' } } } }); } // 初始化图表 let systemChart = createSystemChart(document.body.getAttribute('data-theme') || 'cyber'); // 更新图表数据 function updateChart() { cpuData.shift(); cpuData.push(Math.floor(Math.random() * 80) + 20); memoryData.shift(); memoryData.push(Math.floor(Math.random() * 80) + 20); networkData.shift(); networkData.push(Math.floor(Math.random() * 50) + 5); systemChart.update(); } // 每3秒更新一次图表 setInterval(updateChart, 3000); // 导航栏滚动效果 window.addEventListener('scroll', () => { const navbar = document.querySelector('.navbar'); if (window.scrollY > 50) { navbar.style.padding = '15px 0'; navbar.style.boxShadow = '0 5px 15px rgba(0, 0, 0, 0.3)'; } else { navbar.style.padding = '20px 0'; navbar.style.boxShadow = 'none'; } }); // 服务卡片悬停效果增强 const serviceCards = document.querySelectorAll('.service-card'); serviceCards.forEach(card => { card.addEventListener('mouseenter', () => { card.style.transform = 'translateY(-10px) scale(1.02)'; card.style.boxShadow = '0 15px 30px rgba(0, 0, 0, 0.5), 0 0 15px rgba(0, 255, 235, 0.3)'; }); card.addEventListener('mouseleave', () => { card.style.transform = 'translateY(0) scale(1)'; card.style.boxShadow = '0 8px 32px 0 rgba(0, 0, 0, 0.37)'; }); }); // 平滑滚动和链接处理 document.querySelectorAll('a').forEach(anchor => { anchor.addEventListener('click', function (e) { const href = this.getAttribute('href'); const target = this.getAttribute('target'); // 如果已经设置了target="_blank",让浏览器正常处理跳转 if (target === '_blank') { return; } // 检查是否是有效的页面内ID选择器(以#开头且不是URL) if (href && href.startsWith('#') && href.length > 1 && !href.includes('://')) { const targetElement = document.querySelector(href); if (targetElement) { // 只在找到目标元素时阻止默认行为 e.preventDefault(); targetElement.scrollIntoView({ behavior: 'smooth' }); } // 如果找不到目标元素,不阻止默认行为 } else if (href === '#') { // 处理 href="#" 的情况,滚动到页面顶部 e.preventDefault(); window.scrollTo({ top: 0, behavior: 'smooth' }); } // 对于URL链接等其他情况,如果没有设置target="_blank",添加它 else if (href && !href.startsWith('#') && (href.includes('://') || href.startsWith('//'))) { // 不阻止默认行为,让浏览器处理带target="_blank"的跳转 this.target = '_blank'; } }); }); // 视觉风格切换器功能 const themeToggle = document.getElementById('themeToggle'); const themeMenu = document.getElementById('themeMenu'); const themeOptions = document.querySelectorAll('.theme-option'); const particleCanvas = document.getElementById('particleCanvas'); // 在animate()函数前添加animationId变量声明 let animationId; function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); for (let i = 0; i < particles.length; i++) { particles[i].update(); particles[i].draw(); } // 连接相近的粒子 connectParticles(); animationId = requestAnimationFrame(animate); } // 页面加载完成后执行 window.addEventListener('load', () => { // 添加页面加载动画 document.body.classList.add('loaded'); // 初始化粒子颜色 const initialTheme = document.body.getAttribute('data-theme') || 'cyber'; updateParticleColors(initialTheme); // 初始化动态效果 toggleDynamicEffects(initialTheme); // 启动动画(确保在DOM加载完成后) animate(); }); // 切换菜单显示/隐藏 themeToggle.addEventListener('click', () => { themeMenu.classList.toggle('active'); }); // 点击页面其他区域关闭菜单 document.addEventListener('click', (e) => { if (!themeToggle.contains(e.target) && !themeMenu.contains(e.target)) { themeMenu.classList.remove('active'); } }); // 主题切换功能 themeOptions.forEach(option => { option.addEventListener('click', () => { // 移除所有选项的active类 themeOptions.forEach(opt => opt.classList.remove('active')); // 为当前选项添加active类 option.classList.add('active'); // 获取主题值 const theme = option.getAttribute('data-theme'); // 设置body的data-theme属性 document.body.setAttribute('data-theme', theme); // 更新图标 updateThemeIcon(theme); // 更新粒子背景颜色 updateParticleColors(theme); // 切换动态效果 toggleDynamicEffects(theme); // 关闭菜单 themeMenu.classList.remove('active'); }); }); // 更新主题图标 function updateThemeIcon(theme) { const icon = themeToggle.querySelector('i'); switch(theme) { case 'cyber': icon.className = 'fas fa-bolt'; break; case 'minimal': icon.className = 'fas fa-moon'; break; case 'gallery': icon.className = 'fas fa-palette'; break; } } // 更新粒子背景颜色 function updateParticleColors(theme) { let primaryColor, secondaryColor; let particleVisibility = 'visible'; switch(theme) { case 'cyber': primaryColor = '#00ffeb'; secondaryColor = '#ff6b35'; particleVisibility = 'visible'; break; case 'minimal': primaryColor = '#6c757d'; secondaryColor = '#6c757d'; particleVisibility = 'hidden'; break; case 'gallery': primaryColor = '#ff758f'; // 粉色 secondaryColor = '#4dabf7'; // 蓝色 particleVisibility = 'visible'; break; } // 设置粒子可见性 if (particleCanvas) { particleCanvas.style.visibility = particleVisibility; } particles.forEach(particle => { particle.color = Math.random() > 0.5 ? primaryColor : secondaryColor; }); } // 切换动态效果 function toggleDynamicEffects(theme) { // 暂停/恢复粒子动画 if (theme === 'minimal') { if (animationId) { cancelAnimationFrame(animationId); animationId = null; } // 移除视差滚动效果 document.querySelectorAll('[data-parallax]').forEach(el => { el.style.transform = 'translateY(0)'; el.removeAttribute('data-parallax'); el.setAttribute('data-parallax-disabled', 'true'); }); // 移除悬停效果 document.querySelectorAll('.service-card, .thought-card, .friend-card, .lab-card').forEach(card => { card.style.transform = 'none'; card.style.boxShadow = 'none'; }); } else { // 恢复粒子动画 if (!animationId) { animate(); } // 恢复视差滚动效果 document.querySelectorAll('[data-parallax-disabled]').forEach(el => { el.setAttribute('data-parallax', '0.3'); el.removeAttribute('data-parallax-disabled'); }); } // 添加以下代码来更新图表颜色 // 销毁旧图表 if (systemChart) { systemChart.destroy(); } // 使用新主题创建新图表 systemChart = createSystemChart(theme); }