JS | 详解图片懒加载的6种实现方案

目录

一、什么是懒加载?

二、为什么要懒加载?

三、图片懒加载的实现原理

四、图片懒加载实现方式

3.1 方案一:设置 img 标签属性 loading=“lazy”

3.2  方案二:利用JS监听scroll滚动事件

3.3 方案三:利用元素的 getBoundingClientRect 方法实现

3.4. 方案四:IntersectionObserver

3.5 方案五:利用element-ui 的组件的lazy属性开启懒加载功能

3.6 方案六:使用vue-lazyLoad插件实现


一、什么是懒加载?

懒加载是一种对网页性能优化的方式,比如,当访问一个网页的时候,优先显示可视区域的图片而不是一次加载全部的图片,当需要显示时,再发送请求加载图片。

懒加载 :延迟加载,对于一个很长的页面,优先加载可视区域的内容,其他部分等进入可视区域时再加载。 

二、为什么要懒加载?

懒加载是一种网页性能优化的方式,它能极大的提升用户体验。比如一个页面中有很多图片,但是首屏只出现几张,这时如果一次性把图片全部加载出来会影响性能。这时可以使用懒加载,页面滚动到可视区再加载。优化首屏加载。

一次性加载全部图片的话,一方面会影响用户体验;另一方面浪费用户的流量,有些用户并不想全部看完,全部加载会耗费大量流量。 而使用图片懒加载就会使页面加载速度快,减轻服务器压力,节约流量,用户体验好。

当页面需要展示大量图片时,如果一次性渲染所有图片,会向服务器发出大量请求,导致服务器响应慢,出现页面卡顿或崩溃等问题。采用懒加载技术只预先加载可视区内的图片,当滚动到其他位置时,才去加载这块区域的图片,也可以使用比较小的loading图片进行占位,有效减轻服务器的压力,加速页面渲染,提高用户体验。     

小结——懒加载优点

  • 避免首次加载时消耗大量时间,降低页面渲染速度,造成卡顿现象。
  • 按需加载,避免无效图片的加载,减轻服务器压力,节约网络资源。

三、图片懒加载的实现原理

  •  基本原理 监听图片是否位于页面的可视区域内,若在则加载图片,不在则不加载图片
  •  实现方案 自定义属性-将图片真实地址 url 存储在自定义属性中,当监听到图片进入可视区 域 时,将自定义属性值赋值给 img 的 src 属性

四、图片懒加载实现方式

图像是页面的一部分,它会提前开始加载。一旦浏览器在源代码中看到它们,就会提示下载。即使图像被隐藏,即使它位于一个非常长的页面的底部,也会提前加载。

3.1 方案一:设置 img 标签属性 loading=“lazy”

设置 loading="lazy"允许浏览器,延迟加载屏幕外图像 img 和 iframe,直到用户滚动到它们附近。

loading属性支持下面这几个值:

① lazy:图片或框架懒加载,也就是元素资源快要被看到的时候加载。

② eager:图片或框架无视一切进行加载。

③ auto:默认值。

图片或框架基于浏览器自己的策略进行加载。如果HTMLImageElement或者HTMLIFrameElement元素没有显式地设置loading属性或者loading属性的值不合法,则都被当作’auto’处理。

<img src="" loading="lazy"/>
<iframe src="" loading="lazy"/>
  • Lazy loading加载数量与屏幕高度有关,高度越小加载数量越少,但并不是线性关系。
  • Lazy loading加载数量与网速有关,网速越慢,加载数量越多,但并不是线性关系。
  • 滚动即会触发图片懒加载,而不是滚动一屏后再去加载。
  • 窗口resize尺寸变化也会触发图片懒加载,当屏幕高度从小变大的时候。

3.1.1 loading 属性的兼容

loading 属性的兼容性如下:

3.1.2 如何判断当前浏览器是否支持loading=”lazy”?

下面三种方法都可以:

var isSupportLoading = 'loading' in document.createElement('img');
var isSupportLoading = 'loading' in new Image();
var isSupportLoading = 'loading' in HTMLImageElement.prototype;

