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.
170 lines
5.1 KiB
170 lines
5.1 KiB
import "./common.js";
|
|
//#region js/product.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 introGalleryInit() {
|
|
const root = document.querySelector(".p-intro__gallery");
|
|
if (!root || !window.Swiper) return;
|
|
const swiper = new window.Swiper(root, {
|
|
loop: true,
|
|
speed: 500,
|
|
autoplay: {
|
|
delay: 3e3,
|
|
disableOnInteraction: false
|
|
},
|
|
observer: true,
|
|
observeParents: true,
|
|
resizeObserver: true,
|
|
pagination: {
|
|
el: ".p-intro__gallery-pagination",
|
|
clickable: true
|
|
}
|
|
});
|
|
window.addEventListener("resize", () => swiper.update(), { passive: true });
|
|
}
|
|
function relatedCarouselInit() {
|
|
const root = document.querySelector(".p-related");
|
|
const el = root?.querySelector(".p-related__swiper");
|
|
if (!root || !el || !window.Swiper) return;
|
|
const slideCount = el.querySelectorAll(".swiper-wrapper > .swiper-slide").length;
|
|
// 一屏展示 4 条,不超过 4 条时隐藏切换按钮
|
|
if (slideCount <= 4) {
|
|
root.querySelectorAll(".p-related__header .s-arrows").forEach((node) => {
|
|
node.style.display = "none";
|
|
});
|
|
}
|
|
new window.Swiper(el, {
|
|
slidesPerView: 1.15,
|
|
spaceBetween: 16,
|
|
grabCursor: true,
|
|
watchOverflow: true,
|
|
pagination: {
|
|
el: root.querySelector(".p-related__pagination"),
|
|
clickable: true
|
|
},
|
|
navigation: {
|
|
nextEl: root.querySelector(".s-arrows__next"),
|
|
prevEl: root.querySelector(".s-arrows__prev")
|
|
},
|
|
breakpoints: {
|
|
768: {
|
|
slidesPerView: 2,
|
|
spaceBetween: 24
|
|
},
|
|
1200: {
|
|
slidesPerView: 4,
|
|
spaceBetween: 40
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function productSubnavInit() {
|
|
const subnav = document.querySelector("[data-p-subnav]");
|
|
const intro = document.querySelector("#p-intro");
|
|
if (!subnav || !intro) return;
|
|
const sectionIds = [
|
|
"p-intro",
|
|
"p-spec",
|
|
"p-download",
|
|
"p-related"
|
|
];
|
|
const sections = sectionIds.map((id) => document.getElementById(id)).filter(Boolean);
|
|
const links = [...subnav.querySelectorAll("[data-p-nav]")];
|
|
const setVisible = (visible) => {
|
|
subnav.classList.toggle("is-visible", visible);
|
|
subnav.setAttribute("aria-hidden", visible ? "false" : "true");
|
|
document.body.classList.toggle("is-p-subnav", visible);
|
|
};
|
|
const setActiveLink = (id) => {
|
|
links.forEach((link) => {
|
|
link.classList.toggle("is-active", link.dataset.pNav === id);
|
|
});
|
|
};
|
|
const getSubnavHeight = () => subnav.offsetHeight || 80;
|
|
const updateActiveByScroll = () => {
|
|
const offset = getSubnavHeight() + 8;
|
|
let current = sectionIds[0];
|
|
for (const section of sections) if (section.getBoundingClientRect().top <= offset) current = section.id;
|
|
setActiveLink(current);
|
|
};
|
|
const updateVisibility = () => {
|
|
const visible = intro.getBoundingClientRect().top <= 1;
|
|
setVisible(visible);
|
|
if (visible) updateActiveByScroll();
|
|
};
|
|
const scrollToSection = (id) => {
|
|
const target = document.getElementById(id);
|
|
if (!target) return;
|
|
const top = window.scrollY + target.getBoundingClientRect().top - getSubnavHeight();
|
|
if (window.lenis) window.lenis.scrollTo(top, { duration: 1 });
|
|
else window.scrollTo({
|
|
top,
|
|
behavior: "smooth"
|
|
});
|
|
};
|
|
subnav.addEventListener("click", (event) => {
|
|
const link = event.target.closest("[data-p-nav], .p-subnav__cta");
|
|
if (!link) return;
|
|
if (link.hasAttribute("data-selection-trigger")) return;
|
|
const href = link.getAttribute("href");
|
|
if (!href || !href.startsWith("#")) return;
|
|
event.preventDefault();
|
|
scrollToSection(href.slice(1));
|
|
});
|
|
document.querySelectorAll("a[href=\"#p-spec\"]").forEach((link) => {
|
|
if (link.closest("[data-p-subnav]")) return;
|
|
if (link.hasAttribute("data-selection-trigger")) return;
|
|
link.addEventListener("click", (event) => {
|
|
event.preventDefault();
|
|
scrollToSection("p-spec");
|
|
});
|
|
});
|
|
const onScroll = () => {
|
|
updateVisibility();
|
|
};
|
|
if (window.lenis) window.lenis.on("scroll", onScroll);
|
|
else window.addEventListener("scroll", onScroll, { passive: true });
|
|
window.addEventListener("resize", updateVisibility, { passive: true });
|
|
updateVisibility();
|
|
}
|
|
function selectionModalInit() {
|
|
const modal = document.querySelector("[data-selection-modal]");
|
|
if (!modal) return;
|
|
const open = () => {
|
|
modal.hidden = false;
|
|
document.body.style.overflow = "hidden";
|
|
if (window.lenis?.stop) window.lenis.stop();
|
|
};
|
|
const close = () => {
|
|
modal.hidden = true;
|
|
document.body.style.overflow = "";
|
|
if (window.lenis?.start) window.lenis.start();
|
|
};
|
|
document.querySelectorAll("[data-selection-trigger]").forEach((trigger) => {
|
|
trigger.addEventListener("click", (event) => {
|
|
if (trigger.classList.contains("disabled")) return;
|
|
event.preventDefault();
|
|
open();
|
|
});
|
|
});
|
|
modal.querySelectorAll("[data-selection-close]").forEach((el) => {
|
|
el.addEventListener("click", close);
|
|
});
|
|
document.addEventListener("keydown", (event) => {
|
|
if (event.key === "Escape" && !modal.hidden) close();
|
|
});
|
|
}
|
|
$(function() {
|
|
setActiveNav();
|
|
introGalleryInit();
|
|
relatedCarouselInit();
|
|
productSubnavInit();
|
|
selectionModalInit();
|
|
});
|
|
//#endregion
|