手把手教你实现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...

相关推荐
理想不理想v2 分钟前
webpack如何自定义插件?示例
前端·webpack·node.js
小华同学ai20 分钟前
ShowDoc:Star12.3k,福利项目,个人小团队的在线文档“简单、易用、轻量化”还专门针对API文档、技术文档做了优化
前端·程序员·github
一雨方知深秋20 分钟前
智慧商城:封装getters实现动态统计 + 全选反选功能
开发语言·javascript·vue2·foreach·find·every
海威的技术博客23 分钟前
关于JS中的this指向问题
开发语言·javascript·ecmascript
王解37 分钟前
Vue CLI 脚手架创建项目流程详解 (2)
前端·javascript·vue.js
刘大浪40 分钟前
vue.js滑动到顶便锁定位置
前端·javascript·vue.js
小金刚®1 小时前
构建简洁之美:我的第一个前端页面
前端
ordinary901 小时前
指令-v-for的key
前端·javascript·vue.js
rpa_top1 小时前
RPA 助力电商:自动化商品信息上传,节省人力资源 —— 以影刀 RPA 为例【rpa.top】
大数据·前端·人工智能·自动化·rpa
新时代农民工--小明1 小时前
前端自动化部署更新,自动化打包部署
运维·前端·自动化