例:您可以通过检查HTMLImageElement.prototype上是否存在loading属性来判断当前浏览器是否支持loading="lazy"特性。以下是一个简单的JavaScript代码示例: 

function isLazyLoadingSupported() {
    // 检查'loading'属性是否在HTMLImageElement.prototype上定义
    return 'loading' in HTMLImageElement.prototype;
}
 
if (isLazyLoadingSupported()) {
    console.log('Lazy loading is supported.');
} else {
    console.log('Lazy loading is not supported.');
}

如果isLazyLoadingSupported()函数返回true,则当前浏览器支持loading="lazy";如果返回false,则不支持。 

3.1.3. 如何获取loading属性值

var attrLoading = img.loading;

如果浏览器并不支持原生的loading懒加载,则会返回undefined,例如在Firefox浏览器下

3.2  方案二:利用JS监听scroll滚动事件

3.2.1. 实现原理

监听scroll事件,获取 img 元素相对于视口的顶点位置 el.getBoundingClientRect().top,只要这个值小于浏览器的高度 window.innerHeight 就说明进入可视区域,当图片进入可视区域时再去加载图片资源。

图片刚开始显示的是默认图片,当进入可视区域时,用 data-src 的真实图片地址赋值给 src

3.2.2. 实现方案

① 首先给图片一个占位资源:

<img src="default.jpg" data-src="http://www.xxx.com/target.jpg" />

② clientHeight、scrollTop 和 offsetTop

属性介绍

 获得浏览器窗口(视口)大小: 2组:

1、获取文档显示区 / 网页可见区域大小

对于Internet Explorer9+、Chrome、Firefox、Opera 以及 Safari

window.innerWidth、window.innerHeight | Window innerWidth 与 innerHeight 属性 | 参考手册

window.innertHeight :  浏览器窗口的内部高度

  • A 表示window的内部高度包含border、paddingmargin以及水平滚动条的高度
  • B 语法:window.innertHeight

window.innerWidth:  浏览器窗口的内部宽度

  • A 表示window的内部宽度包括 border、paddingmargin以及垂直滚动条的宽度
  • B 语法:window.innerWidth

对于 Internet Explorer 8、7、6、5

element.clientHeight、element.clientWidth

document.body.clientHeight : 表示的是<body>元素的内容区域高度

  • A 表示的是<body>元素的内容区域高度,包含padding 不包含 border 和 margin以及水平滚动条的高度
  • B 语法:element.clientHeight

document.body.clientWidth : 表示的是<body>元素的内容区域宽度

  • A 表示的是<body>元素的内容区域宽度,包含padding 不包含 border 和 margin以及垂直滚动条的宽度
  • B 语法:document.body.clientWidth

或者

document.documentElement.clientHeight:表示的是整个视口的高度

  • A 表示的是整个视口的高度,即整个网页的可视区域高度,包含padding 不包含 border 和 margin以及水平滚动条的高度
  • B 语法:document.documentElement.clientHeight

document.documentElement.clientWidth:表示的是整个视口的宽度

  • A 表示的是整个视口的宽度,即整个网页的可视区域宽度,包含padding 不包含 border 和 margin以及垂直滚动条的宽度
  • B 语法:document.documentElement.clientWidth

参考:JS | 深入理解客户区尺寸client

✔ 实用的获取页面大小的浏览器兼容性JavaScript 方案(涵盖所有浏览器):

var w=window.innerWidth || document.documentElement.clientWidth
|| document.body.clientWidth;
 
var h=window.innerHeight || document.documentElement.clientHeight
|| document.body.clientHeight;

补:‌document.documentElement.clientHeight与document.body.clientHeight的主要区别在于它们代表的网页区域不同。

  • document.documentElement.clientHeight‌ 表示的是整个视口的高度,即整个网页的可视区域高度。它包括了padding但排除了border、水平滚动条和margin的高度‌。
  • document.body.clientHeight‌ 表示的是<body>元素的内容区域高度,通常不包括滚动条的高度。如果<body>元素没有设置高度或者其高度小于其内部内容的高度,则可能会显示不全‌。

