如何在用户滚动到视图中时动态(或懒加载)加载图片

103
我注意到在许多“现代”网站(例如Facebook和Google图像搜索)中,当用户滚动页面足够将其位于可见视口区域内时,下面的图像才会加载(检查源代码,页面显示X<img>标记,但它们不会立即从服务器获取)。这种技术叫什么,它是如何工作的,在多少浏览器中起作用。是否有一个jQuery插件可以用最少的代码实现这种行为。

编辑

奖励:是否有人能解释一下HTML元素是否有“onScrolledIntoView”或类似事件。如果没有,这些插件是如何工作的?


你只需要图片懒加载吗?如果你需要内容懒加载,无限滚动插件是正确的答案。 - soju
@rsp @jwegner @Nicholas 很抱歉,但这不是 Salman 所问的。 - Alec Smart
21
让人想知道为什么浏览器的默认行为不是只加载可见的图像。如果是这样的话,在过去的18年中可以节省多少带宽啊! - Matthew Lock
2
虽然我理解延迟加载背后的原因...但当我访问使用这种方法的网站时,我实在受不了那些图片的闪烁! :) - EliTheDawg
@MatthewLock 因为这需要所有的网页开发者在编写网站时都要考虑到这一点——如果他们没有这样做,页面的布局会随着用户向下滚动而跳跃和变化。如果能够实现这一点那就太好了,但我不认为它会很快成为标准。 - Chuck Le Butt
显示剩余2条评论
9个回答

67

这里的一些答案适用于无限页面。Salman 所问的是图片的懒加载。

插件

演示

编辑:这些插件是如何工作的?

以下是简化的解释:

  1. 查找窗口大小并查找所有图像的位置和大小
  2. 如果图像不在窗口大小内,则用相同大小的占位符替换它
  3. 当用户向下滚动,且图像位置 < 滚动位置 + 窗口高度时,图像将被加载

