睿能科技
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

175 lines
4.8 KiB

import "./common.js";
//#region js/about-history.js
function setActiveNav() {
const pageNav = document.querySelector("[data-nav]")?.getAttribute("data-nav");
if (!pageNav) return;
document.querySelectorAll(".site-header__nav a").forEach((link) => {
const active = link.textContent.trim().startsWith(pageNav);
link.classList.toggle("is-active", active);
});
}
function getHeaderOffset() {
const header = document.querySelector(".site-header");
const h = header ? header.offsetHeight : 88;
const isMobile = window.matchMedia("(max-width: 992px)").matches;
if (isMobile) {
const years = document.querySelector(".ah-nav__years");
const yearsH = years ? years.offsetHeight : 60;
return h + yearsH + 12;
}
return h + 24;
}
function clamp(n, min, max) {
return Math.min(max, Math.max(min, n));
}
function initHistorySpy() {
const root = document.querySelector("[data-ah-spy]");
if (!root) return;
const navItems = Array.from(root.querySelectorAll(".ah-nav__item[data-year]"));
const blocks = Array.from(root.querySelectorAll(".ah-block[data-year]"));
const yearsWrap = root.querySelector(".ah-nav__years");
const rail = root.querySelector(".ah-nav__rail");
const indicator = root.querySelector(".ah-nav__indicator");
if (!navItems.length || !blocks.length) return;
let activeYear = navItems[0].dataset.year;
let clicking = false;
let rafId = 0;
const isMobile = () => window.matchMedia("(max-width: 992px)").matches;
const syncRailHeight = () => {
if (!yearsWrap || !rail || isMobile()) return;
rail.style.height = `${yearsWrap.offsetHeight}px`;
};
const setProgress = (progress) => {
if (!indicator) return;
indicator.style.transform = `scaleY(${clamp(progress, 0.04, 1)})`;
};
const getActiveIndex = () => {
const offset = getHeaderOffset() + 8;
let idx = 0;
for (let i = 0; i < blocks.length; i++) {
if (blocks[i].getBoundingClientRect().top <= offset) idx = i;
}
return idx;
};
/**
* 进度只跟内容滚动的年份序号插值,不依赖左侧字号布局。
* 跨年时 (idx+local)/(n-1) 单调连续,避免「先变短再变长」。
*/
const updateProgressFromScroll = () => {
if (!indicator || !rail || isMobile()) return;
syncRailHeight();
const n = navItems.length;
if (n <= 1) {
setProgress(1);
return;
}
const offset = getHeaderOffset() + 8;
const idx = getActiveIndex();
let local = 1;
if (blocks[idx + 1]) {
const curTop = blocks[idx].getBoundingClientRect().top;
const nextTop = blocks[idx + 1].getBoundingClientRect().top;
const span = nextTop - curTop;
local = span > 0 ? clamp((offset - curTop) / span, 0, 1) : 1;
}
setProgress((idx + local) / (n - 1));
};
const setActive = (year, { scrollNav = true } = {}) => {
if (!year || year === activeYear) return;
activeYear = year;
navItems.forEach((el) => {
el.classList.toggle("is-active", el.dataset.year === year);
});
if (scrollNav && isMobile()) {
const current = navItems.find((el) => el.dataset.year === year);
current?.scrollIntoView({
inline: "center",
block: "nearest",
behavior: "smooth"
});
}
};
const onScroll = () => {
if (rafId) return;
rafId = requestAnimationFrame(() => {
rafId = 0;
// 点击滚动过程中仍跟手更新进度;仅锁定高亮年份,避免中途抢焦点
if (!clicking) {
const idx = getActiveIndex();
const year = navItems[idx]?.dataset.year;
if (year) setActive(year);
}
updateProgressFromScroll();
});
};
const scrollToYear = (year) => {
const target = blocks.find((el) => el.dataset.year === year);
if (!target) return;
clicking = true;
setActive(year);
const top = window.scrollY + target.getBoundingClientRect().top - getHeaderOffset();
const done = () => {
clicking = false;
updateProgressFromScroll();
};
if (window.lenis) {
window.lenis.scrollTo(top, {
duration: 1,
onComplete: done
});
} else {
window.scrollTo({
top,
behavior: "smooth"
});
window.setTimeout(done, 800);
}
};
navItems.forEach((item) => {
item.addEventListener("click", (event) => {
event.preventDefault();
scrollToYear(item.dataset.year);
});
});
if (window.lenis) window.lenis.on("scroll", onScroll);
else window.addEventListener("scroll", onScroll, { passive: true });
if (typeof ResizeObserver !== "undefined" && yearsWrap) {
new ResizeObserver(() => {
syncRailHeight();
updateProgressFromScroll();
}).observe(yearsWrap);
}
window.addEventListener("resize", () => {
syncRailHeight();
updateProgressFromScroll();
});
navItems[0]?.classList.add("is-active");
syncRailHeight();
updateProgressFromScroll();
const hashYear = (location.hash || "").replace(/^#year-/, "");
if (hashYear && blocks.some((el) => el.dataset.year === hashYear)) {
requestAnimationFrame(() => scrollToYear(hashYear));
}
}
setActiveNav();
initHistorySpy();
//#endregion