影响这两个属性值的主要因素包括‌:

  • CSS设置‌:如果<body>元素的CSS高度被设置为100%,并且包含了所有的内容高度,那么document.body.clientHeight将反映整个视口的高度。相反,如果<html>元素的CSS高度被设置为100%,而<body>元素的高度未明确设置,那么document.documentElement.clientHeight将反映整个视口的高度,而document.body.clientHeight可能为0或小于视口高度‌。
  • DOCTYPE声明‌:缺少DOCTYPE声明可能会导致document.documentElement.clientHeight为0,因为浏览器可能无法正确解析文档类型,从而影响元素的默认显示和尺寸计算‌。

实际应用中的注意事项‌:

  • 在开发过程中,应注意DOCTYPE的声明和CSS的设置,以确保页面布局的正确显示。如果需要获取整个视口的高度,应使用document.documentElement.clientHeight;如果需要获取<body>元素的内容高度,应确保<body>元素的CSS高度设置正确‌。
  • 在调试页面布局时,可以使用浏览器的开发者工具查看这些属性的值,帮助定位问题所在‌

参考:document.documentElement.clientHeight与document.body.clientHeight的区别-CSDN博客

补:document.body.clientWidth和window.innerWidth的主要区别在于是否包含滚动条和边框。

document.body.clientWidth表示浏览器窗口中文档主体部分的视口宽度,这个值包括了文档主体的内容区域宽度,但不包括滚动条的宽度。如果文档主体有边框,这个值也不包括边框的宽度。相反,window.innerWidth表示浏览器窗口的内视口宽度,这个值包括了视口内部的全部宽度,即包括了滚动条的宽度(如果存在的话)‌。

此外,document.body.clientWidthwindow.innerWidth的区别还受到
文档模式的影响。在混杂模式(BackCompat)下,document.body.clientWidthwindow.innerWidth的值可能不同,因为混杂模式下文档主体的宽度计算不包括滚动条。而在标准模式(CSS1Compat)下,两者的值通常是相同的,因为此时文档的宽度计算包括了滚动条‌

2、完整窗口大小: window.outerWidth   window.outerHeight

offsetTop : 距离父级元素顶部的高度

  • A 表示当前元素相对于其offsetParent元素的顶部内边距的距离
  • B 语法:element.offsetTop

scrollTop : 网页被卷去的距离

A 表示在有滚动条时,滚动条向下滚动的距离也就是元素顶部被遮住部分的高度
B 语法:element.scrollTop                       

③ 接着,通过监听 scroll 事件来判断图片是否到达视口

let img = document.getElementsByTagName("img");
let num = img.length;
let count = 0; //存储图片加载到的位置,避免每次都从第一张图片开始遍历
 
lazyload(); // 首次加载别忘了显示图片
 
window.addEventListener('scroll', throttle(lazyload, 200)); // throttle是节流函数,自己实现一下
 
//offsetTop是元素与offsetParent的距离,循环获取直到页面顶部
function getTop(el) {
    var T = el.offsetTop;
    while(el = el.offsetParent) {
        T += el.offsetTop;
    }
    return T;
}
 
function lazyload() {
  let viewHeight = document.documentElement.clientHeight || document.body.clientHeight;//视口高度
  let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;//滚动条卷去的高度
  for(let i = count; i <num; i++) {
    // 元素现在已经出现在视口中
    if(getTop(img[i]) < scrollTop + viewHeight) {
      if(img[i].getAttribute("src") !== "default.jpg") continue;
      img[i].src = img[i].getAttribute("data-src");
      count ++;
    } else {
      break; // 提早退出
    }
  }
}

offsetParent 就是距离该子元素最近的进行过定位的父元素(position:absolute或relative 或fixed),如果其父元素中不存在定位,则offsetParent为:body元素

参考:JS | JS之元素偏移量 offset 系列属性详解

●小结:用JS监测这个方式主要是利用整体距离实现

(1)属性介绍:参看上面

