通过图片懒加载带你了解两个超神的js方法

前言

图片懒加载也是一个很重要的前端优化的点,也是一个经常考的一个面试手写,原理有点类似于虚拟列表。

实现

先说一说具体思路,一个img标签,当它的src属性没有值的时候,它是不会发送接口请求的。只有当他的src有值的时候才会发送请求。因此我们先将src属性设成空值,同时给img加上一个我们自己写的属性data-original用来储存我们想要请求图片的地址。

js 复制代码
<body>
<img src="" data-original="图片地址" alt="">
<img src="" data-original="图片地址" alt="">
<img src="" data-original="图片地址" alt="">
</body>

我们直接在body里放置10个图片,我们通过获取它相对于浏览器窗口顶部的来确定其是否需要被加载,需要被加载的图片我们就将其src属性赋上data-original的值。

js 复制代码
// 获取可视窗口高度
const viewHeight = document.documentElement.clientHeight
    function lazyLoad(){
    // 获取所有带有data-original属性的img标签
    const imgs = document.querySelectorAll('img[data-original]')
    imgs.forEach(item=>{
    let rect = item.getBoundingClientRect()
    if(rect.top<viewHeight){
        item.src = item.dataset.original
        item.removeAttribute('data-original')// 移除属性就不会被获取也就遍历不到了
    }
    })
    }
    document.addEventListener('scroll', lazyLoad)
    lazyLoad()// 先调用一次让页面初始图片被加载

这个图片的懒加载的关键就是getBoundingClientRect()方法,这个方法能够获取元素的几何属性

也是一个在实战中很好用的方法了,大家可以记住一下。不过它有个缺点就是也是会像offset那些方法一样会把渲染队列清空。

IntersectionObserver

这个方法是用来监听目标元素与其祖先或视窗交叉状态。也就是目标元素和祖先或者视窗是否相交,甚至相交多少都能用它来判断。

js 复制代码
const io = new IntersectionObserver(
    (entries)=>{
        console.log(entries)
},
{threshold:[0],
root:box,
rootMargin:0})

它接收两个参数,先说第二个参数。是个对象,其中threshold是阈值,当目标元素和祖先或者视窗交叉状态达到阈值时就会触发第一个参数里的回调,它可以是多个阈值,以数组方式存储

接着是root,也就是我们说的目标元素的祖先或者视窗,不写的话默认写当前视窗。其次是rootMargin,是相对于root元素往外拓展的外边距,可以写上右下左四个方向的外边距。

第一个参数中的回调函数自带一个参数,我们打印这个参数看看。

我们能看到甚至有我们上面讲的boundingClientRect,下面说说这几个参数含义

  1. intersectionRatio 代表目标元素和视窗交叉的比率,0~1
  2. intersectionRect 代表交叉区域的几何信息
  3. isIntersecting 目标元素是否与视口交叉
  4. rootBounds 根元素或视口的几何信息
  5. isVisible 目标元素是否可见
  6. target 被观察的目标元素
  7. time 目标元素可见性发生变化的瞬间时间戳
js 复制代码
io.observe(item)

这样就监听了item元素。通过这个方法来实现图片懒加载实在是再合适不过。

js 复制代码
const io = new IntersectionObserver((entries)=>{
entries.forEach(entry=>{
    if(entry.isIntersecting){
    entry.target.src = entry.target.dataset.original
    entry.target.removeAttribute('data-original')
    io.unobserve(entry.target)// 取消观察
    }
})
})
const imgs = document.querySelectorAll('img[data-original]')
    imgs.forEach(item => {
        io.observe(item)
    })

这个方法相较于使用getBoundingClientRect()方法,首先就是他不会强制清空渲染队列,性能上有一定的优化。其次还有就是他无论你在哪刷新页面都只会加载页面上能显示的那几张图片,而不会在底下刷新就将底下到顶部的图片全部加载。

尾声

这两个方法都十分强大,除去图片的懒加载还有很多很好用的应用场景。用好了是能够有奇效的。这篇文章如果有帮到大家的话,帮我点个赞吧,谢谢。

相关推荐
golitter.5 分钟前
Ajax和axios简单用法
前端·ajax·okhttp
PleaSure乐事15 分钟前
【Node.js】内置模块FileSystem的保姆级入门讲解
javascript·node.js·es6·filesystem
雷特IT25 分钟前
Uncaught TypeError: 0 is not a function的解决方法
前端·javascript
长路 ㅤ   1 小时前
vite学习教程02、vite+vue2配置环境变量
前端·vite·环境变量·跨环境配置
亚里士多没有德7751 小时前
强制删除了windows自带的edge浏览器,重装不了怎么办【已解决】
前端·edge
micro2010141 小时前
Microsoft Edge 离线安装包制作或获取方法和下载地址分享
前端·edge
.生产的驴1 小时前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
awonw1 小时前
[前端][easyui]easyui select 默认值
前端·javascript·easyui
老齐谈电商1 小时前
Electron桌面应用打包现有的vue项目
javascript·vue.js·electron