手把手教你实现js懒加载

js懒加载问题是个非常容易被问到的面试点,如果你还不清楚如何实现,不妨一起学习下

懒加载

所谓懒加载就是需要使用你的时候再加载,通常就是浏览网页的时候,你下拉很多图片的网页,边拉边加载,你可以看得出来下面的图片在展现你面前之前是没有加载出来的

自己实现

我们自行去网络上搜10张图,然后给10张图加个样式,让它们成一个块级元素,从上到下显示

xml 复制代码
<style>
    .img-item {
        display: block;
        height: 300px;
        margin-top: 50px;
    }
</style>
ini 复制代码
<body>
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.5053ecdbef05fa7726aa489d27b52e40&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.c5db2c88af1a76f18d0efe02fcded91d&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.c5129de8701c4a933d92cd6bf832b233&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.afe7f6448d6eba0055cd8ce9ac9fdf62&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.e168b9c5da30772083104ed0f4ef0ecf&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.8025ce5a977b3826589022cede69e110&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.a58ae29e32e20a27d498eed19528ee3c&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.2049b527600b31b2cd863a380be59848&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.9f51912b8b6c19a9891b380ad526db85&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
    <img class='img-item' src="https://th.bing.com/th?id=ORMS.1b6375ea147b5704f9d073a326e1fc2a&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
</body>

想要让这些图片进入到可视区内加载,进入之前不加载,就需要去动src,src有值了就一定会去加载,所以我们可以先把url放到另一个伪属性中去,等到了图片进入到可视区内再去把伪属性的url赋给src

如何获取元素的几何信息?

top和bottom都是自己到最顶部的距离,均已浏览器顶部为准

querySelector是获取第一个元素,你会发现getBoundingClientRect给你拿到了bottom和top属性

只要每个图片的top值比窗口的高度小,那么就代表着图片进入可视区范围内

ini 复制代码
imgs.forEach(el => {
	let rect = el.getBoundingClientRect()
	if(rect.top < viewHeight) {
		// 赋值逻辑......
	}
})

data-original的值赋给src需要先交给第三方,这个第三方也需要是image标签,正常情况是需要createElement添加一个标签的,但是image标签非常之特殊,它本身就具有构造函数

ini 复制代码
let image = new Image()
image.src = el.dataset.original

data-有个专有写法就是dataset,因此data-original就是dataset.original

接下来,通过load事件来确保image这个标签在创建完成之前是不会执行赋值的

ini 复制代码
image.onload = function() {
    el.src = image.src 
}

这里肯定有小朋友要提出一个问题了,为何不直接写el.src = el.dataset.original。确实,这样写也没有问题,只不过浏览器对图片是有个缓存机制的,靠第三方的image标签纯粹是为了onload,看图片是否被浏览器加载完毕,加载完毕才把值赋过去,如果直接赋值,加载的时候是空白的,加载是需要时间的。Image对象的src属性设置为要加载的url时,浏览器会异步开始加载该图片,这样图片可能已经被缓存了,从而提高了加载速度

图片一旦加载就不需要二次加载了,所以我们把data-original这个属性移除掉

arduino 复制代码
el.removeAttribute('data-original')

因为imgs数组获取的时候就是获取带有data-original属性的图片

接下来就需要让用户滚动页面去触发这个事件,所以来一个监听滚动事件

javascript 复制代码
document.addEventListener('scroll', lazyLoad)

最终代码如下

xml 复制代码
<script>
    let viewHeight = window.innerHeight
    function lazyLoad() {
        let imgs = document.querySelectorAll('img[data-original]') 
        imgs.forEach(el => {
            let rect = el.getBoundingClientRect() 
            if(rect.top < viewHeight) {
                let image = new Image()
                image.src = el.dataset.original
                image.onload = function() {
                    el.src = image.src 
                }
                el.removeAttribute('data-original') 
            }
        })
    }
    lazyLoad() // 页面初始加载时调用一次
    document.addEventListener('scroll', lazyLoad)
</script>

边下划,src边被赋值,最终实现效果如下

最后

因为图片是非常占用浏览器性能的,懒加载的意义就是提高页面加载速度,降低资源浪费,提升用户体验。

懒加载的核心原理其实就是通过一个伪src属性,当图片到达了可视区范围内,就将伪src属性赋值给src

另外有不懂之处欢迎在评论区留言,如果觉得文章对你学习有所帮助,还请"点赞+评论+收藏"一键三连,感谢支持!

本次学习代码已上传至本人GitHub学习仓库:github.com/DolphinFeng...

相关推荐
神之王楠4 分钟前
如何通过js加载css和html
javascript·css·html
余生H8 分钟前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
程序员-珍11 分钟前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
axihaihai16 分钟前
网站开发的发展(后端路由/前后端分离/前端路由)
前端
流烟默28 分钟前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
2401_8572979138 分钟前
招联金融2025校招内推
java·前端·算法·金融·求职招聘
茶卡盐佑星_1 小时前
meta标签作用/SEO优化
前端·javascript·html
与衫1 小时前
掌握嵌套子查询:复杂 SQL 中 * 列的准确表列关系
android·javascript·sql
Ink1 小时前
从底层看 path.resolve 实现
前端·node.js
金灰1 小时前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5