(2)实现方法

可以用image.offsetTop <= document.documentElement.clientHeight + document.documentElement.scrollTop 判断图片是否可以在可视区域内。即判断图像的offsetTop(距离顶部的高度)- scrollTop(页面被卷去的高度)<=window.innerHeight(可视区高度)才加载

  • 图片元素位置的顶部距离:offsetTop
  • 滚动距离的最下端:scrollTop+clientHeight
  // html 标签结构
  <img data-src="./public/image/VCG211430870249.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211430987515.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211431054751.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211435102490.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211438229829.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211438109615.jpg" src="./public/image/默认.jpg" alt="">
<script>
  // 1 获取全部图片的DOM节点
  // 注意:querySelectorAll 值为伪数组利用扩展运算符转为真数组
  const images = [...document.querySelectorAll('img')]
  // 2 监听页面滚动事件
  window.addEventListener('scroll', lazyLoad)
  // 3 定义页面滚动的处理函数
  function lazyload(e) {
    // 3.1 获取屏幕的可视高度
    const clientHeight = document.documentElement.clientHeight
    // 3.2 获取屏幕的滚动距离
    const scrollTop = document.documentElement.scrollTop
    for (let i = 0; i < images.length; i++) {
      if (images[i].offsetTop < clientHeight + scrollTop) {
        images[i].setAttribute('src', images[i].getAttribute('data-src'))
      }
    }
  }
</script>

3.3 方案三:利用元素的 getBoundingClientRect 方法实现

getBoundingClientRect() 方法返回元素相对视口左上角的偏移量以及元素本身长宽,单位:px

修改上述 lazyload 函数

function lazyload() {
  let viewHeight = document.documentElement.clientHeight || document.body.clientHeight;
  for (let i = count; i < num; i++) {
    // 元素现在已经出现在视口中
    if (img[i].getBoundingClientRect().top < viewHeight) {
      if (img[i].getAttribute("src") !== "default.jpg") continue;
      img[i].src = img[i].getAttribute("data-src");
      count++;
    } else {
      break;
    }
  }
}

小结:我们再来举个例子,总结一下利用getBoundingClientRect 方法实现图片懒加载。

参考:JS | JS中的getBoundingClientRect()方法详解,秒懂!

(1)属性介绍:

利用 getBoundingClientRect()方法实时获取物体的动态位置

(2)实现方法:

步骤 1:监听页面滚动事件,lazyLoad为页面滚动时的处理函数,在本节为处理图片懒加载。

window.addEventListener('scroll', lazyLoad)

步骤 2:判断图片是否处于可视区域内

参考:JS代码如何利用getBoundingClientRect方法实现图片懒加载 – PingCode

(1)若距离顶部top(或bottom)小于页面的整体高度window.innerHeight

(2)若距离左侧left(或右侧right)小于页面的整体宽度window.innerWidth

(3)同时图片的底部bottom (或顶部top) 与图片的右侧right(左侧left)距页面顶部、左侧的距离均大于0,则说明该图在屏幕的可视区域内。 

为了提高复用性,我们可以将它封装成一个自定义函数isVisible,将每张图片作为参数传入该函数,并返回truefalse

// 可视区域判断函数
  function isVisible(img) {
    // 判断是否在可视区域,并返回true或false
    const imgRect = img.getBoundingClientRect() // getBoundingClientRect 获取图片的动态信息
    return imgRect.bottom > 0 && imgRect.top < (window.innerHeight|| document.documentElement.clientHeight) && imgRect.right > 0 && imgRect.left < (window.innerWidth||document.documentElement.clientWidth)
  }

步骤 3:定义图片懒加载时的处理事件,监听所有的img,判断该img是否处于可视范围内。

querySelectorAll 获取的元素为类数组对象,需要转为真数组,否则无法使用数组的某些方法

// 获取所有的img元素,并利用扩展运算符转为真数组
const images = [...document.querySelectorAll('img')]

步骤 4:对每张图片进行监听,利用自定义函数isVisible判断是否在可视区域内

