From 251ab53040edbd6c8710a37f02e583f690fc626e Mon Sep 17 00:00:00 2001 From: jack <251108449@qq.com> Date: Fri, 10 Jul 2026 15:13:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/withmind/assets/index.rem.css | 8 +- src/views/withmind/index.vue | 131 ++++++++++++++++-------- 2 files changed, 91 insertions(+), 48 deletions(-) diff --git a/src/views/withmind/assets/index.rem.css b/src/views/withmind/assets/index.rem.css index 20f68f6..7bd199c 100644 --- a/src/views/withmind/assets/index.rem.css +++ b/src/views/withmind/assets/index.rem.css @@ -203,8 +203,8 @@ html { } .box_3 { - background-color: rgba(25, 140, 255, 0.1); - border-radius: 18px; + /* 跟留资/安全一致:Slice_6 本身就是带缺角的"花瓣圆",不再额外垫浅色背景 + 圆角, + 否则浅色方块的四个圆角会透出来,被误认为是图标的"四个角" */ height: 1.814rem; width: 1.814rem; } @@ -277,8 +277,8 @@ html { } .block_2 { - background-color: rgba(255, 165, 39, 0.1); - border-radius: 18px; + /* 跟留资/安全一致:Slice_7 本身就是带缺角的"花瓣圆",不再额外垫浅色背景 + 圆角, + 否则浅色方块的四个圆角会透出来,被误认为是图标的"四个角" */ height: 1.814rem; width: 1.814rem; } diff --git a/src/views/withmind/index.vue b/src/views/withmind/index.vue index ac13a10..d198ff0 100644 --- a/src/views/withmind/index.vue +++ b/src/views/withmind/index.vue @@ -13,11 +13,11 @@ ./assets/img/slice-3-black-3x.png 3x " /> - 首页 - WithMind - Skills - 创作平台 - 模型网关 + 首页 + WithMind + Skills + 创作平台 + 模型网关
{ - /* 多个 entry 同时触发时,选"离顶部最近"的那一个作为 active */ - let best = null; - entries.forEach((entry) => { - if (entry.isIntersecting) { - if (!best || entry.boundingClientRect.top < best.boundingClientRect.top) { - best = entry; - } - } - }); - if (best) { - const id = best.target.id; - this.activeSection = id; - /* 同步 DOM class(因为 nav-link class 在外部 CSS 不可用,直接 toggle class) */ - navLinks.forEach((link) => { - if (link.getAttribute('data-spy') === id) { - link.classList.add('nav-active'); - } else { - link.classList.remove('nav-active'); - } - }); + // 单一 compute:section 顶 ≤ 视口高度的 50%(即"section 顶已过视口中线")就算激活 + // 这避开 about 段高度只有 ~144px 的边界问题: + // 点 skills 后,skills 顶 ≈ 260px < 375px(50% vh),platform 顶 > 375 → 选 skills + // 而 about 顶 ≈ 116px 也 ≤ 375,但 for 循环从上到下遍历,后一个 skills 覆盖前一个 + const compute = () => { + const scrollY = window.scrollY || window.pageYOffset || 0; + if (scrollY < 100) return 'top'; + const vh = window.innerHeight || document.documentElement.clientHeight; + const trigger = vh * 0.5; + let activeId = 'top'; + for (const id of sectionIds) { + const el = document.getElementById(id); + if (!el) continue; + const top = el.getBoundingClientRect().top; + if (top <= trigger) { + activeId = id; + } else { + break; } - }, - { - /* 视口上 30% / 下 40% 区域作为"激活区",让 section 滚到屏幕上半部时高亮 */ - rootMargin: '-30% 0px -40% 0px', - threshold: 0 } - ); + return activeId; + }; + + const update = () => { + // 抑制期(scrollTo 触发的平滑滚动过程中)不响应任何 update + if (Date.now() < (this.scrollSuppressUntil || 0)) return; + this.activeSection = compute(); + }; - sections.forEach((id) => { + // IO 兜底:section 进入/退出视口时重算 + const observer = new IntersectionObserver(() => update(), { + rootMargin: '0px 0px -50% 0px', + threshold: 0 + }); + sectionIds.forEach((id) => { const el = document.getElementById(id); if (el) observer.observe(el); }); + + let ticking = false; + window.addEventListener('scroll', () => { + if (ticking) return; + ticking = true; + requestAnimationFrame(() => { + ticking = false; + update(); + }); + }, { passive: true }); + + update(); }, scrollTo(id) { + // 1) 立即同步响应式状态(不等滚动动画) + this.activeSection = id; + // 2) 抑制一切自动 update 1.2s(覆盖 smooth 滚动动画) + const suppressMs = 1200; + this.scrollSuppressUntil = Date.now() + suppressMs; + // 3) 抑制期结束后,按当前 scrollY 校准一次 + setTimeout(() => { + this.scrollSuppressUntil = 0; // 解除抑制 + // 此时页面已稳定,scrollY 是最终值,compute() 必然正确 + this.activeSection = (() => { + const sectionIds = ['about', 'skills', 'platform', 'agent', 'media', 'gateway']; + const scrollY = window.scrollY || window.pageYOffset || 0; + if (scrollY < 100) return 'top'; + const vh = window.innerHeight || document.documentElement.clientHeight; + const trigger = vh * 0.5; + let activeId = 'top'; + for (const sid of sectionIds) { + const el = document.getElementById(sid); + if (!el) continue; + const top = el.getBoundingClientRect().top; + if (top <= trigger) { + activeId = sid; + } else { + break; + } + } + return activeId; + })(); + }, suppressMs); + // 4) 触发滚动 if (id === 'top') { window.scrollTo({ top: 0, behavior: 'smooth' }); return; } const el = document.getElementById(id); if (el) { - // 模型网关特殊处理:滚到网关模块底部,避免露出 footer 黑色背景 if (id === 'gateway') { - // 让网关底部对齐到"视口底部上方 250px"位置,留更大余量,footer 黑色背景完全在视口外 const rect = el.getBoundingClientRect(); const elBottom = rect.bottom + window.pageYOffset; const target = elBottom - window.innerHeight + 250; window.scrollTo({ top: Math.max(0, target), behavior: 'smooth' }); - return; + } else { + const top = el.getBoundingClientRect().top + window.pageYOffset - 260; + window.scrollTo({ top: top, behavior: 'smooth' }); } - // 顶部 fixed 导航栏高度 2.134rem(80px),加 180px 余量,共 260px 偏移,完全避开导航遮住 - const top = el.getBoundingClientRect().top + window.pageYOffset - 260; - window.scrollTo({ top: top, behavior: 'smooth' }); } } }