JavaScript实战③|图片懒加载与无限滚动,性能优化技巧

发布时间:2026/6/10 8:11:04

JavaScript实战③|图片懒加载与无限滚动,性能优化技巧 author: 专注前端开发分享JavaScript干货title: JavaScript实战③图片懒加载与无限滚动性能优化技巧update: 2026-04-28tags: JavaScript,实战项目,懒加载,无限滚动,性能优化,IntersectionObserver作者专注前端开发分享JavaScript干货更新时间2026年4月适合人群掌握JS基础想学习性能优化技巧的开发者前言为什么需要懒加载网页加载大量图片时首屏加载慢浪费用户流量页面卡顿懒加载Lazy Loading让图片进入视口才加载大幅提升性能。一、图片懒加载1.1 传统方式scroll 事件// 获取所有需要懒加载的图片constlazyImagesdocument.querySelectorAll(img[data-src]);functionlazyLoad(){lazyImages.forEach(img{// 判断图片是否进入视口constrectimg.getBoundingClientRect();constisInViewportrect.topwindow.innerHeightrect.bottom0;if(isInViewportimg.dataset.src){img.srcimg.dataset.src;img.removeAttribute(data-src);}});}// 监听滚动事件需要节流window.addEventListener(scroll,throttle(lazyLoad,200));window.addEventListener(resize,throttle(lazyLoad,200));// 页面加载时执行一次lazyLoad();// 节流函数functionthrottle(fn,delay){letlastTime0;returnfunction(...args){constnowDate.now();if(now-lastTimedelay){fn.apply(this,args);lastTimenow;}};}1.2 现代方式IntersectionObserver// 使用 IntersectionObserver API更现代、更高效constlazyImagesdocument.querySelectorAll(img[data-src]);constimageObservernewIntersectionObserver((entries,observer){entries.forEach(entry{if(entry.isIntersecting){constimgentry.target;img.srcimg.dataset.src;// 加载完成后移除>.onload(){img.removeAttribute(data-src);};// 停止观察这张图片observer.unobserve(img);}});},{rootMargin:50px 0px,// 提前 50px 开始加载threshold:0.01});lazyImages.forEach(imgimageObserver.observe(img));1.3 HTML 结构!-- 懒加载图片 --imgdata-srclarge-image.jpgsrcplaceholder.jpgalt描述classlazy-imagestyle.lazy-image{opacity:0;transition:opacity 0.3s;}.lazy-image[src]:not([data-src]){opacity:1;}/style二、无限滚动Infinite Scroll2.1 实现原理classInfiniteScroll{constructor(options){this.containerdocument.querySelector(options.container);this.loadMoreoptions.loadMore;this.loadingfalse;this.hasMoretrue;this.page1;this.init();}init(){// 使用 IntersectionObserver 监听底部元素constsentineldocument.createElement(div);sentinel.classNamescroll-sentinel;sentinel.style.height10px;this.container.appendChild(sentinel);this.observernewIntersectionObserver((entries){entries.forEach(entry{if(entry.isIntersecting!this.loadingthis.hasMore){this.loadNextPage();}});},{rootMargin:100px 0px});this.observer.observe(sentinel);// 初始加载this.loadNextPage();}asyncloadNextPage(){if(this.loading||!this.hasMore)return;this.loadingtrue;this.showLoading();try{constresultawaitthis.loadMore(this.page);if(result.data.length0){this.hasMorefalse;this.showNoMore();}else{this.renderItems(result.data);this.page;}}catch(error){console.error(加载失败:,error);this.showError();}finally{this.loadingfalse;this.hideLoading();}}showLoading(){constloaderdocument.createElement(div);loader.classNameloading-indicator;loader.innerHTML加载中...;this.container.appendChild(loader);}hideLoading(){constloaderthis.container.querySelector(.loading-indicator);if(loader)loader.remove();}showNoMore(){constnoMoredocument.createElement(div);noMore.classNameno-more;noMore.innerHTML没有更多内容了;noMore.style.cssTexttext-align: center; padding: 20px; color: #999;;this.container.appendChild(noMore);}showError(){consterrordocument.createElement(div);error.classNameerror-message;error.innerHTML加载失败a href# onclicklocation.reload()点击重试/a;this.container.appendChild(error);}renderItems(items){// 子类实现具体的渲染逻辑}}2.2 使用示例// 图片列表无限滚动classImageGalleryextendsInfiniteScroll{constructor(){super({container:.gallery,loadMore:async(page){// 模拟 API 请求constresponseawaitfetch(/api/images?page${page});returnresponse.json();}});}renderItems(images){consthtmlimages.map(imgdiv classgallery-item img>${img.url} srcplaceholder.jpg alt${img.title} p${img.title}/p /div).join();// 插入到 sentinel 之前constsentinelthis.container.querySelector(.scroll-sentinel);sentinel.insertAdjacentHTML(beforebegin,html);// 对新添加的图片启用懒加载constnewImagesthis.container.querySelectorAll(img[data-src]);newImages.forEach(imgimageObserver.observe(img));}}// 初始化constgallerynewImageGallery();三、完整示例图片画廊!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8title图片懒加载 无限滚动/titlestyle*{margin:0;padding:0;box-sizing:border-box;}body{font-family:sans-serif;background:#f5f5f5;}.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:20px;padding:20px;max-width:1200px;margin:0 auto;}.gallery-item{background:white;border-radius:8px;overflow:hidden;box-shadow:0 2px 8pxrgba(0,0,0,0.1);}.gallery-item img{width:100%;height:200px;object-fit:cover;opacity:0;transition:opacity 0.3s;background:#e0e0e0;}.gallery-item img.loaded{opacity:1;}.gallery-item p{padding:15px;color:#333;}.loading-indicator{grid-column:1 / -1;text-align:center;padding:40px;color:#666;}/style/headbodydivclassgalleryidgallery/divscript// 模拟图片数据constmockImages[{url:https://picsum.photos/400/300?random1,title:图片 1},{url:https://picsum.photos/400/300?random2,title:图片 2},{url:https://picsum.photos/400/300?random3,title:图片 3},// ... 更多图片];// 懒加载 ObserverconstimageObservernewIntersectionObserver((entries){entries.forEach(entry{if(entry.isIntersecting){constimgentry.target;img.srcimg.dataset.src;img.onload(){img.classList.add(loaded);img.removeAttribute(data-src);};imageObserver.unobserve(img);}});},{rootMargin:50px});// 无限滚动letpage1;letloadingfalse;asyncfunctionloadMoreImages(){if(loading)return;loadingtrue;// 模拟 API 延迟awaitnewPromise(resolvesetTimeout(resolve,1000));constgallerydocument.getElementById(gallery);// 生成 10 张图片for(leti0;i10;i){constrandomIdpage*10i;constitemdocument.createElement(div);item.classNamegallery-item;item.innerHTMLimg>${randomId} alt图片${randomId} p图片${randomId}/p;gallery.appendChild(item);// 观察新图片imageObserver.observe(item.querySelector(img));}page;loadingfalse;}// 监听滚动constscrollObservernewIntersectionObserver((entries){entries.forEach(entry{if(entry.isIntersecting){loadMoreImages();}});},{rootMargin:200px});// 创建底部触发元素consttriggerdocument.createElement(div);trigger.style.height10px;document.body.appendChild(trigger);scrollObserver.observe(trigger);// 初始加载loadMoreImages();/script/body/html四、知识点回顾知识点应用IntersectionObserver监听元素是否进入视口data-src存储真实图片地址rootMargin提前触发加载的距离throttle节流优化滚动性能async/await异步加载数据五、课后作业实现一个带骨架屏的懒加载图片组件给无限滚动添加加载更多按钮作为降级方案实现图片加载失败时的占位图显示有问题欢迎评论区留言大家一起讨论标签JavaScript | 实战项目 | 懒加载 | 无限滚动 | 性能优化 | IntersectionObserver

相关新闻