(1)若处于可视区域:将自定义的data-src值,赋值给真正的src属性值,其中 data-src存储图片的URL地址,并删除该元素防止重复加载

(2)若不处于可视区域:return 不做处理

// 利用循环判断每张图片是否属于可视区域
function lazyLoad(){
    for (let i = 0; i < images.length; i++) {
    // isVisible是否该图片位于可视区域 返回true 或false
      if (isVisible(images[i])) {
        // 将元素的自定义属性 data-src 赋值给元素的 src 属性
        // 等价于:img.setAttribute('src', img.getAttribute('data-src'))
        images[i].src = images[i].dataset.src 
        // 防止重复被遍历 加载完之后 删除元素不再加载
        images.splice(i, 1)
        i--
      }
    }
}
lazyLoad()

getBoundingClientRect()方法的缺点:这个属性频繁计算会引发页面的重绘,可能会对页面的性能造成影响。 

3.4. 方案四:IntersectionObserver

有兼容性问题。这是浏览器内置的一个API,实现了监听window的scroll事件、判断是否在视口中以及节流三大功能。

let img = document.getElementsByTagName("img");
 
const observer = new IntersectionObserver(changes => {
  //changes 是被观察的元素集合
  for(let i = 0, len = changes.length; i < len; i++) {
    let change = changes[i];
    // 通过这个属性判断是否在视口中
    if(change.isIntersecting) {
      const imgElement = change.target;
      imgElement.src = imgElement.getAttribute("data-src");
      observer.unobserve(imgElement);
    }
  }
})
Array.from(img).forEach(item => observer.observe(item));

这样就很方便地实现了图片懒加载,当然这个IntersectionObserver也可以用作其他资源的预加载,功能非常强大。原文链接:https://blog.csdn.net/qq_44741577/article/details/139324747

小结:关于IntersectionObserver

Intersection Observer是一个比较新的api,他允许你追踪目标元素与其祖先元素或视窗的交叉状态,用他来检测图片是否进入视口非常方便,不用再像之前绑定事件、计算距离等。

(1)属性介绍:

  • 利用Intersection Observer实例上的observe和unobserve方法,注册或取消监听事件。
  • 利用isIntersecting方法,判断该图片是否处于图片与屏幕可视区域的交叉范围内。
  • 注意:Intersection Observer实例会监听交叉状态,即出现和消失(触发两次),出现交叉状态后会去调用new的时候传入的callback回调函数

(2)实现方法:

步骤 1: 监听页面滚动事件,lazyLoad为页面滚动时的处理函数,在本节为处理图片懒加载。

window.addEventListener('scroll', lazyLoad)

步骤 2: 创建图片与可视区域交叉实例

callback

  • 此为传入的回调函数,用于当处于交叉状态改变时进行的处理函数
  • 该函数会被触发2次:图片进入视野时+图片离开视野时
 const observer = new IntersectionObserver(callback)

步骤 3: 利用observer实例上的.observe(img)方法,给每张图片绑定观察事件

// 给每一个图片绑定观察方法
  imagess.forEach(img => {
    // 图片进入视野+离开视野时会触发callback回调函数
    observer.observe(img)
  })

步骤 4: 定义图片的懒加载事件

imgArr:

  • 可以获得包含所有图片的isIntersecting属性的集合,该属性可判断是否在交叉区域内
  • target为该图片的标签元素

// callback 接收的参数为带有监听所有图片交叉属性的集合
const callback = (imgArr) => {
  console.log("视图交叉时触发,离开交叉时也触发", imgArr);
  imgArr.forEach((e) => {
    // 判断是否在视野区域
    if (e.isIntersecting) {
      e.target.src = e.target.dataset.src;
      // 取消监听,避免重复加载同一张图片
      observer.unobserve(e.target);
    }
  });
};

