html如何实现页面懒加载,原生JS如何实现图片懒加载

懒加载简介

什么是图片懒加载

懒加载其实就是延迟加载,是一种对网页性能优化的方式,比如当访问一个页面的时候,优先显示可视区域的图片而不一次性加载所有图片,当需要显示的时候再发送图片请求,避免打开网页时加载过多资源。

什么时候用懒加载

当页面中需要一次性载入很多图片的时候,往往都是需要用懒加载的。

懒加载原理

我们都知道HTML中的标签是代表文档中的一个图像。。说了个废话。。

标签有一个属性是src,用来表示图像的URL,当这个属性的值不为空时,浏览器就会根据这个值发送请求。如果没有src属性,就不会发送请求。

嗯?貌似这点可以利用一下?

我先不设置src,需要的时候再设置?

nice,就是这样。

我们先不给设置src,把图片真正的URL放在另一个属性data-src中,在需要的时候也就是图片进入可视区域的之前,将URL取出放到src中。

图片懒加载如何实现

HTML结构

loading

loading

loading

loading

loading

仔细观察一下,标签此时是没有src属性的,只有alt和data-src属性。

alt 属性是一个必需的属性,它规定在图像无法显示时的替代文本。

data-* 全局属性:构成一类名称为自定义数据属性的属性,可以通过HTMLElement.dataset来访问。

如何判断元素是否在可视区域

方法一

网上看到好多这种方法,稍微记录一下。

通过document.documentElement.clientHeight获取屏幕可视窗口高度

通过element.offsetTop获取元素相对于文档顶部的距离

通过document.documentElement.scrollTop获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离

然后判断②-③

方法二(推荐)

通过getBoundingClientRect()方法来获取元素的大小以及位置,MDN上是这样描述的:

The Element.getBoundingClientRect() method returns the size of an element and its position relative to the viewport.

这个方法返回一个名为ClientRect的DOMRect对象,包含了top、right、botton、left、width、height这些值。

MDN上有这样一张图:

d2e6e7342a9716df1d5e56ef623f98e1.png

可以看出返回的元素位置是相对于左上角而言的,而不是边距。

我们思考一下,什么情况下图片进入可视区域。

假设const bound = el.getBoundingClientRect();来表示图片到可视区域顶部距离;

并设 const clientHeight = window.innerHeight;来表示可视区域的高度。

随着滚动条的向下滚动,bound.top会越来越小,也就是图片到可视区域顶部的距离越来越小,当bound.top===clientHeight时,图片的上沿应该是位于可视区域下沿的位置的临界点,再滚动一点点,图片就会进入可视区域。

也就是说,在bound.top<=clientHeight时,图片是在可视区域内的。

我们这样判断:

function isInSight(el) {

const bound = el.getBoundingClientRect();

const clientHeight = window.innerHeight;

//如果只考虑向下滚动加载

//const clientWidth = window.innerWeight;

return bound.top <= clientHeight + 100;

}

这里有个+100是为了提前加载。

方法三 IntersectionObserver

IntersectionObserver可以自动观察元素是否在视口内。

var io = new IntersectionObserver(callback, option);

// 开始观察

io.observe(document.getElementById('example'));

// 停止观察

io.unobserve(element);

// 关闭观察器

io.disconnect();

callback的参数是一个数组,每个数组都是一个IntersectionObserverEntry对象,包括以下属性:

属性描述time可见性发生变化的时间,单位为毫秒

rootBounds与getBoundingClientRect()方法的返回值一样

boundingClientRect目标元素的矩形区域的信息

intersectionRect目标元素与视口(或根元素)的交叉区域的信息

intersectionRatio目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0

target被观察的目标元素,是一个 DOM 节点对象

我们需要用到intersectionRatio来判断是否在可视区域内,当intersectionRatio > 0 && intersectionRatio <= 1即在可视区域内。

代码

function checkImgs() {

const imgs = Array.from(document.querySelectorAll(".my-photo"));

imgs.forEach(item => io.observe(item));

}

function loadImg(el) {

if (!el.src) {

const source = el.dataset.src;

el.src = source;

}

}

const io = new IntersectionObserver(ioes => {

ioes.forEach(ioe => {

const el = ioe.target;

const intersectionRatio = ioe.intersectionRatio;

if (intersectionRatio > 0 && intersectionRatio <= 1) {

loadImg(el);

}

el.onload = el.onerror = () => io.unobserve(el);

});

});

加载图片

页面打开时需要对所有图片进行检查,是否在可视区域内,如果是就加载。

function checkImgs() {

const imgs = document.querySelectorAll('.my-photo');

Array.from(imgs).forEach(el => {

if (isInSight(el)) {

loadImg(el);

}

})

}

function loadImg(el) {

if (!el.src) {

const source = el.dataset.src;

el.src = source;

}

}

这里应该是有一个优化的地方,设一个标识符标识已经加载图片的index,当滚动条滚动时就不需要遍历所有的图片,只需要遍历未加载的图片即可。

函数节流

在类似于滚动条滚动等频繁的DOM操作时,总会提到“函数节流、函数去抖”。

所谓的函数节流,也就是让一个函数不要执行的太频繁,减少一些过快的调用来节流。

基本步骤:

获取第一次触发事件的时间戳

获取第二次触发事件的时间戳

时间差如果大于某个阈值就执行事件,然后重置第一个时间

function throttle(fn, mustRun = 500) {

const timer = null;

let previous = null;

return function() {

const now = new Date();

const context = this;

const args = arguments;

if (!previous){

previous = now;

}

const remaining = now - previous;

if (mustRun && remaining >= mustRun) {

fn.apply(context, args);

previous = now;

}

}

}

这里的mustRun就是调用函数的时间间隔,无论多么频繁的调用fn,只有remaining>=mustRun时fn才能被执行。

方案二图片懒加载完整demo

下载链接:https://pan.baidu.com/s/10mSvEY05FXnZzq7XZfy8IA

提取码:m45r

来源地址:https://github.com/axuebin/articles/issues/1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值