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' });
}
}
}