(3)完整代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <img data-src="./public/image/VCG211430870249.jpg" src="./public/image/默认.jpg" alt="" />
    <img data-src="./public/image/VCG211430987515.jpg" src="./public/image/默认.jpg" alt="" />
    <img data-src="./public/image/VCG211431054751.jpg" src="./public/image/默认.jpg" alt="" />
    <img data-src="./public/image/VCG211435102490.jpg" src="./public/image/默认.jpg" alt="" />
    <img data-src="./public/image/VCG211438229829.jpg" src="./public/image/默认.jpg" alt="" />
    <img data-src="./public/image/VCG211438109615.jpg" src="./public/image/默认.jpg" alt="" />
    <script>
      // intersectionObserver 交叉观察 : 目标元素和可视窗口会产生交叉区域
      const imagess = [...document.querySelectorAll("img")];
      // 2.1 创建视觉交叉的观察实例
      const observer = new IntersectionObserver(callback);
      // 2.2 给每一个图片绑定观察方法
      imagess.forEach((img) => {
        // 2.3 图片进入视野+离开视野时触发 - 回调
        observer.observe(img);
      });
      // callback 接收的参数为带有监听所有图片交叉属性的集合
      const callback = (imgArr) => {
        console.log("视图交叉时触发,离开交叉时也触发", imgArr);
        imgArr.forEach((e) => {
          // 判断是否在视野区域
          if (e.isIntersecting) {
            e.target.src = e.target.dataset.src;
            // 取消观察追踪,避免重复加载同一张图片
            observer.unobserve(e.target);
          }
        });
      };
    </script>
  </body>
</html>

参考:JS | 图片懒加载之交叉观察器IntersectionObserver API 手把手教学 - 烤地瓜的CSDN博客

3.5 方案五:利用element-ui 的<el-image>组件的lazy属性开启懒加载功能

使用element-ui 的<el-image v-for="url in urls" :key="url" :src="url" lazy></el-iamge>可通过lazy开启懒加载功能,当图片滚动到可视范围内才会加载。

具体实现代码element-ui的 <el-image> Element - The world's most popular Vue UI framework 

<div class="demo-image__lazy">
  <el-image v-for="url in urls" :key="url" :src="url" lazy></el-image>
</div>

<script>
  export default {
    data() {
      return {
        urls: [
          'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
          'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
          'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
          'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
          'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
          'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
          'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
        ]
      }
    }
  }
</script>

3.6 方案六:使用vue-lazyLoad插件实现

使用vue-lazyLoad插件实现,安装【npm i vue-lazyload -S】,main.ts中进行注册

//main.ts
import VueLazyload from 'vue-lazyload'
app.use(VueLazyload,
    {preLoad: 1.3, //预加载的宽高比loading: 
    loadimage:"./assets/vue.svg", //图片加载状态下显示的图片
    // error: "", //图片加载失败时显示的图片
    attempt: 1, // 加载错误后最大尝试次数
})

页面中通过v-lazy使用

//xx.vue
<template>
  <div>
    <div v-for="item in arr" :key="item">
      <img v-lazy="item" width="600" height="200" alt="" />
    </div>
  </div>
</template>
 
<script lang="ts" setup>
//glob是懒加载模式,globEager静态加载
let imageList: Record<string, { default: string }> = import.meta.glob(
  "../assets/images/*.*",
  { eager: true }
);
let arr = Object.values(imageList).map((v) => v.default);
</script>
 
<style lang="scss" scoped></style>

使用vite的两种文件导入方式

  • 【import.meta.glob("/xx")】方式 为懒加载模式,动态导入,构建时,会分离为独立的 chunk,该方式导入使用()=>import("/xx"),跟路由懒加载是一样的导入方式。
  • 【import.meta.globEager("/xx")】以及【import.meta.glob("/xx",{eager:true})】为静态加载

 打印imageList如图


● 参考资料 ●

实现图片懒加载的5种方式-CSDN博客 | JS实现图片懒加载的三种常用方法总结-CSDN博客

图片懒加载🔥三种实现方案 _ 掘金 | JS代码如何实现图片懒加载 – PingCode

如何使用HTML、CSS和jQuery实现图片懒加载的进阶技巧-js教程-PHP中文网

