图片懒加载
其实已经是一个近乎“烂大街”的词语了,在大大小小的面试中也会被频繁的问到,我在之前的面试中也被问到了图片懒加载的原因、实现方式及底层原理
,但由于自己平时很少做“图片”相关的处理,对于“懒加载”也是知之甚少,所以在面试中问答的也不是很好。
今天,我将首先从浏览器底层渲染机制
来剖析为什么要去做图片懒加载,之后我将带大家一起来看下目前主流的几种实现图片懒加载的方式及其实现原理,最后会做一个展望。
要问答这个问题,首先我们先来看下浏览器的底层渲染机制:
1、构建 DOM 树
2、样式计算
3、布局阶段
4、分层
5、绘制
6、分块
7、光栅化
8、合成
而在构建DOM
的过程中如果遇到img
在新老版本的chrome
中表现又是不一样的:
当你打开一个网站时,浏览器会做许多工作,这其中包括下载各种可能用到的资源,然后渲染呈现在你面前,假设你的网站有大量的图片,那么加载的过程是很耗时的,尤其像那些电商类需要大量图片的网站,可想而知,网站的初始加载时间会很长,再加上网络等其它影响,用户体验会很差。
相信你经常遇到过一个网站卡在某个地方,一直在加载,这种体验很不好。我们都希望一输入网址,页面立马就呈现在眼前。
总结一下就是:直接全部加载的话会减缓渲染速度,产生白屏等进而影响用户体验
。
先来看几个后面会用到的API
获取屏幕可视区域的高度。
“图片来源MDN[1]
获取元素相对于文档顶部的高度。
“图片来源阮一峰博客[2]
获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离。
“图片来源Seven's Blog
通过上面三个 API,我们获得了三个值:可视区域的高度、元素相对于其父元素容器顶部的距离、浏览器窗口顶部与容器元素顶部的距离也就是滚动条滚动的高度。
虽然这几个API
很简单,但是单纯的去说还是有点抽象,这里我们还是用图来展示一下:
看完上面这张图片,我想你已经明白了:如果满足offsetTop-scroolTop<clientHeight
,则图片进入了可视区内,我们就去请求进入可视区域的图片。
基于上面的分析,我们很容易就可以写出如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>基于原生 js 实现图片懒加载</title>
<style>
img {
display: block;
width: 100%;
height: 300px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<img data-src="./img/1.png" alt="">
<img data-src="./img/2.png" alt="">
<img data-src="./img/3.png" alt="">
<img data-src="./img/4.png" alt="">
<img data-src="./img/5.png" alt="">
<img data-src="./img/6.png" alt="">
<img data-src="./img/7.png" alt="">
<img data-src="./img/8.png" alt="">
</body>
<script>
var imgs = document.querySelectorAll('img');
//offsetTop是元素与offsetParent的距离,循环获取直到页面顶部
function getRealTop(e) {
var realTop = e.offsetTop;
while(e = e.offsetParent) {
realTop += e.offsetTop;
}
return realTop;
}
function lazyLoad(imgs) {
var H = document.documentElement.clientHeight;//获取可视区域高度
var S = document.documentElement.scrollTop || document.body.scrollTop;
for (var i = 0; i < imgs.length; i++) {
if (H + S > getRealTop(imgs[i])) {
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}
window.onload = window.onscroll = function () { //onscroll()在滚动条滚动的时候触发
lazyLoad(imgs);
}
</script>
</html>
“但上面的代码如果你在
lazyLoad
中打印,你会发现滚动条上下滚动时,lazyLoad
会被频繁调用,造成很大的性能损失,这里我们可以给事件加上节流throttle
先来了解一下这个API
吧:
getBoundingClientRect()
用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。getBoundingClientRect()
是DOM
元素到浏览器可视范围的距离(不包含页面看不见的部分)。
该函数返回一个rectObject
对象,该对象有 6 个属性:top
, left
, bottom
, right
, width
, height
;这里的top
、left
和css
中的理解很相似,width
、height
是元素自身的宽高,但是right
,bottom
和css
中的理解有点不一样。right
是指元素右边界距窗口最左边的距离,bottom
是指元素下边界距窗口最上面的距离。
通过这个 API,我们就很容易获取img
元素相对于视口的顶点位置rectObject.top
,只要这个值小于浏览器的高度window.innerHeight
就说明进入可视区域:
function isInSight(el){
const bound = el.getBoundingClientRect();
const clientHeight = window.innerHeight;
return bound.top <= clientHeight;
}
这里结合第一种实现方式,做下改造,就得到了:
function loadImg(el){
if(!el.src){
const source = el.getAttribute('data-src');;
el.src = source;
}
}
function checkImgs(){
const imgs = document.querySelectorAll('img');
Array.from(imgs).forEach(el =>{
if (isInSight(el)){
loadImg(el);
}
})
}
window.onload = function(){
checkImgs();
}
document.onscroll = function () {
checkImgs();
}
同样,还是先来看一下概念。
“这里我们参考阮一峰大佬关于IntersectionObserver API[3]的介绍。
我们在平时的开发中,常常需要了解某个元素是否进入了"视口"(viewport),即用户能不能看到它。
上图的绿色方块不断滚动,顶部会提示它的可见性。
传统的实现方法是,监听到scroll
事件后,调用目标元素(绿色方块)的getBoundingClientRect()
方法,得到它对应于视口左上角的坐标,再判断是否在视口之内。这种方法的缺点是,由于scroll
事件密集发生,计算量很大,容易造成性能问题。
目前有一个新的 IntersectionObserver API
,可以自动"观察"元素是否可见,Chrome 51+
已经支持。由于可见(visible
)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做交叉观察器
。
它的用法也非常简单。
var io = new IntersectionObserver(callback, option);
上面代码中,IntersectionObserver
是浏览器原生提供的构造函数,接受两个参数:callback
是可见性变化时的回调函数,option
是配置对象(该参数可选)。
构造函数的返回值是一个观察器实例。实例的observe
方法可以指定观察哪个 DOM
节点。
// 开始观察
io.observe(document.getElementById('container'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();
上面代码中,observe
的参数是一个 DOM
节点对象。
如果要观察多个节点,就要多次调用这个方法。
io.observe(elementA);
io.observe(elementB);
看完相关的API
,下面就让我们基于IntersectionObserver
来实现图片懒加载:
const imgs = document.querySelectorAll('img') //获取所有待观察的目标元素
var options = {}
function lazyLoad(target) {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entrie => {
if (entrie.isIntersecting) {
const img = entrie.target;
const src = img.getAttribute('data-src');
img.setAttribute('src', src)
observer.unobserve(img); // 停止监听已开始加载的图片
}
})
}, options);
observer.observe(target)
}
imgs.forEach(lazyLoad)
img.loading=lazy
最后这种相对就简单很多了,它是 Chrome
自带的原生 lazyload
属性。我们先来看下他在各大浏览器的支持程度:
“其实支持程度还不是特别好,我们你的应用对于浏览器兼容性要求比较高的话,建议还是先观望一波~
它的使用也非常简单,如标题所示:
<img src="example.jpg" loading="lazy" alt="zhangxinxu" width="250" height="150">
关于原生懒加载 loading=”lazy”的更多介绍可以参考张鑫旭大佬的浏览器 IMG 图片原生懒加载 loading=”lazy”实践指南[4]。
[1]MDN: https://developer.mozilla.org/zh-CN/docs/Web/API/Element/clientHeight
[2]阮一峰博客: http://www.ruanyifeng.com/blog/2009/09/find_element_s_position_using_javascript.html
[3]IntersectionObserver API: http://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html
[4]浏览器 IMG 图片原生懒加载 loading=”lazy”实践指南: https://www.zhangxinxu.com/wordpress/2019/09/native-img-loading-lazy/
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/jpmbU-UqYsPbl1i8Nnmr4Q
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。