在日常页面开发中,常常会涉及到图片的展示。有时候当图片资源过多时,我们希望能将图片延迟加载,同时当图片加载失败后,能用一张默认图片去代替其进行展示。其效果如图所示:
一、图片懒加载
其实图片懒加载的核心思想很简单:
- 通过预先将图片的src资源指向一张小图片或空,并通过
data-src
来记录其实际图片地址。 - 通过延迟加载或监听滚动事件(图片出现在可视区域中), 将
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
标签
大多数的时候,图片所处位置的宽高都是固定的。但是图片实际的宽高都是未知的,图片宽高的设置方式有:
- 直接将
img
的宽高设置为img { width: 100%; height: 100%; }
可能会出现图片严重失真。 - 通过设置最大宽高的方式
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前端优化之图片优化