)
文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载导读本文基于现代 JavaScript 教程Modern JavaScript Tutorialen.javascript.info中「滚动Scrolling」章节下的实战任务《Load visible images》系统讲解如何在纯 JavaScript 环境下利用scroll事件实现图片懒加载Lazy Loading页面初始只显示轻量占位图当图片滚动进入视口viewport时再替换为真实图片从而为慢速网络客户端节省流量。读完本文你将掌握基于getBoundingClientRect()的元素可见性检测算法、data-src占位图替换模式以及「页面加载时立即加载首屏图片 滚动时按需加载」的完整落地代码。任务背景为什么要按需加载图片对于慢速网络的客户端移动流量十分宝贵。一个常见的优化策略是页面不立即加载所有图片而是先用一个体积很小的占位图placeholder代替只有当用户滚动到某个位置、图片即将或已经进入视野时才把src换成真实图片地址触发真正的图片下载。任务原文给出了这种占位图标记的标准写法参见 任务描述img srcplaceholder.svg width128 height128>function isVisible(elem) { let coords elem.getBoundingClientRect(); let windowHeight document.documentElement.clientHeight; // 元素的顶边是否可见 let topVisible coords.top 0 coords.top windowHeight; // 元素的底边是否可见 let bottomVisible coords.bottom windowHeight coords.bottom 0; return topVisible || bottomVisible; }原理拆解elem.getBoundingClientRect()返回元素的窗口相对坐标coords.top是元素顶边到视口顶部的距离coords.bottom是底边到视口顶部的距离。窗口相对坐标会随滚动自动变化——页面向下滚动 N 像素所有元素的top/bottom就同时减少 N。document.documentElement.clientHeight取的是html即documentElement的可视高度也就是当前视口高度。文档相关内容统一以document.documentElement为参考这也是滚动相关代码的惯用写法。判定逻辑采用「任一边缘可见即视为可见」顶边可见coords.top 0还没滚出视口顶部且coords.top windowHeight还没滚到视口底部以下底边可见coords.bottom windowHeight且coords.bottom 0两者满足其一就认为元素处于当前可视区域内。这种「顶部或底部任一边缘可见」的策略非常稳健既能覆盖图片比视口还高的场景单边永远不可能同时满足两个条件也避免了「图片完全在视口内但恰好顶边为 0」这类边界情况的误判。边界情况说明严格来说上述判断在「图片恰好完全覆盖视口」这类极端尺寸下仍有理论盲区比如超长图片顶边和底边都越出视口但作为教学级懒加载方案已经足够官方源码 solution.view/index.html 中的注释也明确指出只要元素顶部或底部边缘可见即可不必要求整张图片完整呈现。核心方案二showVisible() 按需替换真实图片有了可见性判断接下来遍历所有图片、只加载「可见且尚未加载」的图片function showVisible() { for (let img of document.querySelectorAll(img)) { let realSrc img.dataset.src; if (!realSrc) continue; if (isVisible(img)) { img.src realSrc; img.dataset.src ; } } } showVisible(); window.onscroll showVisible;这段代码如何满足全部需求需求实现机制首屏图片立即加载绑定事件后立即调用一次showVisible()代码中的showVisible();行滚动时按需加载window.onscroll showVisible把检测函数挂到窗口滚动事件上不碰普通图片let realSrc img.dataset.src; if (!realSrc) continue;—— 没有data-src的图片直接跳过不重复加载加载后把img.dataset.src 清空下次遍历时realSrc为空自然被continue跳过这里有一个容易被忽略的精妙设计把data-src清空作为「已加载」的标记。它同时起到两个作用幂等性无论showVisible()被调用多少次页面加载一次 每次滚动一次已加载的图片都不会被再次触碰天然满足「加载后不重载」可读性用「数据源消失」表示「已经消费」语义清晰也方便调试时在 DOM 里直接看出哪些图片已加载。关于脚本执行时机showVisible()首次调用必须发生在文档内容可用之后否则document.querySelectorAll(img)找不到任何图片。官方方案给出了两种等价做法见 solution.md把脚本放在body底部页面内容之后或监听DOMContentLoaded事件在文档加载完成后执行。solution.view/index.html中的演示实现采用的就是第一种script标签紧跟在所有figure之后。进阶方案预加载前后一页的图片任务 P.S. 鼓励实现更高级的版本提前加载当前位置上下各一页范围内的图片让用户在滚动到之前图片就已经就绪体验更顺滑。完整实现同样收录在演示页面 solution.view/index.html以注释形式保留了该变体function isVisible(elem) { let coords elem.getBoundingClientRect(); let windowHeight document.documentElement.clientHeight; let extendedTop -windowHeight; let extendedBottom 2 * windowHeight; // 顶边可见 || 底边可见 let topVisible coords.top extendedTop coords.top extendedBottom; let bottomVisible coords.bottom extendedBottom coords.bottom extendedTop; return topVisible || bottomVisible; }与基础版对比区别仅在边界值基础版可视区间是(0, windowHeight)即一个屏幕预加载版把区间向上下各扩展一个屏幕变为(-windowHeight, 2 * windowHeight)覆盖上下一共三个屏幕的范围。这意味着当图片距离当前位置还有不到一屏距离时就会开始加载——用户滚到那里时图片基本已下载完成显著降低「边滚边加载」的可见延迟。代价是可能多加载少量未真正看到的图片属于典型的「流量换流畅度」取舍。完整演示从占位图到真实图片的闭环仓库为该任务提供了可直接运行的完整演示页面 solution.view/index.html。其页面包含太阳系多个天体的长文与图片每张图都以placeholder.svg占位真实图片地址存放在data-src中。页面底部的脚本约 50 行把上述两段核心代码整合为完整闭环定义isVisible(elem)基础版定义showVisible()遍历document.querySelectorAll(img)演示版在替换前额外执行realSrc ?nocache Math.random();这是仅为演示去缓存而加的官方源码注释明确提醒「this line should be removed in production code」生产代码中应删除此行通过window.addEventListener(scroll, showVisible)监听滚动并在绑定后立即调用showVisible()加载首屏。未完成版本 source.view/index.html 则保留了// todo: your code空实现供学习者先自行尝试再对照答案。整套代码没有引入任何第三方库是理解懒加载原理的极佳范本。场景延伸与相关知识scroll 事件与「无限加载」姊妹任务本任务所属的滚动章节article.md指出scroll事件是许多经典交互的基础根据滚动位置显示/隐藏控件或信息、滚到底部时加载更多数据等。同章节还有两个姊妹任务Endless page无尽页面滚动接近底部时自动追加内容其解决方案同样是「页面加载时调用一次 挂到window.onscroll」的组合并利用document.documentElement.getBoundingClientRect().bottom判断文档底部与视口底部的距离——与本任务共享同一套坐标检测思想Up/down button回到顶部按钮根据滚动距离显示/隐藏按钮。三个任务共同构成了「基于scroll事件 窗口相对坐标」的完整交互工具箱。如果需要按滚动位置做更多业务逻辑例如记日志、埋点、导航高亮可以在此基础上把showVisible替换为统一的滚动处理函数。关于滚动事件本身的两个要点scroll事件既作用于window也作用于可滚动元素element.scrollTop变化的容器本文方案监听的是窗口级滚动无法通过event.preventDefault()在onscroll监听器中阻止滚动——该事件触发时滚动已经发生要阻止滚动应在引发滚动的源头事件如keydown的PageUp/PageDown上拦截或直接用 CSS 的overflow属性控制见 article.md。现代浏览器视角与本方案的关系scroll监听 坐标检测是图片懒加载的经典教学实现理解它有助于把握本质每次滚动后重新计算元素的窗口相对坐标判断其与视口的位置关系。现代浏览器提供的IntersectionObserverAPI 正是对这一模式的原生封装——它免去了手动坐标计算和滚动监听代价是概念更抽象。如果项目面向现代环境可在掌握本方案原理后平滑迁移到IntersectionObserver本仓库教程主体1-js 与 2-ui以基础 DOM API 为主此任务的价值正在于把底层机制讲透。小结本文完整拆解了「用onscroll事件懒加载可见图片」的官方解决方案占位标记模式src指向占位图、真实地址放data-src浏览器不会主动下载可见性算法getBoundingClientRect()的窗口相对坐标 document.documentElement.clientHeight视口高度「顶边或底边任一可见」即判定可见加载与去重showVisible()遍历图片加载后清空data-src实现幂等页面加载时调用一次保证首屏即时渲染window.onscroll showVisible保证滚动按需加载预加载进阶把可见区间扩展为(-windowHeight, 2 * windowHeight)实现上下各一屏的提前加载。参考实现解决方案说明 | 完整演示页面 | 任务要求 | 滚动章节总览赞分享文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载相关推荐Matter 1.5 集群库完整升级指南如何与 Matter 1.4 做版本对比选型Matter 1.5 集群库完整升级指南如何与 Matter 1.4 做版本对比选型 Matter 1.5 集群库比 1.4 多 41 个集群文件、42 种设文档/教程前端JavaScript 图片预加载回调实现基于 en.javascript.info 的 preloadImages 实战任务JavaScript 图片预加载回调实现基于 en.javascript.info 的 preloadImages 实战任务 本文围绕 Modern Java文档/教程前端现代 JavaScript 教程scroll 滚动事件实战——无限滚动加载、回到顶部按钮与图片懒加载现代 JavaScript 教程scroll 滚动事件实战——无限滚动加载、回到顶部按钮与图片懒加载 本文基于开源仓库 en.javascript.info文档/教程前端上一篇freeCodeCamp 每日编程挑战解析Challenge 219 Anniversary MilestonesJS 周年里程碑查找下一篇FanControl 免费 Windows 风扇控制完整指南5 分钟画好一条温度曲线整机静音创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考