面试官:“只会这一种懒加载实现思路?回去等通知吧”

思路一:监听滚动事件

监听滚动事件指的是:通过监听页面的滚动事件,判断需要懒加载的元素是否进入可视区域。当元素进入可视区域时,动态加载对应的资源。这种方式需要手动编写监听滚动事件的逻辑,可能会导致性能问题,如滚动时的抖动和卡顿。

关键 API

  • getBoundingClientRect() 方法返回的对象包含以下属性:
  • top:元素上边缘相对于视窗的距离。
  • right:元素右边缘相对于视窗的距离。
  • bottom:元素下边缘相对于视窗的距离。
  • left:元素左边缘相对于视窗的距离。
  • width:元素的宽度(可选)。
  • height:元素的高度(可选)。

可以看下下面的图。

来看看代码示例

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lazy Loading Example</title>
    <style>
        img {
            width: 100%;
            height: 300px;
            display: block;
        }
    </style>
</head>
<body>
    <img data-src="https://via.placeholder.com/300x300?text=Image+1" src="" alt="Image 1">
    <img data-src="https://via.placeholder.com/300x300?text=Image+2" src="" alt="Image 2">
    <img data-src="https://via.placeholder.com/300x300?text=Image+3" src="" alt="Image 3">
    <script>
        function isInViewport(element) {
        const rect = element.getBoundingClientRect();
        const windowHeight = window.innerHeight || document.documentElement.clientHeight;
        const windowWidth = window.innerWidth || document.documentElement.clientWidth;

        return (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= windowHeight &&
            rect.right <= windowWidth
        );
    }

    function lazyLoad() {
        const images = document.querySelectorAll('img[data-src]');
        for (const img of images) {
            if (isInViewport(img)) {
                img.src = img.getAttribute('data-src');
                img.removeAttribute('data-src');
            }
        }
    }

    window.addEventListener('scroll', lazyLoad);
    window.addEventListener('resize', lazyLoad);
    window.addEventListener('DOMContentLoaded', lazyLoad);

    </script>
</body>
</html>

这里的思路就相对简单了,核心思路就是判断这个元素在不在我的视口里面。

同样的思路下面还有另一种实现方式,是用 offsetTopscrollTopinnerHeight做的,这个很常见,我们就不说了。

思路二:Intersection Observer API

这是一种现代浏览器提供的原生 API,用于监控元素与其祖先元素或顶级文档视窗(viewport)的交叉状态。当元素进入可视区域时,会自动触发回调函数,从而实现懒加载。相比于监听滚动事件,Intersection Observer API 更高效且易于使用。

关键 API

  • Intersection Observer API:创建一个回调函数,该函数将在元素进入或离开可视区域时被调用。回调函数接收两个参数:entries(一个包含所有被观察元素的交叉信息的数组)和 observer(观察者实例)。

其中 entries 值得一提,entries 是一个包含多个 IntersectionObserverEntry 对象的数组,每个对象代表一个观察的元素(target element)与根元素(root element)相交的信息。IntersectionObserverEntry 对象包含以下属性:

  1. intersectionRatio: 目标元素和根元素相交区域占目标元素总面积的比例,取值范围为 0 到 1。
  2. intersectionRect: 目标元素和根元素相交区域的边界信息,是一个 DOMRectReadOnly 对象。
  3. isIntersecting: 布尔值,表示目标元素是否正在与根元素相交。
  4. rootBounds: 根元素的边界信息,是一个 DOMRectReadOnly 对象。
  5. target: 被观察的目标元素,即当前 IntersectionObserverEntry 对象所对应的 DOM 元素。
  6. time: 观察到的相交时间,是一个高精度时间戳,单位为毫秒。

这个最近我们组里的姐姐封了一个懒加载组件,通过单例模式 + Intersection Observer API,然后在外部控制 v-if 就好了,非常 nice。

由于代码保密性,我这里只能提供一个常规实现方法qwq

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lazy Loading Example - Intersection Observer</title>
    <style>
        img {
            width: 100%;
            height: 300px;
            display: block;
        }
    </style>
</head>
<body>
    <img data-src="https://via.placeholder.com/300x300?text=Image+1" src="" alt="Image 1">
    <img data-src="https://via.placeholder.com/300x300?text=Image+2" src="" alt="Image 2">
    <img data-src="https://via.placeholder.com/300x300?text=Image+3" src="" alt="Image 3">
    <script>
        function loadImage(img) {
        img.src = img.getAttribute('data-src');
        img.removeAttribute('data-src');
    }

    function handleIntersection(entries, observer) {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                loadImage(entry.target);
                observer.unobserve(entry.target);
            }
        });
    }

    function lazyLoad()
    </script>
</body>
</html>

思路三:虚拟列表

对于长列表数据,可以使用虚拟列表技术来实现懒加载。虚拟列表只会渲染当前可视区域内的列表项,当用户滚动列表时,动态更新可视区域内的内容。这种方式可以大幅减少 DOM 节点的数量,提高页面性能。

这个我之前专门有文章聊过:b站面试官:如果后端给你 1w 条数据,你如何做展示?

就不赘述啦~

那么这就是本篇文章的全部内容啦~

相关推荐
庸俗今天不摸鱼14 分钟前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX1873015 分钟前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下21 分钟前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox32 分钟前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞35 分钟前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行35 分钟前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_5937581036 分钟前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox
掘金一周39 分钟前
金石焕新程 >> 瓜分万元现金大奖征文活动即将回归 | 掘金一周 4.3
前端·人工智能·后端
三翼鸟数字化技术团队1 小时前
Vue自定义指令最佳实践教程
前端·vue.js
uhakadotcom1 小时前
构建高效自动翻译工作流:技术与实践
后端·面试·github