Zepto下实现可靠图片懒加载的完整方案
图片懒加载是前端性能优化的重要手段,通过延迟加载非可视区域的图片,减少首屏资源请求,提升页面加载速度和用户体验。在Zepto框架下实现懒加载,需要结合滚动监听、元素位置计算、状态管理等逻辑,保证在各种场景下的可靠性。本文将详细介绍完整的实现思路与代码。
懒加载核心原理
懒加载的核心逻辑可以拆解为以下步骤:
给需要懒加载的图片设置一个自定义属性(如
data-src)存储真实图片地址,初始src设为占位图或空值监听页面滚动、窗口大小变化等可能改变元素可视状态的事件
每次事件触发时,遍历所有待加载的图片,计算其是否进入可视区域
进入可视区域的图片,将
data-src的值赋给src属性,触发图片加载,并标记为已加载,避免重复处理
关键实现细节
1. 可视区域判断
判断元素是否进入可视区域,需要结合元素的偏移位置和视口的范围:
元素顶部距离页面顶部的距离:通过
offset().top获取视口顶部位置:通过
window.scrollTop()获取视口底部位置:视口顶部位置 + 视口高度,视口高度通过
window.height()获取
当元素顶部距离小于视口底部位置,且元素底部距离大于视口顶部位置时,说明元素进入可视区域。为了提前加载,还可以设置一个提前加载的阈值,比如提前100px开始加载。
2. 事件监听优化
滚动事件触发频率极高,如果每次滚动都执行遍历逻辑,会严重影响性能。因此需要使用节流函数,限制事件处理函数的执行频率,通常设置为100-200ms执行一次即可。
3. 状态管理
已经加载过的图片不需要再次处理,因此需要给加载完成的图片添加一个标记(如data-loaded="true"),遍历时跳过已标记的图片,减少不必要的计算。
完整实现代码
HTML结构示例
首先准备需要懒加载的图片结构,真实地址存放在data-src中:
<ul class="img-list"> <li> <img class="lazy-img" data-src="https://www.ipipp.com/image1.jpg" src="placeholder.jpg" alt="示例图片1"> </li> <li> <img class="lazy-img" data-src="https://www.ipipp.com/image2.jpg" src="placeholder.jpg" alt="示例图片2"> </li> <li> <img class="lazy-img" data-src="https://www.ipipp.com/image3.jpg" src="placeholder.jpg" alt="示例图片3"> </li> </ul>
Zepto懒加载逻辑实现
下面是完整的Zepto懒加载实现代码,包含节流函数、可视判断、加载逻辑:
// 节流函数,限制函数执行频率
function throttle(fn, delay) {
let timer = null;
return function() {
const context = this;
const args = arguments;
if (!timer) {
timer = setTimeout(function() {
fn.apply(context, args);
timer = null;
}, delay);
}
};
}
// 判断元素是否进入可视区域
function isInViewport(el, threshold) {
threshold = threshold || 100; // 提前100px加载
const rect = el.getBoundingClientRect();
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
const viewportTop = window.scrollY || document.documentElement.scrollTop;
const viewportBottom = viewportTop + viewportHeight;
const elTop = rect.top + viewportTop;
const elBottom = elTop + rect.height;
// 元素底部高于视口顶部,且元素顶部低于视口底部+阈值,说明进入可视范围
return elBottom > viewportTop && elTop < viewportBottom + threshold;
}
// 加载懒加载图片
function loadLazyImages() {
// 选择未加载的懒加载图片
$('.lazy-img:not([data-loaded="true"])').each(function() {
const $img = $(this);
const el = $img[0];
if (isInViewport(el)) {
const realSrc = $img.attr('data-src');
if (realSrc) {
// 绑定加载完成事件,标记已加载
$img.on('load', function() {
$img.attr('data-loaded', 'true');
}).on('error', function() {
// 加载失败处理,比如显示错误占位图
$img.attr('src', 'error-placeholder.jpg');
$img.attr('data-loaded', 'true');
});
// 赋值真实地址触发加载
$img.attr('src', realSrc);
}
}
});
}
// 页面初始化时执行一次,加载首屏图片
$(function() {
loadLazyImages();
// 监听滚动事件,使用节流优化
$(window).on('scroll', throttle(loadLazyImages, 150));
// 监听窗口大小变化事件,重新判断可视区域
$(window).on('resize', throttle(loadLazyImages, 150));
// 监听页面DOM变化,比如动态插入的图片也能被处理
if (typeof MutationObserver !== 'undefined') {
const observer = new MutationObserver(throttle(loadLazyImages, 150));
observer.observe(document.body, {
childList: true,
subtree: true
});
}
});可靠性优化建议
为了让懒加载在各种场景下更可靠,还可以添加以下优化:
处理动态插入的图片:通过
MutationObserver监听DOM变化,新插入的懒加载图片会被自动检测到加载失败容错:给图片绑定
error事件,加载失败时显示占位图并标记已处理,避免重复请求兼容低版本浏览器:如果浏览器不支持
getBoundingClientRect,可以通过offsetTop和scrollTop计算位置避免重复绑定事件:确保滚动、 resize 等事件只绑定一次,防止内存泄漏
注意事项
在使用过程中需要注意以下几点:
占位图的尺寸最好和实际图片一致,避免图片加载完成后页面布局抖动
如果页面有异步加载的内容,在内容插入后手动调用一次
loadLazyImages方法,确保新图片被处理节流函数的延迟时间可以根据页面实际滚动频率调整,高频滚动场景可以适当增大延迟