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:
154
argontheme.js
154
argontheme.js
@@ -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) {
|
images.forEach(function(img) {
|
||||||
// 重置图片状态
|
// 重置图片状态
|
||||||
img.style.opacity = '';
|
img.style.opacity = '';
|
||||||
img.style.transform = '';
|
img.style.transform = '';
|
||||||
img.style.transition = '';
|
img.style.transition = '';
|
||||||
lazyloadObserver.observe(img);
|
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');
|
||||||
|
img.classList.remove('lazyload');
|
||||||
|
|
||||||
// 移除所有lazyload-style-* 类
|
// 移除所有lazyload-style-* 类
|
||||||
img.className = img.className.replace(/\blazyload-style-\d+\b/g, '').trim();
|
img.className = img.className.replace(/\blazyload-style-\d+\b/g, '').trim();
|
||||||
|
|
||||||
// 使用 requestAnimationFrame 应用加载效果
|
// 应用加载效果
|
||||||
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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user