diff --git a/js/about.js b/js/about.js index 4ce492b..70660b9 100644 --- a/js/about.js +++ b/js/about.js @@ -220,8 +220,15 @@ class DataManager { } init() { - setTimeout(() => this.fetchGithub(), 0); - setTimeout(() => this.fetchBlog(), 0); + // 使用requestIdleCallback或setTimeout优化初始化调用 + if ('requestIdleCallback' in window) { + requestIdleCallback(() => this.fetchGithub(), { timeout: 1000 }); + requestIdleCallback(() => this.fetchBlog(), { timeout: 1000 }); + } else { + // 降级到setTimeout,但稍后执行以避免阻塞 + setTimeout(() => this.fetchGithub(), 50); + setTimeout(() => this.fetchBlog(), 100); + } } // 创建带超时的fetch函数 @@ -336,10 +343,16 @@ class DataManager {
${escapeHtml(dShort)}
`; }); - const pc = $('#projects-container'); - pc.removeClass('fade-in'); - pc.html(html); - pc.addClass('fade-in'); + + // 使用requestAnimationFrame避免强制重排 + requestAnimationFrame(() => { + const pc = $('#projects-container'); + pc.removeClass('fade-in'); + requestAnimationFrame(() => { + pc.html(html); + pc.addClass('fade-in'); + }); + }); } // 从RSS获取博客文章 @@ -447,10 +460,16 @@ class DataManager {
${escapeHtml(cat)}
`; }); - const bc = $('#blog-container'); - bc.removeClass('fade-in'); - bc.html(html); - bc.addClass('fade-in'); + + // 使用requestAnimationFrame避免强制重排 + requestAnimationFrame(() => { + const bc = $('#blog-container'); + bc.removeClass('fade-in'); + requestAnimationFrame(() => { + bc.html(html); + bc.addClass('fade-in'); + }); + }); } } @@ -585,6 +604,7 @@ class UIManager { const themeObserver = new MutationObserver(() => { const newTheme = document.documentElement.getAttribute('data-theme'); const newLang = document.documentElement.getAttribute('data-lang'); + console.log('Theme/Language changed:', newTheme, newLang); // 延迟执行 setTimeout(() => { // 重新加载整个评论组件 @@ -738,78 +758,111 @@ class UIManager { } else { // PC: 3D Sphere container.classList.remove('mobile-scroll'); - container.__animToken = Date.now(); - const tags = []; - - techStack.forEach((item, index) => { - const el = document.createElement('a'); - el.className = 'tech-tag-3d'; - const colorClass = `tag-color-${item.gradientId || ((index % 10) + 1)}`; - el.classList.add(colorClass); - el.innerText = item.name; - el.style.border = 'none'; - container.appendChild(el); - tags.push({el, x: 0, y: 0, z: 0}); - }); - - // 动态半径,避免容器溢出 - let radius = Math.max(160, Math.min(container.offsetWidth, container.offsetHeight) / 2 - 24); - const dtr = Math.PI / 180; - let lasta = 1, lastb = 1; - let active = false, mouseX = 0, mouseY = 0; - - // Init positions - tags.forEach((tag, i) => { - let phi = Math.acos(-1 + (2 * i + 1) / tags.length); - let theta = Math.sqrt(tags.length * Math.PI) * phi; - tag.x = radius * Math.cos(theta) * Math.sin(phi); - tag.y = radius * Math.sin(theta) * Math.sin(phi); - tag.z = radius * Math.cos(phi); - }); - - container.onmouseover = () => active = true; - container.onmouseout = () => active = false; - container.onmousemove = (e) => { - let rect = container.getBoundingClientRect(); - mouseX = (e.clientX - (rect.left + rect.width / 2)) / 5; - mouseY = (e.clientY - (rect.top + rect.height / 2)) / 5; - }; - - const update = () => { - let a, b; - if (active) { - a = (-Math.min(Math.max(-mouseY, -200), 200) / radius) * 2; - b = (Math.min(Math.max(-mouseX, -200), 200) / radius) * 2; - } else { - a = lasta * 0.98; // Auto rotate - b = lastb * 0.98; + + // 使用防抖优化尺寸计算 + let resizeTimeout; + const updateContainerSize = () => { + if (resizeTimeout) { + clearTimeout(resizeTimeout); } - lasta = a; - lastb = b; - - if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01 && !active) a = 0.5; // Keep spinning slowly - - let sa = Math.sin(a * dtr), ca = Math.cos(a * dtr); - let sb = Math.sin(b * dtr), cb = Math.cos(b * dtr); - - tags.forEach(tag => { - let rx1 = tag.x, ry1 = tag.y * ca - tag.z * sa, rz1 = tag.y * sa + tag.z * ca; - let ry2 = ry1, rz2 = rx1 * -sb + rz1 * cb; - tag.x = rx1 * cb + rz1 * sb; - tag.y = ry2; - tag.z = rz2; - - let scale = (tag.z + radius) / (2 * radius) + 0.45; - scale = Math.min(Math.max(scale, 0.7), 1.15); - tag.el.style.opacity = (tag.z + radius) / (2 * radius) + 0.2; - tag.el.style.zIndex = parseInt(scale * 100); - let left = tag.x + container.offsetWidth / 2 - tag.el.offsetWidth / 2; - let top = tag.y + container.offsetHeight / 2 - tag.el.offsetHeight / 2; - tag.el.style.transform = `translate(${left}px, ${top}px) scale(${scale})`; - }); - requestAnimationFrame(update); + resizeTimeout = setTimeout(() => { + init3DSphere(); + }, 100); }; - update(); + + // 初始化3D球体 + const init3DSphere = () => { + // 清除之前的动画 + if (container.__animToken) { + cancelAnimationFrame(container.__animToken); + } + + // 清空容器 + container.innerHTML = ''; + + const tags = []; + + techStack.forEach((item, index) => { + const el = document.createElement('a'); + el.className = 'tech-tag-3d'; + const colorClass = `tag-color-${item.gradientId || ((index % 10) + 1)}`; + el.classList.add(colorClass); + el.innerText = item.name; + el.style.border = 'none'; + container.appendChild(el); + tags.push({el, x: 0, y: 0, z: 0}); + }); + + // 动态半径,避免容器溢出,使用防抖优化 + let radius = Math.max(160, Math.min(container.offsetWidth, container.offsetHeight) / 2 - 24); + const dtr = Math.PI / 180; + let lasta = 1, lastb = 1; + let active = false, mouseX = 0, mouseY = 0; + + // 初始化位置 + tags.forEach((tag, i) => { + let phi = Math.acos(-1 + (2 * i + 1) / tags.length); + let theta = Math.sqrt(tags.length * Math.PI) * phi; + tag.x = radius * Math.cos(theta) * Math.sin(phi); + tag.y = radius * Math.sin(theta) * Math.sin(phi); + tag.z = radius * Math.cos(phi); + }); + + container.onmouseover = () => active = true; + container.onmouseout = () => active = false; + container.onmousemove = (e) => { + let rect = container.getBoundingClientRect(); + mouseX = (e.clientX - (rect.left + rect.width / 2)) / 5; + mouseY = (e.clientY - (rect.top + rect.height / 2)) / 5; + }; + + const update = () => { + let a, b; + if (active) { + a = (-Math.min(Math.max(-mouseY, -200), 200) / radius) * 2; + b = (Math.min(Math.max(-mouseX, -200), 200) / radius) * 2; + } else { + a = lasta * 0.98; // Auto rotate + b = lastb * 0.98; + } + lasta = a; + lastb = b; + + if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01 && !active) a = 0.5; // Keep spinning slowly + + let sa = Math.sin(a * dtr), ca = Math.cos(a * dtr); + let sb = Math.sin(b * dtr), cb = Math.cos(b * dtr); + + // 批量更新样式以减少重排 + const fragment = document.createDocumentFragment(); + + tags.forEach(tag => { + let rx1 = tag.x, ry1 = tag.y * ca - tag.z * sa, rz1 = tag.y * sa + tag.z * ca; + let ry2 = ry1, rz2 = rx1 * -sb + rz1 * cb; + tag.x = rx1 * cb + rz1 * sb; + tag.y = ry2; + tag.z = rz2; + + let scale = (tag.z + radius) / (2 * radius) + 0.45; + scale = Math.min(Math.max(scale, 0.7), 1.15); + tag.el.style.opacity = (tag.z + radius) / (2 * radius) + 0.2; + tag.el.style.zIndex = parseInt(scale * 100); + let left = tag.x + container.offsetWidth / 2 - tag.el.offsetWidth / 2; + let top = tag.y + container.offsetHeight / 2 - tag.el.offsetHeight / 2; + tag.el.style.transform = `translate(${left}px, ${top}px) scale(${scale})`; + }); + + container.__animToken = requestAnimationFrame(update); + }; + + container.__animToken = requestAnimationFrame(update); + }; + + // 初始化3D球体 + init3DSphere(); + + // 监听窗口大小变化 + window.addEventListener('resize', updateContainerSize); } }