JS | JS中的getBoundingClientRect()方法详解,秒懂!- 烤地瓜的CSDN博客

JS | 图片懒加载之IntersectionObserver API 手把手教学 - 烤地瓜的CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/899886.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Aatrox-Bert-VITS2部署指南

一、模型介绍 【AI 剑魔 ①】在线语音合成&#xff08;Bert-Vits2&#xff09;&#xff0c;将输入文字转化成暗裔剑魔亚托克斯音色的音频输出。 作者&#xff1a;Xz 乔希 https://space.bilibili.com/5859321 声音归属&#xff1a;Riot Games《英雄联盟》暗裔剑魔亚托克斯 …

Redis——缓存

目录 前言 一、缓存基本概念 1.概念 2.二八定律 二、使用 Redis 作为缓存 三、缓存的更新策略 1.定期生成 2.实时生成 四、Redis 内存淘汰机制 1.通用淘汰策略 &#xff08;1&#xff09;FIFO &#xff08;2&#xff09;LRU &#xff08;3&#xff09;LFU &#…

机器学习在智能水泥基复合材料中的应用与实践

在人工智能与复合材料技术融合的背景下&#xff0c;复合材料的研究和应用正迅速发展&#xff0c;创新解决方案层出不穷。从复合材料性能的精确预测到复杂材料结构的智能设计&#xff0c;从数据驱动的材料结构优化到多尺度分析&#xff0c;人工智能技术正以其强大的数据处理能力…

Linux 权限的理解

内容摘要 本文内容包括shell的运行原理&#xff0c;包括外壳程序的原理、理解、和意义&#xff0c;以及从两个方面对于权限的理解&#xff08;人和事物的属性&#xff09;、修改文件的权限&#xff0c;包括修改文件的拥有者、修改文件拥有者所在的组的用户以及修改文件的三类用…

【linux】线程(二)

10. pthread_t 类型 注意&#xff1a; 每一个线程的库级别的tcb的起始地址&#xff0c;就是线程的 tid每一个线程都有自己独立的栈结构线程和线程之间&#xff0c;也是可以被其他线程看到并访问的&#xff08;比如全局函数&#xff09; 代码 如果想要进程拥有私人的全局变量(即…

关于武汉芯景科技有限公司的限流开关芯片XJ6288开发指南(兼容SY6288)

一、芯片引脚介绍 1.芯片引脚 二、系统结构图 三、功能描述 1.EN引脚控制IN和OUT引脚的通断 2.OCB引脚指示状态 3.过流自动断开

C++ [项目] 恶魔轮盘赌

现在才发现C游戏的支持率这么高&#xff0c;那就发几篇吧 零、前情提要 此篇是我与 同学的共创,他负责写人,我负责写机,简称人机, 不过有一点小插曲…… 一、基本介绍 支持Dev-C5.11版本(务必调为英文输入法),基本操作看游戏里的介绍,怎么做的……懒得说,能看懂就看注释,没有…

Vue3结合vue-plugin-hiprint实现自定义打印模板设计与布局

简介 在现代Web应用开发中&#xff0c;打印功能是不可或缺的一部分&#xff0c;尤其是在需要输出标准化文档的场景下。本文将详细介绍如何在Vue3项目中利用vue-plugin-hiprint插件实现一个可定制的打印模板设计器&#xff0c;并通过具体示例来展示其配置与使用方法。 技术栈 …

Python如何导入模块及常见的导入方法

&#x1f600;前言 在 Python 编程中&#xff0c;模块&#xff08;Module&#xff09;是非常重要的工具。它们可以帮助我们将代码进行逻辑分割和复用&#xff0c;从而提高代码的可读性和可维护性。本文将详细介绍如何导入模块、使用常见的导入方法&#xff0c;并简要介绍一些常…

[分享] SQL在线编辑工具(好用)

在线SQL编写工具&#xff08;无广告&#xff09; - 在线SQL编写工具 - Web SQL - SQL在线编辑格式化 - WGCLOUD

若依微服务15 - RuoYi-Vue3 实现前端独立运行