在应用程序中,它们不是一样的吗?单列图像的无限滚动与延迟加载它们是相同的,对吧?也许我有点困惑。 - jwegner
1
无限滚动可以让您在用户到达(或接近)页面底部时向页面底部添加新项目。懒加载图像可以在页面上具有相同尺寸的占位符,而图像本身则在滚动时加载。因此,后者可以进行懒加载而不影响页面布局。 - Annika Backstrom
1
这里有一个相关的插件,它可能以类似的方式工作:http://afarkas.github.io/lazysizes/,但我相信它更加强大,并且使用了更多已经存在的功能(例如,不需要占位符,但如果您想要的话也可以使用)。 - cregox
与数据表格很好地配合使用,但是一旦您对某列进行排序,它就停止工作了。 :( - Wonko the Sane
如果我在一个页面中使用多张图片,这会加快页面加载速度吗?还是这些图片无论如何都会在开始时加载,只是在滚动时才显示出来? - sisorken
显示剩余3条评论

16

我想出了自己的基本方法,目前看起来还不错。一些流行脚本可能解决了我没有考虑到的许多问题。

注意:这个解决方案快速且易于实现,但对于性能而言并不是最优的。如果性能是一个问题,一定要查看由Apoorv提到并由developers.google解释的新的Intersection Observer

JQuery

$(window).scroll(function() {
    $.each($('img'), function() {
        if ( $(this).attr('data-src') && $(this).offset().top < ($(window).scrollTop() + $(window).height() + 100) ) {
            var source = $(this).data('src');
            $(this).attr('src', source);
            $(this).removeAttr('data-src');
        }
    })
})

示例 HTML 代码

<div>
    <img src="" data-src="pathtoyour/image1.jpg">
    <img src="" data-src="pathtoyour/image2.jpg">
    <img src="" data-src="pathtoyour/image3.jpg">
</div>

解释

当页面滚动时,将检查页面上的每个图像..

$(this).attr('data-src') - 如果图像具有属性 data-src

以及这些图像距离窗口底部有多远..

$(this).offset().top < ($(window).scrollTop() + $(window).height() + 100)

调整 +100 的值到您喜欢的任何值 (-100 例如)

var source = $(this).data('src'); - 获取 data-src= 即图像 url 的值

$(this).attr('src', source); - 将该值放入 src=

$(this).removeAttr('data-src'); - 移除 data-src 属性 (这样您的浏览器就不会浪费资源处理已经加载的图像)

添加到现有代码中

要转换您的html,在编辑器中只需搜索并替换 src="src="" data-src="


1
完美。祝福家人。 - LifterCoder

10

(编辑: 用存档副本替换了损坏的链接)

AOL的Dave Artz在去年的jQuery Conference Boston上做了一次优化方面的精彩演讲。AOL使用一种名为Sonar的工具,根据滚动位置进行按需加载。查看代码以了解它如何将scrollTop(和其他内容)与元素偏移量进行比较,以检测元素的某部分或全部是否可见。

jQuery Sonar

Dave在这些幻灯片中谈到了Sonar。 Sonar从第46张幻灯片开始,而整个“按需加载”讨论则从第33张幻灯片开始。


我想知道这个与Appelsinii的lazyload相比如何?它更轻量级吗?它能在每个浏览器上工作吗?我记得lazyload在Chrome上不起作用。 - deathlock

5

这里有一个非常不错的无限滚动插件here

我自己从来没有编写过这样的插件,但我想它应该是这样工作的。

  1. An event is bound to the the window scrolling

    $(window).scroll(myInfinteScrollFunction);
    
  2. The called function checks if scroll top is greater than the window size

    function myInfiniteScrollFunction() {  
        if($(window).scrollTop() == $(window).height())  
        makeAjaxRequest();  
    }
    
  3. An AJAX request is made, specifying which result # to start at, how many to grab, and any other parameters necessary for the data pull.

    $.ajax({
        type: "POST",
        url:  "myAjaxFile.php",
        data: {"resultNum": 30, "numPerPage": 50, "query": "interesting%20icons" },
        success: myInfiniteLoadFunction(msg)
    });
    
  4. The ajax returns some (most-likely JSON formatted) content, and passes them into the loadnig function.

希望这有意义。

5
现在你可以在图像以及iFrames上使用loading="lazy",以便将其加载推迟到用户滚动到该元素时再进行加载。
<img src="http://placeimg.com/640/360/any" loading="lazy" />

如在MDN中所述:

Loading 属性 一个元素的 loading 属性(或一个img元素的loading属性)可用于指示浏览器推迟加载屏幕外的图像/iframe,直到用户滚动到它们附近。

Can I use?

对于图片,您可以在所有现代浏览器上使用该属性,但是对于iframes,目前仍处于试验阶段。

@import url('https://fonts.googleapis.com/css2?family=Oswald&display=swap');

.scroll-down {
  height: 100vh;
  background: #037ef3;
  display: grid;
  place-items: center;
  color: #fff;
  font-family: "Oswald";
  font-size: 2em;
}

.image {
  padding: 2em;
  display: grid;
  place-items: center;
  box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
}
<div class="scroll-down">
  Let me take this space so that you can scroll down
</div>
<div class="image">
  <img src="http://placeimg.com/640/360/any" loading="lazy" /> <!-- The only important part -->
</div>

提示:

从演示中可以看出,它会创建布局移位,这会在滚动时导致糟糕的用户体验。因此,请尝试使用占位符。类似于这样的东西: NextJS 占位符


loading="lazy" 不会在滚动时加载。它会在开始时一次性加载所有内容。 - user1034912
1
@user1034912,我刚刚也检查了网络请求。它只有在我向下滚动时才加载图像。您能否解释得更详细一些,以便用户可以理解? - m4n0
抱歉,是我的错。你是正确的。我有一个不同的问题。 - user1034912

3

将监听器附加到滚动事件或利用 setInterval 来进行图片的懒加载是高度低效的,因为每次调用 getBoundingClientRect() 都会强制浏览器重新布局整个页面,并且会给您的网站带来相当大的卡顿。

使用 Lozad.js(仅569字节,无依赖项),它使用 IntersectionObserver 来实现高效的图片懒加载。


如果浏览器不支持,可以动态添加Polyfill。 - Apoorv Saxena
现在浏览器的支持情况要好得多了 - can i use - Hastig Zusammenstellen

1

图片惰性加载的瑞士军刀是YUI的ImageLoader

因为这个问题不仅仅是观察滚动位置。


0

这个链接对我有效 演示

1.在jQuery库之后但是在结束body标签之前加载jQuery loadScroll插件。

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script><script src="jQuery.loadScroll.js"></script>

2. 使用Html5的data-src属性将图像添加到您的网页中。您还可以使用常规img的src属性插入占位符。

<img data-src="1.jpg" src="Placeholder.jpg" alt="Image Alt"><img data-src="2.jpg" src="Placeholder.jpg" alt="Image Alt"><img data-src="3.jpg" src="Placeholder.jpg" alt="Image Alt">

3. 在 img 标签上调用插件,并指定淡入效果的持续时间,使您的图像逐渐显示出来

$('img').loadScroll(500); // in ms

0

我正在使用jQuery Lazy。测试花了我大约10分钟的时间,然后又花了一两个小时将其添加到我网站上的大多数图像链接(CollegeCarePackages.com)。我与开发者没有任何关系(零),但它为移动用户改善了我们的跳出率,节省了我很多时间,我非常感激。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接