// 这是自定义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模板中