Browse Source

修改样式

main
jack 3 days ago
parent
commit
251ab53040
  1. 8
      src/views/withmind/assets/index.rem.css
  2. 131
      src/views/withmind/index.vue

8
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;
}

131
src/views/withmind/index.vue

@ -13,11 +13,11 @@
./assets/img/slice-3-black-3x.png 3x
"
/>
<span class="text_1 nav-link" data-spy="top" @click="scrollTo('top')">首页</span>
<span class="text_2 nav-link" data-spy="about" @click="scrollTo('about')">WithMind</span>
<span class="text_3 nav-link" data-spy="skills" @click="scrollTo('skills')">Skills</span>
<span class="text_4 nav-link" data-spy="platform" @click="scrollTo('platform')">创作平台</span>
<span class="text_5 nav-link" data-spy="gateway" @click="scrollTo('gateway')">模型网关</span>
<span class="text_1 nav-link" :class="{ 'nav-active': activeSection === 'top' }" data-spy="top" @click="scrollTo('top')">首页</span>
<span class="text_2 nav-link" :class="{ 'nav-active': activeSection === 'about' }" data-spy="about" @click="scrollTo('about')">WithMind</span>
<span class="text_3 nav-link" :class="{ 'nav-active': activeSection === 'skills' }" data-spy="skills" @click="scrollTo('skills')">Skills</span>
<span class="text_4 nav-link" :class="{ 'nav-active': activeSection === 'platform' }" data-spy="platform" @click="scrollTo('platform')">创作平台</span>
<span class="text_5 nav-link" :class="{ 'nav-active': activeSection === 'gateway' }" data-spy="gateway" @click="scrollTo('gateway')">模型网关</span>
<div class="group_3 flex-col"></div>
</div>
<img
@ -530,67 +530,110 @@ export default {
this.initScrollSpy();
},
methods: {
/* scroll-spy: IntersectionObserver section,
进入视口时把对应 nav 链接加 .nav-active (蓝色高亮) */
/* scroll-spy: Vue data(activeSection) nav-link :class
关键设计:点击 nav-link ,锁定 activeSection = id,屏蔽一切自动 update,
直到平滑滚动结束再校准这样彻底避免"点击瞬间设的 activeSection
IO/scroll 回调里的 compute() 改掉"的竞态 */
initScrollSpy() {
const sections = ['top', 'about', 'skills', 'platform', 'agent', 'media', 'gateway'];
const navLinks = document.querySelectorAll('.section_2 [data-spy]');
const sectionIds = ['about', 'skills', 'platform', 'agent', 'media', 'gateway'];
const observer = new IntersectionObserver(
(entries) => {
/* 多个 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' });
}
}
}

Loading…
Cancel
Save