feat: 优化 Lazyload 生命周期管理

- 添加全局 lazyloadScrollHandler 变量,用于降级方案的清理
- 优化 lazyloadInit() 函数:
  - 增强 Observer 存在性检查,添加 try-catch 错误处理
  - 清理旧的滚动监听器(降级方案)
  - 添加详细的调试日志
  - IntersectionObserver 初始化失败时自动降级
- 优化 loadImageOptimized() 函数:
  - 使用 requestAnimationFrame 优化 DOM 操作
  - 图片加载失败时取消 Observer 监听
  - 没有 data-src 时取消 Observer 监听
- 优化 lazyloadFallback() 降级方案:
  - 保存 handler 引用到全局变量
  - 所有图片加载完成后自动清理监听器
- 优化 cleanupLazyloadObserver() 函数:
  - 同时清理 Observer 和滚动监听器
  - 添加完善的错误处理
- 移除 cleanupEventListeners() 中的重复清理代码

满足需求:2.1, 2.2, 2.4, 2.5, 3.1-3.3, 8.2
This commit is contained in:
2026-01-25 00:31:33 +08:00
parent 8180a87b89
commit 1781e3bd79

View File

@@ -2460,12 +2460,33 @@ $.fancybox.defaults.i18n = {
*/
// 全局 Observer 实例,用于清理
var lazyloadObserver = null;
// 全局滚动监听 handler用于降级方案清理
var lazyloadScrollHandler = null;
function lazyloadInit() {
// 清理旧的 Observer
// 清理旧的 Observer(防止重复初始化)
if (lazyloadObserver) {
try {
lazyloadObserver.disconnect();
lazyloadObserver = null;
ArgonDebug.log('清理旧的 Lazyload Observer');
} catch(e) {
ArgonDebug.warn('清理 Lazyload Observer 失败:', e);
lazyloadObserver = null;
}
}
// 清理旧的滚动监听器(降级方案)
if (lazyloadScrollHandler) {
try {
window.removeEventListener('scroll', lazyloadScrollHandler);
window.removeEventListener('resize', lazyloadScrollHandler);
lazyloadScrollHandler = null;
ArgonDebug.log('清理旧的滚动监听器');
} catch(e) {
ArgonDebug.warn('清理滚动监听器失败:', e);
lazyloadScrollHandler = null;
}
}
// 检查是否启用懒加载
@@ -2477,14 +2498,18 @@ function lazyloadInit() {
let images = document.querySelectorAll('img.lazyload[data-src]');
if (images.length === 0) {
ArgonDebug.log('没有需要懒加载的图片');
return;
}
let effect = argonConfig.lazyload_effect || 'fadeIn';
let threshold = parseInt(argonConfig.lazyload_threshold) || 800;
ArgonDebug.log(`初始化懒加载: ${images.length} 张图片, 效果: ${effect}, 阈值: ${threshold}px`);
// 使用 IntersectionObserver 实现懒加载
if ('IntersectionObserver' in window) {
try {
lazyloadObserver = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
@@ -2504,8 +2529,15 @@ function lazyloadInit() {
img.style.transition = '';
lazyloadObserver.observe(img);
});
ArgonDebug.log('使用 IntersectionObserver 实现懒加载');
} catch(e) {
ArgonDebug.error('IntersectionObserver 初始化失败,使用降级方案:', e);
lazyloadFallback(images, effect, threshold);
}
} else {
// 降级方案:使用滚动监听
ArgonDebug.log('浏览器不支持 IntersectionObserver使用滚动监听降级方案');
lazyloadFallback(images, effect, threshold);
}
}
@@ -2518,11 +2550,19 @@ function lazyloadInit() {
*/
function loadImageOptimized(img, effect) {
let src = img.getAttribute('data-src');
if (!src) return;
if (!src) {
// 如果没有 data-src取消 Observer 监听
if (lazyloadObserver) {
lazyloadObserver.unobserve(img);
}
return;
}
// 预加载图片
let tempImg = new Image();
tempImg.onload = function() {
// 使用 requestAnimationFrame 优化 DOM 操作
requestAnimationFrame(function() {
img.src = src;
img.removeAttribute('data-src');
img.classList.remove('lazyload');
@@ -2530,15 +2570,23 @@ function loadImageOptimized(img, effect) {
// 移除所有lazyload-style-* 类
img.className = img.className.replace(/\blazyload-style-\d+\b/g, '').trim();
// 使用 requestAnimationFrame 应用加载效果
// 应用加载效果
applyLoadEffectOptimized(img, effect);
});
};
tempImg.onerror = function() {
// 加载失败时使用原有src
// 加载失败时使用降级方案
requestAnimationFrame(function() {
img.src = src;
img.removeAttribute('data-src');
img.classList.remove('lazyload');
img.className = img.className.replace(/\blazyload-style-\d+\b/g, '').trim();
// 取消 Observer 监听
if (lazyloadObserver) {
lazyloadObserver.unobserve(img);
}
});
};
tempImg.src = src;
}
@@ -2604,16 +2652,26 @@ function lazyloadFallback(images, effect, threshold) {
loadedImages.add(img);
}
});
// 如果所有图片都已加载,清理监听器
if (loadedImages.size === images.length) {
if (lazyloadScrollHandler) {
window.removeEventListener('scroll', lazyloadScrollHandler);
window.removeEventListener('resize', lazyloadScrollHandler);
lazyloadScrollHandler = null;
ArgonDebug.log('所有图片已加载,清理滚动监听器');
}
}
}
// 使用 eventManager 的节流函数优化性能
const throttledCheck = argonEventManager ?
lazyloadScrollHandler = argonEventManager ?
argonEventManager.throttle(checkImagesInView, 100) :
checkImagesInView;
// 绑定事件监听器
window.addEventListener('scroll', throttledCheck, {passive: true});
window.addEventListener('resize', throttledCheck, {passive: true});
window.addEventListener('scroll', lazyloadScrollHandler, {passive: true});
window.addEventListener('resize', lazyloadScrollHandler, {passive: true});
// 立即检查一次
checkImagesInView();
@@ -2740,10 +2798,11 @@ var pjaxScrollTop = 0, pjaxLoading = false;
// ==========================================================================
/**
* 清理 Lazyload Observer
* 清理 Lazyload Observer 和滚动监听器
* @returns {void}
*/
function cleanupLazyloadObserver() {
// 清理 IntersectionObserver
if (lazyloadObserver) {
try {
lazyloadObserver.disconnect();
@@ -2751,6 +2810,20 @@ function cleanupLazyloadObserver() {
ArgonDebug.log('Lazyload Observer 已清理');
} catch(e) {
ArgonDebug.warn('清理 Lazyload Observer 失败:', e);
lazyloadObserver = null;
}
}
// 清理滚动监听器(降级方案)
if (lazyloadScrollHandler) {
try {
window.removeEventListener('scroll', lazyloadScrollHandler);
window.removeEventListener('resize', lazyloadScrollHandler);
lazyloadScrollHandler = null;
ArgonDebug.log('Lazyload 滚动监听器已清理');
} catch(e) {
ArgonDebug.warn('清理 Lazyload 滚动监听器失败:', e);
lazyloadScrollHandler = null;
}
}
}
@@ -2883,12 +2956,7 @@ function cleanupEventListeners() {
// 注意:大部分事件使用事件委托,不需要手动清理
// 这里只清理特定的非委托事件
// 清理滚动监听(如果使用了降级方案)
if (typeof lazyloadScrollHandler !== 'undefined') {
window.removeEventListener('scroll', lazyloadScrollHandler);
window.removeEventListener('resize', lazyloadScrollHandler);
ArgonDebug.log('已清理 Lazyload 滚动监听器');
}
// Lazyload 滚动监听器已在 cleanupLazyloadObserver() 中清理
ArgonDebug.log('事件监听器已清理');
} catch(e) {