正文开始&#xff1a; RuoYi-Vue3 使用 Vue3 Element Plus Vite 技术栈。 GitHub 开源地址&#xff1a;https://github.com/yangzongzhuan/RuoYi-Vue3 本文介绍使用若依提供的在线后端接口&#xff0c;仅启动前端项目并进行界面开发&#xff0c;而无需启动后端服务。 一、克隆…

Vue笔记-浏览器窗口改变时,重新计算表格高度并设置

当窗口大小改变时&#xff0c;你监听 window 对象的 resize 事件&#xff0c;然后在事件处理程序中重新计算表格的高度。在 Vue 中&#xff0c;可以在组件中通过 created 生命周期钩子来添加事件监听器&#xff0c;然后在组件销毁时移除事件监听器。 如下vue代码&#xff1a; …

33 类与对象 · 下

目录 一、构造函数的深入 &#xff08;一&#xff09;构造函数的其他特点 &#xff08;二&#xff09;使用例 1、Date类与Time类显示写 2、Date类与Time类写一部分 &#xff08;三&#xff09;总结 &#xff08;四&#xff09;初始化顺序小题目 二、类型转化 &#xff…

Linux Redis查询key与移除日常操作

维护老项目Express node 编写的后端程序、有这么一个方法、没有设置redis过期时间&#xff08;建议设置过期时间&#xff0c;毕竟登录生产服务器并不是每个人都有权限登录的&#xff01;&#xff01;&#xff01;&#xff09;。如果变动只能通过登录生产服务器、手动修改… 于…

@Autowired和@Resource的用法与区别

前言&#xff1a; Autowired 和 Resource 来自不同的“父类”&#xff0c;其中 Autowired 是 Spring 定义的注解&#xff0c;而 Resource 是 Java 定义的注解&#xff0c;它来自于 JSR-250&#xff08;Java 250 规范提案&#xff09;。当它们的实现类只有一个时&#xff0c;那…

github pages + hugo 搭建静态博客网站

体验地址 1. 起因&#xff0c; 目的: 其实6年前&#xff0c;我就写过这个。 项目代码 博客地址 最近想改写一下。 github 推荐的主题是 Jekyll&#xff0c; 我当时用的就是这个&#xff0c;感觉很麻烦。尤其是文章命名。 新的主题 hugo 用起来还行。 2.过程: 过程记录&am…

代码随想录算法训练营第六天|454四数相加II、 383赎金信、15三数之和、18四数之和

day06 1. 454四数相加II 首先定义 一个unordered_map&#xff0c;key放a和b两数之和&#xff0c;value 放a和b两数之和出现的次数。遍历大A和大B数组&#xff0c;统计两个数组元素之和&#xff0c;和出现的次数&#xff0c;放到map中。定义int变量count&#xff0c;用来统计 …

新电脑Win11家庭中文版跳过联网激活方法(教程)

预装Win11家庭中文版的新电脑&#xff0c;如何跳过联网激活&#xff1b;由于微软限制必须要联网激活&#xff0c;需要使用已有的微软账户登入或者注册新的微软账户后才可以继续开机使用&#xff0c;Win11联网后系统会自动激活。下面介绍一下初次开机初始化电脑时如何跳过联网激…

虚拟滚动列表如何实现?

highlight: a11y-dark 虚拟滚动列表&#xff0c;虚拟滚动的关键在于只渲染当前视口内可见的数据项&#xff0c;而不是一次性渲染所有数据项。这可以显著提高性能&#xff0c;尤其是在处理大量数据时。 以下是一个完整的虚拟滚动列表的示例代码&#xff1a; <!DOCTYPE htm…

RFC2616 超文本传输协议 HTTP/1.1

一、URL-俗称“网址” HTTP 使用 URL(Uniform Resource Locator&#xff0c;统一资源定位符)来定位资源&#xff0c;它是 URI(Uniform Resource Identifier&#xff0c;统一资源标识符)的子集&#xff0c;URL 在 URI 的基础上增加了定位能力 URI 除了包含 URL&#xff0c;还包…