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.

371 lines
14 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 这是自定义JS文件用于覆盖主题默认JS文件
/**
* AdvancedImageLoader
* 通用图片加载管理器:支持懒加载、预加载、骨架屏控制
*/
class AdvancedImageLoader {
constructor(options = {}) {
this.options = Object.assign({
rootMargin: '200px 0px', // 提前 200px 开始加载
threshold: 0.01, // 只要露出 1% 就加载
selector: '.lazy-target',// 需要懒加载的目标选择器
skeletonClass: 'skeleton-pulse', // 骨架屏动画类名
loadedClass: 'loaded', // 加载完成后的 CSS 类名
}, options);
this.observer = null;
this.init();
}
init() {
if ('IntersectionObserver' in window) {
this.observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadImage(entry.target);
observer.unobserve(entry.target);
}
});
}, {
rootMargin: this.options.rootMargin,
threshold: this.options.threshold
});
}
this.scan();
}
/**
* 扫描 DOM寻找未加载的图片并加入观察队列
* 注意:在动态渲染(如搜索、翻页)后必须调用此方法
*/
scan() {
const elements = document.querySelectorAll(`${this.options.selector}:not(.${this.options.loadedClass})`);
elements.forEach(el => {
// 如果浏览器不支持 Observer直接加载
if (!this.observer) {
this.loadImage(el);
} else {
this.observer.observe(el);
}
});
}
/**
* 核心加载逻辑
* @param {HTMLElement} el 目标 DOM 元素
*/
loadImage(el) {
const bgSrc = el.getAttribute('data-bg');
const imgSrc = el.getAttribute('data-src');
// 寻找外层包裹的骨架屏容器(如果有)
const skeleton = el.closest('.skeleton-wrapper');
if (!bgSrc && !imgSrc) return;
// 1. 创建内存对象进行预加载 (Preload)
const loader = new Image();
loader.onload = () => {
// 2. 图片下载完毕,更新 DOM
if (bgSrc) {
el.style.backgroundImage = `url("${bgSrc}")`;
}
if (imgSrc) {
el.setAttribute('src', imgSrc);
}
// 3. 触发 CSS 动画 (Fade-in)
// 使用 requestAnimationFrame 确保样式重绘顺滑
requestAnimationFrame(() => {
el.classList.add(this.options.loadedClass);
});
// 4. 关闭骨架屏动画
if (skeleton) {
skeleton.classList.remove(this.options.skeletonClass);
// 可选:加载完成后移除背景色,或者保留作为底色
// skeleton.style.backgroundColor = 'transparent';
}
};
loader.onerror = () => {
console.warn('Image load failed:', bgSrc || imgSrc);
// 即使失败也移除动画,避免一直闪烁
if (skeleton) skeleton.classList.remove(this.options.skeletonClass);
};
// 开始下载
loader.src = bgSrc || imgSrc;
}
/**
* 手动强制预加载一组图片(不等待进入视口)
* 适用于:轮播图的首屏图片、模态框弹出前的图片
* @param {Array} urls 图片链接数组
*/
static preloadBatch(urls) {
urls.forEach(url => {
const img = new Image();
img.src = url;
});
}
}
document.addEventListener('DOMContentLoaded', function() {
// 加载图片,支持懒加载、预加载、骨架屏控制
window.ImageLoader = new AdvancedImageLoader();
// 菜单切换
const menuToggle = document.querySelector('.menu-toggle');
const navMenu = document.querySelector('.nav-menu');
if (menuToggle && navMenu) {
menuToggle.addEventListener('click', function() {
navMenu.classList.toggle('active');
// 切换菜单按钮动画
const spans = this.getElementsByTagName('span');
this.classList.toggle('active');
if (this.classList.contains('active')) {
spans[0].style.transform = 'rotate(45deg) translate(5px, 5px)';
spans[1].style.opacity = '0';
spans[2].style.transform = 'rotate(-45deg) translate(7px, -7px)';
} else {
spans[0].style.transform = 'none';
spans[1].style.opacity = '1';
spans[2].style.transform = 'none';
}
});
}
// 移动端下拉菜单点击切换
function initMobileDropdown() {
const menuItems = document.querySelectorAll('.menu-item-has-children');
// 简单的节流函数
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
// 处理菜单切换逻辑
const toggleMenu = function(e, item) {
// 只在移动端处理
if (window.innerWidth > 768) return;
e.preventDefault();
e.stopPropagation();
// 如果正在动画中则忽略点击可选依赖CSS过渡时间
// 这里使用简单的类切换由CSS控制动画
const isOpening = !item.classList.contains('mobile-open');
// 关闭同级其他菜单项
const siblings = item.parentNode.children;
for (let sibling of siblings) {
if (sibling !== item && sibling.classList.contains('menu-item-has-children')) {
sibling.classList.remove('mobile-open');
}
}
// 切换当前菜单状态
item.classList.toggle('mobile-open');
};
// 创建节流版本的切换函数300ms内只响应一次
const throttledToggle = throttle(toggleMenu, 300);
menuItems.forEach(function(item) {
const link = item.querySelector('a');
const arrow = item.querySelector('.dropdown-arrow');
if (link) {
// 如果有箭头,优先使用箭头触发
if (arrow) {
arrow.addEventListener('click', function(e) {
throttledToggle(e, item);
});
// 同时也为箭头添加触摸事件监听,提高响应速度
arrow.addEventListener('touchend', function(e) {
// 防止触发 click
e.preventDefault();
throttledToggle(e, item);
});
}
// 链接点击处理
link.addEventListener('click', function(e) {
const href = link.getAttribute('href');
// 如果是在移动端,且链接是空或者#,或者没有箭头(只能点链接),则触发菜单切换
if (window.innerWidth <= 768) {
if (!href || href === '#' || href === 'javascript:void(0);') {
throttledToggle(e, item);
}
}
});
}
});
}
// 初始化移动端下拉菜单
initMobileDropdown();
// 窗口大小改变时重新初始化
window.addEventListener('resize', function() {
// 如果切换到桌面端,关闭所有移动端展开的菜单
if (window.innerWidth > 768) {
const openItems = document.querySelectorAll('.menu-item-has-children.mobile-open');
openItems.forEach(function(item) {
item.classList.remove('mobile-open');
});
}
});
// 滚动时改变导航栏样式
let lastScroll = 0;
const nav = document.querySelector('.main-nav');
// window.addEventListener('scroll', function() {
// const currentScroll = window.pageYOffset;
// // 到顶部时显示导航栏并清除背景和阴影
// if (currentScroll <= 0) {
// nav.classList.remove('scrolled');
// nav.style.transform = 'translateY(0)';
// nav.style.backgroundColor = '';
// nav.style.boxShadow = '';
// // 设置主菜单项颜色为白色
// const menuLinks = nav.querySelectorAll('.menu-items > li > a');
// menuLinks.forEach(link => {
// link.style.color = '#333';
// });
// // 确保下拉菜单项保持黑色
// const subMenuLinks = nav.querySelectorAll('.sub-menu li a');
// subMenuLinks.forEach(link => {
// link.style.color = '#333';
// });
// } else if (currentScroll > 80) {
// // 滚动超过80px时添加背景和阴影
// nav.classList.add('scrolled');
// nav.style.backgroundColor = '#fff';
// nav.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 1)';
// // 设置主菜单项颜色为黑色
// const menuLinks = nav.querySelectorAll('.menu-items > li > a');
// menuLinks.forEach(link => {
// link.style.color = '#000';
// });
// // 确保下拉菜单项保持黑色
// const subMenuLinks = nav.querySelectorAll('.sub-menu li a');
// subMenuLinks.forEach(link => {
// link.style.color = '#333';
// });
// if (currentScroll > lastScroll) {
// // 向下滚动时显示导航栏
// nav.style.transform = 'translateY(0)';
// } else {
// // 向上滚动时隐藏导航栏
// nav.style.transform = 'translateY(-100%)';
// }
// } else {
// // 滚动在0-80px之间时清除背景和阴影
// nav.classList.remove('scrolled');
// nav.style.backgroundColor = '';
// nav.style.boxShadow = '';
// nav.style.transform = 'translateY(0)';
// // 设置主菜单项颜色为白色
// const menuLinks = nav.querySelectorAll('.menu-items > li > a');
// menuLinks.forEach(link => {
// link.style.color = '#333';
// });
// // 确保下拉菜单项保持黑色
// const subMenuLinks = nav.querySelectorAll('.sub-menu li a');
// subMenuLinks.forEach(link => {
// link.style.color = '#333';
// });
// }
// lastScroll = currentScroll;
// });
// 鼠标移入移出导航栏效果
nav.addEventListener('mouseenter', function() {
nav.classList.add('scrolled');
nav.style.backgroundColor = '#fff';
nav.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.1)';
// 设置菜单项颜色为黑色
const menuLinks = nav.querySelectorAll('.menu-items > li > a');
menuLinks.forEach(link => {
link.style.color = '#000';
});
// 确保下拉菜单项保持黑色
const subMenuLinks = nav.querySelectorAll('.sub-menu li a');
subMenuLinks.forEach(link => {
link.style.color = '#333';
});
});
nav.addEventListener('mouseleave', function() {
const currentScroll = window.pageYOffset;
// 根据当前滚动位置决定是否保持背景色
if (currentScroll <= 80) {
nav.classList.remove('scrolled');
nav.style.backgroundColor = '';
nav.style.boxShadow = '';
// 设置菜单项颜色为白色
const menuLinks = nav.querySelectorAll('.menu-items > li > a');
menuLinks.forEach(link => {
link.style.color = '#333';
});
// 确保下拉菜单项保持黑色
const subMenuLinks = nav.querySelectorAll('.sub-menu li a');
subMenuLinks.forEach(link => {
link.style.color = '#333';
});
}
});
// 为有子菜单的项目添加特殊处理
const menuItemsWithChildren = nav.querySelectorAll('.menu-item-has-children');
menuItemsWithChildren.forEach(function(item) {
item.addEventListener('mouseenter', function() {
// 确保导航栏有背景色以便下拉菜单显示
nav.classList.add('scrolled');
nav.style.backgroundColor = '#fff';
nav.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.1)';
const menuLinks = nav.querySelectorAll('.menu-items > li > a');
menuLinks.forEach(link => {
link.style.color = '#000';
});
// 确保下拉菜单项保持黑色
const subMenuLinks = nav.querySelectorAll('.sub-menu li a');
subMenuLinks.forEach(link => {
link.style.color = '#333';
});
});
});
// 窗口大小改变时重置菜单状态
window.addEventListener('resize', function() {
if (window.innerWidth > 768) {
// 桌面端时隐藏所有移动端展开的子菜单
document.querySelectorAll('.sub-menu').forEach(menu => {
menu.style.display = '';
});
}
});
});
// Banner轮播现在使用原生JavaScript实现无需Swiper初始化
// 轮播逻辑已集成在block-banner.php模板中