图片懒加载及异常处理

数字霜焰渡
• 阅读 3118

在日常页面开发中,常常会涉及到图片的展示。有时候当图片资源过多时,我们希望能将图片延迟加载,同时当图片加载失败后,能用一张默认图片去代替其进行展示。其效果如图所示:

图片懒加载及异常处理

一、图片懒加载

其实图片懒加载的核心思想很简单:

  1. 通过预先将图片的src资源指向一张小图片或空,并通过 data-src 来记录其实际图片地址。
  2. 通过延迟加载或监听滚动事件(图片出现在可视区域中), 将 data-src 属性值赋值给 src 实现图片的懒加载。
setTimeout({
    $imgs.each(function () {
        var $img = $(this);
        $img.src = $img.attr('data-src');
    });  
}, 0);

// 设置 500ms 防抖动,避免回调频繁执行,影响性能
$(window).on('scroll', _.debounce(function () {
    var $window = $(window); 
    var top = parseInt($window.height()) + parseInt($window.scrollTop());
    $imgs.each(function () {
        var $img = $(this);
        var oSrc = $img.attr('data-src');
        if (!oSrc) return;
        if ($img.offset().top < top) {
            $img.src = oSrc;
            $img.attr('data-src', '');
        }
}, 500));

二、图片加载错误处理

有些时候,由于网络请求或是资源问题,导致图片资源请求失败,这时图片会展示为非常难看的效果(破碎的图片)。这时可以通过监听图片的 onerror 时间来处理。

$img.onerror = function () {
    $img.src = 'default.jpg';
}

为了避免默认图片也加载失败时,图片资源无限执行的情况,可以利用 jQuery 的 one() api 接口绑定一个一次性的 onerror 事件。

$img.one('error', function () {
    $img.src = 'default.jpg';
});
tip: 在加载图片时,我们可以利用创建一个不在 渲染树 中的 Img 元素来加载图片资源。
var oSrc = $img.attr('data-src');
var img = document.createElement('img');
img.onload = function () {
    $img.src = oSrc;
};
img.onerror = function () {
    console.debug('图片加载失败:', img.src);
    // 此时 $img src 依然为默认图,如果图片是否替换判断不为 data-src ,可不进行清空
    $img.attr('data-src', '');
};
img.src = oSrc;

三、利用 background-size 属性代替 img 标签

大多数的时候,图片所处位置的宽高都是固定的。但是图片实际的宽高都是未知的,图片宽高的设置方式有:

  1. 直接将 img 的宽高设置为 img { width: 100%; height: 100%; }可能会出现图片严重失真。
  2. 通过设置最大宽高的方式 img { max-width: 100%; max-height: 100%; } 会出现上下或左右的留白,同时当资源图片宽高小于容器时,留白更多。

background-size: cover; 能够对图片最大程度的利用,不存在留白和图片失真的问题。不过该方式会存在图片资源的损失(图片不能完全展示)。

.img {
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
}

四、利用 Vue 实现一个图片处理指令

export default function (el, binding) {
    setTimeout(() => {
        const img = document.createElement('img');
        img.onload = function () {
            el.style.backgroundImage = `url(${binding.value})`;
        };
        img.onerror = function () {
            console.debug('图片加载失败:', img.src);
        };
        img.src = binding.value;
    }, 0);
};

完整示例代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
    <title>图片懒加载处理</title>
    <style>
        .img-group {
            display: flex;
            width: 800px;
            flex-wrap: wrap;
            list-style-type: none;
        }
        .img-item {
            flex: 0 0 33.3%;
            height: 100px;
            background-color: aquamarine;
            background-position: center;
            background-repeat: no-repeat;
            background-size: cover;
        }
        .img-item:nth-child(odd) {
            background-color: chocolate;
        }
    </style>
</head>

<body>
    <div id="app"></div>

    <template id="tpl">
        <ul class="img-group">
            <li class="img-item" v-for="img in imgs" v-img=" img"></li>
        </ul>
    </template>

    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
    new Vue({
        el: '#app',
        template: '#tpl',
        data() {
            return {
                imgs: [
                    'http://inews.gtimg.com/newsapp_match/0/9167593089/0',
                    'http://inews.gtimg.com/newsapp_match/0/9167593090/0',
                    'http://inews.gtimg.com/newsapp_match/0/9167593092/0',
                    'http://inews.gtimg.com/newsapp_match/0/9167593093/0',
                    'http://inews.gtimg.com/newsapp_match/0/9167593095/0',
                    'http://inews.gtimg.com/newsapp_match/0/9167595616/0',
                    'http://inews.gtimg.com/newsapp_match/0/9167595617/0',
                    'http://inews.gtimg.com/newsapp_match/0/9167595618/0',
                    'http://inews.gtimg.com/newsapp_match/0/9167595619/0'
                ],
            };
        },
        directives: {
            img(el, binding) {
                setTimeout(() => {
                    const img = document.createElement('img');
                    img.onload = function() {
                        el.style.backgroundImage = `url(${binding.value})`;
                    };
                    img.onerror = function() {
                        console.debug('图片加载失败:', img.src);
                    };
                    img.src = binding.value;
                }, 0);
            },
        },
    });
    </script>
</body>

</html>

五、图片优化

如果是前端资源图片的话,还可以做图片做一些其他优化:

  • 压缩图片,降低图片大小 (智图:一个图片优化平台
  • 响应式请求图片资源(高清屏请求 @2x 图片 , 一般屏幕 请求 @x 图片,控制图片尺寸,从而缩减图片大小)
  • 减少图片 http 请求次数(雪碧图)
  • 利用字体库代替图标 (canvas 、svg 绘图替代图标)

具体细节说明可以参考: web前端优化之图片优化

点赞
收藏
评论区
推荐文章
Jacquelyn38 Jacquelyn38
4年前
Vue.js的图片加载性能优化你可以试试
前言图片加载优化对于一个网站性能好坏起着至关重要的作用。所以我们使用Vue来操作一波。备注以下的优化一、优化二栏目都是我自己封装在Vue的工具函数里,所以请认真看完,要不然直接复制的话,容易出错的。资源Vue.jsElementUI优化一:图片加载动画只有当图片加载完成后才可以显示图片,加载动画结束。我们使用ElementUI
Dax Dax
4年前
前端性能优化
前端性能优化1、减少资源的请求次数和大小压缩合并js和css文件,减少http请求次数和请求资源的大小;在项目中使用webpackglup等打包编译工具2、尽量使用字体图标或者svg图标代替传统的png(jpg)图渲染更快,减少代码体积,且放大不会出现变形等3、使用图片懒加载目的是减少页面第一次加载的http请求次数,实现思路:
Easter79 Easter79
4年前
twojs 加载图片和为图片加mask
原文链接: twojs加载图片(https://my.oschina.net/ahaoboy/blog/4953023)一个做2维的webgl库,支持svg和gl,如果只是简单的二维形状效果,这个库用起来还蛮好用的https://two.js.org/(https://www.oschina.net/action/GoToLink?u
Jacquelyn38 Jacquelyn38
4年前
手把手教你实现一个图片压缩工具(Vue与Node的完美配合)
前言图片压缩对于我们日常生活来讲,是非常实用的一项功能。有时我们会在在线图片压缩网站上进行压缩,有时会在电脑下软件进行压缩。那么我们能不能用前端的知识来自己实现一个图片压缩工具呢?答案是有的。效果展示原图片大小:82KB压缩后的图片大小:17KB测试是不是特别good!!!看到上面的压缩后的图片,可能你还会质疑图片的清晰度,那么看下面(第一张图为压缩后的图片
浩浩 浩浩
4年前
【Flutter实战】图片和Icon
3.5图片及ICON3.5.1图片Flutter中,我们可以通过Image组件来加载并显示图片,Image的数据源可以是asset、文件、内存以及网络。ImageProviderImageProvider是一个抽象类,主要定义了图片数据获取的接口load(),从不同的数据源获取图片需要实现不同的ImageProvi
Wesley13 Wesley13
4年前
Unity加载外部图片
在这里记录一下在Unity3D中分别使用WWW和IO流加载外部图片使用WWW加载///<summary///使用WWW加载图片,并赋值给_rawImage///</summary///<paramname"_url"图片地址<
Stella981 Stella981
4年前
Egret白鹭开发小游戏之自定义load加载界面
刚接触不久就遇到困难自定义loading。想和其他获取图片方式一样获取加载界面的图片,结果发现资源还没加载就需要图片,在网上百度了许多,都没有找到正确的方式,通过自己的摸索,终于,,,我成功了。。。下面介绍一下主要思想:首先,我们需要使用异步加载的方式,在加载界面之前加载loading界面需要的素材,然后再loadingUI中就可以大胆使
Stella981 Stella981
4年前
JavaScript——图片懒加载
前言有一个朋友问我这个问题,刚好有时间,现在就简单的写个Demo~github|https://github.com/wangyang0210/bky/tree/picLoadLazy(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fwan
Stella981 Stella981
4年前
Fastdfs安装_nginx进行图片动态压缩
说明1.因为上传的图片较大,部分页面直接引用图片地址,则造成页面加载缓慢问题。2.考虑到服务器空间问题,我们没有进行上传缩略图。仅仅是上传了原图3.为了优化页面加载图片的时间问题,所以对图片进行动态缩放。PS:如果访问量较高,建议进行存储缩略图图片缩放采用nginx的http\_image\_filter\_module
深入理解 Flutter 图片加载原理 | 京东云技术团队
Flutter官方为我们提供了Image控件可实现图片的加载及显示,Image控件本身是一个StatefulWidget,那么在图片显示过程中是如何加载及显示出来的呢?本篇文章将逐步分析Flutter中图片加载原理,理解了Flutter图片源码的加载原理后对我们有什么帮助?
程序员小五 程序员小五
1年前
融云IM干货丨有没有插件能帮我优化uni-app的页面加载速度?
根据您的需求,以下是一些可以帮助优化uniapp页面加载速度的插件和方法:1.图片懒加载插件:使用图片懒加载可以显著减少首屏的加载时间。可以在页面滚动时才加载图片,减少初次加载的压力。2.代码拆分和懒加载:根据页面和功能的使用情况,将代码拆分为多个模块,并