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.
244 lines
8.7 KiB
244 lines
8.7 KiB
//#region \0vite/modulepreload-polyfill.js
|
|
(function polyfill() {
|
|
const relList = document.createElement("link").relList;
|
|
if (relList && relList.supports && relList.supports("modulepreload")) return;
|
|
for (const link of document.querySelectorAll("link[rel=\"modulepreload\"]")) processPreload(link);
|
|
new MutationObserver((mutations) => {
|
|
for (const mutation of mutations) {
|
|
if (mutation.type !== "childList") continue;
|
|
for (const node of mutation.addedNodes) if (node.tagName === "LINK" && node.rel === "modulepreload") processPreload(node);
|
|
}
|
|
}).observe(document, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
function getFetchOpts(link) {
|
|
const fetchOpts = {};
|
|
if (link.integrity) fetchOpts.integrity = link.integrity;
|
|
if (link.referrerPolicy) fetchOpts.referrerPolicy = link.referrerPolicy;
|
|
if (link.crossOrigin === "use-credentials") fetchOpts.credentials = "include";
|
|
else if (link.crossOrigin === "anonymous") fetchOpts.credentials = "omit";
|
|
else fetchOpts.credentials = "same-origin";
|
|
return fetchOpts;
|
|
}
|
|
function processPreload(link) {
|
|
if (link.ep) return;
|
|
link.ep = true;
|
|
const fetchOpts = getFetchOpts(link);
|
|
fetch(link.href, fetchOpts);
|
|
}
|
|
})();
|
|
//#endregion
|
|
//#region js/common.js
|
|
$(function() {
|
|
AOS.init({ duration: 800 });
|
|
const lenis = new Lenis();
|
|
window.lenis = lenis;
|
|
gsap.registerPlugin(ScrollTrigger, Observer);
|
|
lenis.on("scroll", ScrollTrigger.update);
|
|
gsap.ticker.add((time) => {
|
|
lenis.raf(time * 1e3);
|
|
});
|
|
gsap.ticker.lagSmoothing(0);
|
|
const $header = $(".site-header");
|
|
const $mask = $(".mask");
|
|
const $targets = $("[data-header-dark]");
|
|
const updateHeader = () => {
|
|
if (!$header.length) return;
|
|
const headerRect = $header[0].getBoundingClientRect();
|
|
let shouldDark = false;
|
|
const probeX = Math.max(0, Math.min(window.innerWidth - 1, window.innerWidth / 2));
|
|
const probeY = Math.max(0, Math.min(window.innerHeight - 1, headerRect.bottom + 2));
|
|
if (document.elementFromPoint(probeX, probeY)?.closest("[data-header-dark]")) shouldDark = true;
|
|
else $targets.each(function() {
|
|
const rect = this.getBoundingClientRect();
|
|
if (rect.top <= headerRect.bottom && rect.bottom > headerRect.top) {
|
|
shouldDark = true;
|
|
return false;
|
|
}
|
|
});
|
|
$header.toggleClass("dark", shouldDark || $header.hasClass("is-mega-open"));
|
|
const isScrolled = window.scrollY > 50;
|
|
$header.toggleClass("is-scrolled", isScrolled);
|
|
$mask.toggleClass("is-scrolled", isScrolled);
|
|
};
|
|
lenis.on("scroll", updateHeader);
|
|
ScrollTrigger.addEventListener("refresh", updateHeader);
|
|
updateHeader();
|
|
const maskEl = document.querySelector(".mask");
|
|
const maskContentEl = document.querySelector(".mask-content");
|
|
function setMaskOpenUi(isOpen) {
|
|
$("body").toggleClass("is-mask-open", isOpen);
|
|
}
|
|
$(".site-header__extra-btn.toggle").on("click", function() {
|
|
if (!maskEl || !maskContentEl) return;
|
|
const nodes = maskContentEl.querySelectorAll(".mask-nav__link");
|
|
$(maskEl).addClass("show mask--nav-motion");
|
|
$("body").css("overflow", "hidden");
|
|
setMaskOpenUi(true);
|
|
gsap.killTweensOf(nodes);
|
|
gsap.from(nodes, {
|
|
opacity: 0,
|
|
y: 10,
|
|
stagger: .04,
|
|
delay: .2,
|
|
overwrite: "auto",
|
|
onComplete: function() {
|
|
maskEl.classList.remove("mask--nav-motion");
|
|
gsap.set(nodes, { clearProps: "all" });
|
|
}
|
|
});
|
|
});
|
|
$(".mask-header__icon-btn--close").on("click", function() {
|
|
if (!maskEl || !maskContentEl) return;
|
|
gsap.killTweensOf(maskContentEl.querySelectorAll("ul li a"));
|
|
$(maskEl).removeClass("show mask--nav-motion");
|
|
$("body").css("overflow", "auto");
|
|
setMaskOpenUi(false);
|
|
});
|
|
$(".mask-nav__toggle").on("click", function() {
|
|
const $item = $(this).closest(".mask-nav__item--expandable, .mask-nav__subitem--expandable");
|
|
const isExpanded = $item.attr("data-expanded") === "true";
|
|
$item.attr("data-expanded", String(!isExpanded));
|
|
$(this).attr("aria-expanded", String(!isExpanded));
|
|
});
|
|
|
|
// nav-mega 子组:标题 / 箭头均可展开收起
|
|
$(document).on("click", ".nav-mega__subgroup-title, .nav-mega__subgroup-toggle", function() {
|
|
const $subgroup = $(this).closest(".nav-mega__subgroup");
|
|
const isExpanded = !$subgroup.hasClass("is-expanded");
|
|
$subgroup.toggleClass("is-expanded", isExpanded);
|
|
$subgroup.find(".nav-mega__subgroup-toggle").attr("aria-expanded", isExpanded);
|
|
});
|
|
|
|
// 语言切换:默认语言无前缀,其它语言用 /{lang}/ 前缀(与 getLang 一致)
|
|
(function initLangSwitch() {
|
|
const ALLOWED = ["zh", "tc", "en", "ja", "de", "fa", "id", "th", "ru"];
|
|
const defaultLang =
|
|
document.querySelector(".site-header__lang")?.getAttribute("data-lang-default") || "zh";
|
|
|
|
const getPathLang = () => {
|
|
const seg = location.pathname.replace(/^\//, "").split("/")[0] || "";
|
|
return ALLOWED.includes(seg) ? seg : defaultLang;
|
|
};
|
|
|
|
const buildLangUrl = (targetLang) => {
|
|
const parts = location.pathname.replace(/^\//, "").split("/").filter(Boolean);
|
|
if (parts.length && ALLOWED.includes(parts[0])) parts.shift();
|
|
const rest = parts.join("/");
|
|
let path;
|
|
if (!targetLang || targetLang === defaultLang) {
|
|
path = rest ? `/${rest}` : "/";
|
|
} else {
|
|
path = rest ? `/${targetLang}/${rest}` : `/${targetLang}/`;
|
|
}
|
|
return path + location.search + location.hash;
|
|
};
|
|
|
|
const goLang = (targetLang) => {
|
|
if (!targetLang) return;
|
|
const cur = getPathLang();
|
|
const uiCur = cur === "en" ? "en" : "zh";
|
|
if (targetLang === uiCur || targetLang === cur) return;
|
|
location.href = buildLangUrl(targetLang);
|
|
};
|
|
|
|
const syncActive = () => {
|
|
const uiLang = getPathLang() === "en" ? "en" : "zh";
|
|
$(".site-header__lang [data-lang]").removeClass("site-header__lang-active");
|
|
$(`.site-header__lang [data-lang="${uiLang}"]`).addClass("site-header__lang-active");
|
|
};
|
|
|
|
$(document).on("click", ".site-header__lang [data-lang]", function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
goLang(this.getAttribute("data-lang"));
|
|
});
|
|
|
|
$(document).on("click", ".site-header__lang", function(e) {
|
|
if ($(e.target).closest("[data-lang]").length) return;
|
|
goLang(getPathLang() === "en" ? "zh" : "en");
|
|
});
|
|
|
|
$(document).on("click", ".site-header__extra-btn.lang, .mask-header__icon-btn.lang", function(e) {
|
|
e.preventDefault();
|
|
goLang(getPathLang() === "en" ? "zh" : "en");
|
|
});
|
|
|
|
syncActive();
|
|
})();
|
|
// $(".section-contact-form").on("submit", function(e) {
|
|
// e.preventDefault();
|
|
// const $form = $(this);
|
|
// const $name = $form.find("[name=\"name\"]");
|
|
// const $phone = $form.find("[name=\"phone\"]");
|
|
// const name = $.trim($name.val());
|
|
// const phone = $.trim($phone.val());
|
|
// const agreed = $form.find("[name=\"agree\"]").is(":checked");
|
|
// if (!name) {
|
|
// alert("请输入姓名");
|
|
// $name.focus();
|
|
// return;
|
|
// }
|
|
// if (!phone) {
|
|
// alert("请输入联系方式");
|
|
// $phone.focus();
|
|
// return;
|
|
// }
|
|
// if (!agreed) {
|
|
// alert("请阅读并同意隐私政策");
|
|
// return;
|
|
// }
|
|
// alert("提交成功,我们将尽快与您联系");
|
|
// $form[0].reset();
|
|
// });
|
|
$("#nav-mega-product").on("mouseenter", "[data-mega-cat]", function() {
|
|
const $mega = $("#nav-mega-product");
|
|
const cat = $(this).attr("data-mega-cat");
|
|
$mega.find("[data-mega-cat]").removeClass("is-active");
|
|
$(this).addClass("is-active");
|
|
$mega.find("[data-mega-panel]").each(function() {
|
|
const match = this.dataset.megaPanel === cat;
|
|
this.hidden = !match;
|
|
this.classList.toggle("is-active", match);
|
|
});
|
|
});
|
|
|
|
// Lenis.stop() 会加 .lenis-stopped { overflow: clip },经典滚动条(如360)消失后
|
|
// fixed 头部会变宽;内容区通常不变。只补偿头部,不给 html/body 加 padding。
|
|
function getScrollbarWidth() {
|
|
return Math.max(0, window.innerWidth - document.documentElement.clientWidth);
|
|
}
|
|
function lockPageScroll() {
|
|
const root = document.documentElement;
|
|
if (root.classList.contains("is-scroll-locked")) return;
|
|
const sbw = getScrollbarWidth();
|
|
root.style.setProperty("--scroll-lock-compensation", `${sbw}px`);
|
|
root.classList.add("is-scroll-locked");
|
|
lenis.stop();
|
|
// 若 CSS 已保住滚动条,则清零补偿,避免头部被多余收窄
|
|
requestAnimationFrame(() => {
|
|
if (getScrollbarWidth() > 0) {
|
|
root.style.setProperty("--scroll-lock-compensation", "0px");
|
|
}
|
|
});
|
|
}
|
|
function unlockPageScroll() {
|
|
const root = document.documentElement;
|
|
if (!root.classList.contains("is-scroll-locked")) return;
|
|
root.classList.remove("is-scroll-locked");
|
|
root.style.removeProperty("--scroll-lock-compensation");
|
|
lenis.start();
|
|
}
|
|
|
|
$(".nav-mega").attr("data-lenis-prevent", "");
|
|
|
|
$(".site-header__nav-item--mega").on("mouseenter", function() {
|
|
if ($("body").hasClass("is-mask-open")) return;
|
|
lockPageScroll();
|
|
}).on("mouseleave", function() {
|
|
if ($("body").hasClass("is-mask-open")) return;
|
|
unlockPageScroll();
|
|
});
|
|
});
|
|
//#endregion
|