|
|
/**
|
|
|
* Smooth Scroll Initialization
|
|
|
* 平滑滚动初始化脚本
|
|
|
* 优化版本:增强与Elementor和其他滚动库的兼容性
|
|
|
*
|
|
|
* @package Nenghui Energy Theme
|
|
|
* @since 1.0.0
|
|
|
*/
|
|
|
|
|
|
// Elementor兼容性检查
|
|
|
function isElementorEditMode() {
|
|
|
return window.elementorFrontend && window.elementorFrontend.isEditMode();
|
|
|
}
|
|
|
|
|
|
// 检查是否有冲突的滚动库
|
|
|
function hasScrollConflicts() {
|
|
|
const conflicts = [];
|
|
|
|
|
|
// 检查常见的滚动库
|
|
|
if (window.AOS) conflicts.push('AOS');
|
|
|
if (window.ScrollMagic) conflicts.push('ScrollMagic');
|
|
|
if (window.gsap && window.ScrollTrigger) conflicts.push('GSAP ScrollTrigger');
|
|
|
|
|
|
if (conflicts.length > 0) {
|
|
|
|
|
|
}
|
|
|
|
|
|
return conflicts.length > 0;
|
|
|
}
|
|
|
|
|
|
// 动态配置选项
|
|
|
function getSmoothScrollConfig() {
|
|
|
const baseConfig = {
|
|
|
// 滚动速度 (毫秒)
|
|
|
animationTime: 800,
|
|
|
|
|
|
// 步长大小
|
|
|
stepSize: 100,
|
|
|
|
|
|
// 加速度倍数
|
|
|
accelerationDelta: 50,
|
|
|
|
|
|
// 最大加速度
|
|
|
accelerationMax: 3,
|
|
|
|
|
|
// 键盘支持
|
|
|
keyboardSupport: true,
|
|
|
|
|
|
// 箭头滚动步长
|
|
|
arrowScroll: 50,
|
|
|
|
|
|
// 脉冲算法设置
|
|
|
pulseAlgorithm: true,
|
|
|
|
|
|
// 脉冲比例
|
|
|
pulseScale: 4,
|
|
|
|
|
|
// 脉冲标准化
|
|
|
pulseNormalize: 1,
|
|
|
|
|
|
// 固定背景支持
|
|
|
fixedBackground: true,
|
|
|
|
|
|
// 排除的元素选择器
|
|
|
excluded: 'textarea, input[type="text"], input[type="password"], input[type="email"], input[type="number"], input[type="search"], input[type="tel"], input[type="url"], select'
|
|
|
};
|
|
|
|
|
|
// Elementor编辑模式下的特殊配置
|
|
|
if (isElementorEditMode()) {
|
|
|
return {
|
|
|
...baseConfig,
|
|
|
animationTime: 600, // 增加动画时间,使滚动更平滑
|
|
|
keyboardSupport: false, // 在编辑模式下禁用键盘支持
|
|
|
excluded: baseConfig.excluded + ', .elementor-editor-active, .elementor-widget-container'
|
|
|
};
|
|
|
}
|
|
|
|
|
|
// 检测到滚动冲突时的配置
|
|
|
if (hasScrollConflicts()) {
|
|
|
return {
|
|
|
...baseConfig,
|
|
|
animationTime: 600, // 减少动画时间
|
|
|
accelerationMax: 2, // 降低加速度
|
|
|
excluded: baseConfig.excluded + ', .gsap-scroll-trigger, .aos-animate, .scroll-magic-element'
|
|
|
};
|
|
|
}
|
|
|
|
|
|
return baseConfig;
|
|
|
}
|
|
|
|
|
|
// 在库加载前设置全局配置选项
|
|
|
if (typeof window.SmoothScrollOptions === 'undefined') {
|
|
|
window.SmoothScrollOptions = getSmoothScrollConfig();
|
|
|
}
|
|
|
|
|
|
(function() {
|
|
|
'use strict';
|
|
|
|
|
|
// 防抖函数
|
|
|
function debounce(func, wait) {
|
|
|
let timeout;
|
|
|
return function executedFunction(...args) {
|
|
|
const later = () => {
|
|
|
clearTimeout(timeout);
|
|
|
func(...args);
|
|
|
};
|
|
|
clearTimeout(timeout);
|
|
|
timeout = setTimeout(later, wait);
|
|
|
};
|
|
|
}
|
|
|
|
|
|
// 节流函数
|
|
|
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 SmoothScrollManager = {
|
|
|
initialized: false,
|
|
|
backToTopBtn: null,
|
|
|
scrollThreshold: 300,
|
|
|
|
|
|
// 初始化
|
|
|
init: function() {
|
|
|
if (this.initialized) return;
|
|
|
|
|
|
// 在Elementor编辑模式下延迟初始化
|
|
|
if (isElementorEditMode()) {
|
|
|
|
|
|
setTimeout(() => this.initScrollFeatures(), 1000);
|
|
|
} else {
|
|
|
this.initScrollFeatures();
|
|
|
}
|
|
|
|
|
|
this.initialized = true;
|
|
|
},
|
|
|
|
|
|
// 初始化滚动功能
|
|
|
initScrollFeatures: function() {
|
|
|
console.log('✅ Smooth Scroll options configured successfully');
|
|
|
|
|
|
this.setupAnchorLinks();
|
|
|
this.setupBackToTop();
|
|
|
this.bindEvents();
|
|
|
},
|
|
|
|
|
|
// 设置锚点链接
|
|
|
setupAnchorLinks: function() {
|
|
|
const anchorLinks = document.querySelectorAll('a[href^="#"]');
|
|
|
anchorLinks.forEach(link => {
|
|
|
// 避免重复绑定事件
|
|
|
if (link.hasAttribute('data-smooth-scroll-bound')) return;
|
|
|
|
|
|
link.addEventListener('click', this.handleAnchorClick.bind(this));
|
|
|
link.setAttribute('data-smooth-scroll-bound', 'true');
|
|
|
});
|
|
|
},
|
|
|
|
|
|
// 处理锚点点击
|
|
|
handleAnchorClick: function(e) {
|
|
|
const targetId = e.currentTarget.getAttribute('href').substring(1);
|
|
|
const targetElement = document.getElementById(targetId);
|
|
|
|
|
|
if (targetElement) {
|
|
|
e.preventDefault();
|
|
|
|
|
|
// 检查是否在Elementor编辑模式下
|
|
|
if (isElementorEditMode()) {
|
|
|
// 在编辑模式下使用简单的滚动
|
|
|
targetElement.scrollIntoView({ behavior: 'auto' });
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 检查GSAP ScrollTrigger是否存在并刷新
|
|
|
if (window.ScrollTrigger) {
|
|
|
window.ScrollTrigger.refresh();
|
|
|
}
|
|
|
|
|
|
// 平滑滚动到目标元素
|
|
|
targetElement.scrollIntoView({
|
|
|
behavior: 'smooth',
|
|
|
block: 'start',
|
|
|
inline: 'nearest'
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 设置回到顶部按钮
|
|
|
setupBackToTop: function() {
|
|
|
this.backToTopBtn = document.querySelector('.back-to-top');
|
|
|
if (this.backToTopBtn) {
|
|
|
// 避免重复绑定事件
|
|
|
if (!this.backToTopBtn.hasAttribute('data-smooth-scroll-bound')) {
|
|
|
this.backToTopBtn.addEventListener('click', this.handleBackToTop.bind(this));
|
|
|
this.backToTopBtn.setAttribute('data-smooth-scroll-bound', 'true');
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 处理回到顶部
|
|
|
handleBackToTop: function(e) {
|
|
|
e.preventDefault();
|
|
|
|
|
|
// 在Elementor编辑模式下使用简单滚动
|
|
|
if (isElementorEditMode()) {
|
|
|
window.scrollTo({ top: 0, behavior: 'auto' });
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
this.smoothScrollToTop();
|
|
|
},
|
|
|
|
|
|
// 自定义平滑滚动到顶部函数
|
|
|
smoothScrollToTop: function() {
|
|
|
const startPosition = window.pageYOffset;
|
|
|
const startTime = performance.now();
|
|
|
const duration = 800;
|
|
|
|
|
|
const animation = (currentTime) => {
|
|
|
const timeElapsed = currentTime - startTime;
|
|
|
const run = this.easeInOutQuad(timeElapsed, startPosition, -startPosition, duration);
|
|
|
window.scrollTo(0, run);
|
|
|
|
|
|
if (timeElapsed < duration) {
|
|
|
requestAnimationFrame(animation);
|
|
|
} else {
|
|
|
// 动画完成后刷新ScrollTrigger
|
|
|
if (window.ScrollTrigger) {
|
|
|
window.ScrollTrigger.refresh();
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
requestAnimationFrame(animation);
|
|
|
},
|
|
|
|
|
|
// 缓动函数(easeInOutQuad)
|
|
|
easeInOutQuad: function(t, b, c, d) {
|
|
|
t /= d / 2;
|
|
|
if (t < 1) return c / 2 * t * t + b;
|
|
|
t--;
|
|
|
return -c / 2 * (t * (t - 2) - 1) + b;
|
|
|
},
|
|
|
|
|
|
// 绑定事件
|
|
|
bindEvents: function() {
|
|
|
// 使用节流的滚动事件处理器
|
|
|
const throttledScrollHandler = throttle(this.handleScroll.bind(this), 16); // 约60fps
|
|
|
window.addEventListener('scroll', throttledScrollHandler, { passive: true });
|
|
|
|
|
|
// 监听窗口大小变化
|
|
|
const debouncedResizeHandler = debounce(this.handleResize.bind(this), 250);
|
|
|
window.addEventListener('resize', debouncedResizeHandler);
|
|
|
|
|
|
// 监听Elementor前端加载完成
|
|
|
if (window.elementorFrontend && window.elementorFrontend.hooks && typeof window.elementorFrontend.hooks.addAction === 'function') {
|
|
|
try {
|
|
|
window.elementorFrontend.hooks.addAction('frontend/element_ready/global', () => {
|
|
|
this.setupAnchorLinks(); // 重新设置锚点链接
|
|
|
});
|
|
|
} catch (error) {
|
|
|
console.warn('SmoothScroll: 无法绑定Elementor钩子:', error);
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 处理滚动事件
|
|
|
handleScroll: function() {
|
|
|
if (this.backToTopBtn) {
|
|
|
const shouldShow = window.pageYOffset > this.scrollThreshold;
|
|
|
this.backToTopBtn.classList.toggle('visible', shouldShow);
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 处理窗口大小变化
|
|
|
handleResize: function() {
|
|
|
// 刷新ScrollTrigger实例
|
|
|
if (window.ScrollTrigger) {
|
|
|
window.ScrollTrigger.refresh();
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 销毁方法
|
|
|
destroy: function() {
|
|
|
// 移除所有事件监听器
|
|
|
const anchorLinks = document.querySelectorAll('a[href^="#"][data-smooth-scroll-bound]');
|
|
|
anchorLinks.forEach(link => {
|
|
|
link.removeEventListener('click', this.handleAnchorClick);
|
|
|
link.removeAttribute('data-smooth-scroll-bound');
|
|
|
});
|
|
|
|
|
|
if (this.backToTopBtn && this.backToTopBtn.hasAttribute('data-smooth-scroll-bound')) {
|
|
|
this.backToTopBtn.removeEventListener('click', this.handleBackToTop);
|
|
|
this.backToTopBtn.removeAttribute('data-smooth-scroll-bound');
|
|
|
}
|
|
|
|
|
|
this.initialized = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 等待DOM加载完成
|
|
|
if (document.readyState === 'loading') {
|
|
|
document.addEventListener('DOMContentLoaded', () => SmoothScrollManager.init());
|
|
|
} else {
|
|
|
SmoothScrollManager.init();
|
|
|
}
|
|
|
|
|
|
// 页面卸载时清理
|
|
|
window.addEventListener('beforeunload', () => SmoothScrollManager.destroy());
|
|
|
|
|
|
// 暴露到全局作用域以便调试
|
|
|
window.SmoothScrollManager = SmoothScrollManager;
|
|
|
|
|
|
})(); |