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