diff --git a/2023/11/20/first/index.html b/2023/11/20/first/index.html index 6a5cf29..294ab64 100644 --- a/2023/11/20/first/index.html +++ b/2023/11/20/first/index.html @@ -5,12 +5,12 @@ - + -

first

文章作者: 幺幺一一
文章链接: https://yaoyaoyiyi216.github.io/2023/11/20/first/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 YUN's Blog
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖

first

文章作者: 幺幺一一
文章链接: https://yaoyaoyiyi216.github.io/2023/11/20/first/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 YUN's Blog
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖

this(普通函数)————初版

this(普通函数)

this是什么

this———用于访问当前方法所属的对象

+})()

this(普通函数)————初版

文章作者: 幺幺一一
文章链接: https://yaoyaoyiyi216.github.io/2023/12/03/this%E6%99%AE%E9%80%9A%E5%87%BD%E6%95%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 YUN's Blog
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖

React实现图片懒加载

前言

图片懒加载是一种优化网页性能的技术,它允许在用户滚动到图片位置之前延迟加载图片。通过懒加载,可以在用户需要查看图片时才加载图片,避免了不必要的图片加载,从而提高了网页的加载速度和用户体验。

+})()

React实现图片懒加载

前言

图片懒加载是一种优化网页性能的技术,它允许在用户滚动到图片位置之前延迟加载图片。通过懒加载,可以在用户需要查看图片时才加载图片,避免了不必要的图片加载,从而提高了网页的加载速度和用户体验。

方法一

实现思路

在说明思路之前,先了解几个常见的视图属性。

  1. clientHeight:元素的像素高度,包含元素的高度+内边距,不包含水平滚动条,边框和外边距。

    @@ -197,16 +197,16 @@
    第二步

    遍历图片url集合,渲染loading图片

    <div className={styles['box-one']} ref={scrollRef}>
    {imgUrls(100).map((item) => {
    return <img data-src={item} key={item} src={loadingUrl} alt="" />;
    })}
    </div>
    -

    image.png

    +

    image.png

    第三步

    监听容器的滚动事件,当容器滚动时计算容器的高度加上滚动条的高度大于当前图片的offsetTop时加载当前的图片。

    import loadingUrl from '@/assets/imgs/loading.jpg';
    import { useEffect, useRef } from 'react';
    import styles from '../index.less';

    // 图片url
    const imgUrls = (num = 10) => {
    const urls = [];
    for (let i = 0; i < num; i++) {
    const url = `https://robohash.org/${i}.png`;
    urls.push(url);
    }
    return urls;
    };

    const LazyLoading = () => {
    const scrollRef = useRef({} as any);

    // 滚动事件
    const changeScroll = () => {
    const clientHeight = scrollRef?.current.clientHeight; //可视区域高度
    const scrollTop = scrollRef?.current.scrollTop; //滚动条滚动高度
    const childNodes = scrollRef?.current.childNodes; // 获取所有图片集合

    for (let j = 0; j < childNodes.length; j++) {
    const element = childNodes[j];
    if (scrollTop + clientHeight > element.offsetTop) {
    element.src = element.getAttribute('data-src'); // 替换当前的src
    }
    }
    };

    useEffect(() => {
    changeScroll(); // 第一次渲染的时候替换loading图片
    }, []);

    return (
    <div className={styles['box-one']} ref={scrollRef} onScroll={changeScroll}>
    {imgUrls(100).map((item) => {
    return <img data-src={item} key={item} src={loadingUrl} alt="" />;
    })}
    </div>
    );
    };

    export default LazyLoading;
    -

    image.png

    +

    image.png

    方法二

    方案二的实现思路利用浏览器提供的 IntersectionObserver API实现。IntersectionObserver API提供了一种方便的方式来监视目标元素和其祖先元素或视窗之间的交叉状态变化。当目标元素进入或离开视口时,可以触发回调函数,进行相应的操作。它的原理是通过注册一个回调函数来观察特定元素的交叉状态变化,并在满足条件时执行相应的操作。

    使用 IntersectionObserver API非常简单,可以通过创建一个 IntersectionObserver 实例,并传入回调函数和选项对象来实现。回调函数会在目标元素的交叉状态发生变化时被调用,并接收一个参数,包含有关交叉状态的信息。

    import loadingUrl from '@/assets/imgs/loading.jpg';
    import styles from '../index.less';
    import React, { useRef, useEffect, useState } from 'react';
    // 图片url
    const imgUrls = (num = 10) => {
    const urls = [];
    for (let i = 0; i < num; i++) {
    const url = `https://robohash.org/${i}.png`;
    urls.push(url);
    }
    return urls;
    };

    const LazyLoadImage = ({ src, alt }) => {
    const [imageSrc, setImageSrc] = useState(loadingUrl);
    const imgRef = useRef(null as any);

    useEffect(() => {
    let observer: IntersectionObserver;
    if (imgRef.current) {
    // 创建IntersectionObserver实例
    observer = new IntersectionObserver(
    ([entry]) => {
    // 当图片进入可视区域时,设置图片地址进行加载
    if (entry.isIntersecting) {
    setImageSrc(src);
    observer.unobserve(imgRef.current);
    }
    },
    {
    rootMargin: '0px 0px 200px 0px', // 可视区域的上边距设置为200px
    //rootMargin 是 IntersectionObserver 的配置项之一,用于指定根元素边界框的外边距,以便扩大或缩小视口的大小
    },
    );
    observer.observe(imgRef.current); //开始观察目标元素
    }
    return () => {
    if (observer && observer.unobserve) {
    observer.unobserve(imgRef.current);
    }
    };
    }, [src]);

    return <img ref={imgRef} src={imageSrc} alt={alt} />;
    };

    const LazyLoading = () => {
    return (
    <div className={styles['box-two']}>
    {imgUrls(100).map((item) => {
    return <LazyLoadImage src={item} alt="lazy load image" />;
    })}
    </div>
    );
    };

    export default LazyLoading;
    -

    2024-01-08 16.17.31.gif

    +

    2024-01-08 16.17.31.gif

    注意

    在初始化的时候,需要给imageSrc设置一个初始化的loading地址,如果没有的话,初始化的时候会加载多张图片。

    方法三

    利用react的懒加载库react-lazyload,这里介绍几个它的常见属性:

      @@ -219,7 +219,7 @@

      因为这里实现的图片懒加载是局部懒加载,所以需要指定 scrollContainerscrollContainer 的值DOM对象。在实现的过程中,同时需要设置overflow为true,以及height的值。

      import react, { useRef, useEffect } from 'react';
      import LazyLoad from 'react-lazyload';
      import styles from '../index.less';

      // 图片url
      const imgUrls = (num = 10) => {
      const urls = [];
      for (let i = 0; i < num; i++) {
      const url = `https://robohash.org/${i}.png`;
      urls.push(url);
      }
      return urls;
      };

      const LazyLoading = () => {
      const scrollRef = useRef({} as any);

      return (
      <div className={styles['box-three']} ref={scrollRef}>
      {imgUrls(100).map((item) => {
      return (
      <LazyLoad
      height={200}
      overflow={true}
      offset={0}
      key={item}
      scroll={true}
      scrollContainer={scrollRef.current} // DOM
      >
      <img src={item} alt="" />
      </LazyLoad>
      );
      })}
      </div>
      );
      };

      export default LazyLoading;
      -

文章作者: 幺幺一一
文章链接: https://yaoyaoyiyi216.github.io/2024/03/02/React%E5%AE%9E%E7%8E%B0%E5%9B%BE%E7%89%87%E6%87%92%E5%8A%A0%E8%BD%BD/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 YUN's Blog
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖

canvas进阶

1.动画

在Canvas中,动画其实也就是一些基础的几何变换,因此想做动画第一步咱们需要先了解有哪些几何变换

+})()

canvas进阶

1.动画

在Canvas中,动画其实也就是一些基础的几何变换,因此想做动画第一步咱们需要先了解有哪些几何变换

几何变换

几何变换的类型其实和CSS动画中的类型差不多,也就是:移动、旋转、缩放

移动

语法:translate(x, y),其中 x 是左右偏移量,y 是上下偏移量。

const canvas = document.getElementById('canvas'); // 获取Canvas
const ctx = canvas.getContext('2d'); // 获取绘制上下文
ctx.fillStyle="#ff0000"
// 向x轴和y轴平移200像素(移的是画布的原点)
ctx.translate(200, 200);
// 在(0,0)坐标点绘制一个宽:200,高:100的矩形
ctx.fillRect(0, 0, 200, 100)

@@ -194,7 +194,7 @@

const canvas = document.getElementById('canvas'); // 获取Canvas
const ctx = canvas.getContext('2d'); // 获取绘制上下文

ctx.fillStyle = "gray";
ctx.fillRect(10, 10, 200, 100);
// 保存状态
ctx.save();
ctx.fillStyle = "orange";
ctx.fillRect(10, 150, 200, 100);
// 恢复上次保存的状态
ctx.restore();
ctx.fillRect(10, 300, 200, 200);
-

image.png

+

image.png

如上图我们可以看出,最开始我们设置了填充颜色为灰色,并绘制了一个矩形,然后我们执行了状态保存,上面我们已经列举了哪些状态可以保存,所以这里我们知道此次的状态保存的是:fillStyle状态,保存完以后我们又设置了填充颜色为橘色,并且又绘制了一个矩形,最后我们执行了一次状态恢复,接着直接绘制一个正方形。我们知道如果没有状态保存和恢复的方法,正常情况下正方形应该是使用橘色来填充,但正因为我们保存了fillStyle状态的灰色,又在绘制正方形之前恢复了fillStyle状态为灰色,因此绘制出来的正方形为灰色。

2.动画

Canvas呈现的东西都是绘制完了以后才能看到,因此想通过Canvas自己提供的Api来实现动画是做不到的。

那么想在 Canvas 中实现动画就得借助别的东西,那么借助啥呢?

@@ -209,7 +209,7 @@

2.

setInterval setTimeout

这里先使用 setInterval()方法实现一个元素的位移效果。

const canvas = document.getElementById('canvas'); // 获取Canvas
const ctx = canvas.getContext('2d'); // 获取绘制上下文
ctx.fillStyle = "#ccc";
let num = 0
setInterval(()=>{
num += 1
if(num <= 400) {
ctx.fillRect(num, 0, 100, 100);
}
})
-

1.gif

+

1.gif

如图我们可以看出,元素确实动了,但是似乎不是我们想要的那个样子,我们想实现的是元素的位移,但看样子实现的是元素的变宽。

那么我们看一下问题出在哪里?

经过我们的一番思考,我们发现,Canvas 绘制时把元素一帧一帧的绘制到画布上,比如上面的例子我们把一个元素从(0,0)移动到(400,0),也就是横向移动400像素。既然是一帧一帧绘制的,那么我们看到的就是连续的从(0,0)绘制到(400,0)的效果,也就是我们看到的是所有的帧组合在一起的效果,而不是从(0,0)移动到(400,0)的效果。

@@ -224,7 +224,7 @@
const canvas = document.getElementById('canvas'); // 获取Canvas
const ctx = canvas.getContext('2d'); // 获取绘制上下文
ctx.fillStyle = "#ccc";
const width = canvas.width
const height = canvas.height
let num = 0
setInterval(()=>{
num += 1
if(num <= 400) {
ctx.clearRect(0, 0, width, height) //清除整张画布
ctx.fillRect(num, 0, 100, 100);
}
})
-

2.gif

+

2.gif

requestAnimationFrame

requestAnimationFrame()方法的整体性能要比setInterval()方法好很多,打个比方,当我们用setInterval()方法来做动画,我们需要设置一下多长时间执行一次setInterval()方法里面的代码块,而这个时间我们只要设定了,那么就会强行这个时间执行,而如果我们的浏览器显示频率和setInterval()方法执行的绘制请求不一致,就会导致一些帧率消失,从而造成卡顿的效果。因此使用requestAnimationFrame()方法做动画会更加平缓且有效率。

同时在requestAnimationFrame()方法的使用中我们需要注意,一般每秒钟回调函数执行次数为60次,但也可能会被降低,因为通常情况下requestAnimationFrame()方法会遵循W3C的建议,在浏览器中的回调函数执行次数需要和浏览器屏幕刷新次数相匹配。还有就是为了提高性能和电池使用寿命,requestAnimationFrame() 方法运行在后台标签页或者隐藏在 <iframe>标签里时,requestAnimationFrame()方法会暂停调用以提升性能和电池使用寿命。

requestAnimationFrame()方法不能自循环,那怎么让他实时触发渲染呢?

@@ -233,8 +233,8 @@

    const canvas = document.getElementById('canvas'); 
// 获取绘制上下文
const ctx = canvas.getContext('2d');
// globalCompositeOperation 属性设置或返回如何将一个源(新的)图像绘制到目标(已有的)的图像上。
// 这里主要是为了让飞机压在运行轨迹上
ctx.globalCompositeOperation = 'destination-over';
//globalCompositeOperation 设置或返回如何将一个源(新的)图像绘制到目标(已有的)的图像上
//destination-over 把源图像绘制到目标图像的上面(也就是源图像盖到目标图像的上面)
const width = canvas.width
const height = canvas.height
let num = 0
ctx.strokeStyle = "#ccc"
const img = new Image()
img.src="../images/plane.png"
img.onload = ()=>{
requestAnimationFrame(planeRun);
}
function planeRun(){
// 清空画布
ctx.clearRect(0, 0, width, height)

// 保存画布状态
ctx.save();

// 把圆心移到画布中间
ctx.translate(250, 250);

// 绘制飞机和飞机动画
num += 0.01
ctx.rotate(-num);
ctx.translate(0, 200);
ctx.drawImage(img, -20, -25, 40, 40);

// 恢复状态
ctx.restore();

// 飞机运行的轨迹
ctx.beginPath();
ctx.arc(250, 250, 200, 0, Math.PI * 2, false);
ctx.stroke();

// 执行完以后继续调用
requestAnimationFrame(planeRun);
}
-

4.gif

-

文章作者: 幺幺一一
文章链接: https://yaoyaoyiyi216.github.io/2024/04/12/canvas%E8%BF%9B%E9%98%B6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 YUN's Blog
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
文章总览 - 2
2023
first
first
Hello World
Hello World
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 2
2023
first
first
Hello World
Hello World
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 2
2023
闭包
闭包
this(普通函数)————初版
this(普通函数)————初版
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 2
2023
闭包
闭包
this(普通函数)————初版
this(普通函数)————初版
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 4
2023
闭包
闭包
this(普通函数)————初版
this(普通函数)————初版
first
first
Hello World
Hello World
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 4
2023
闭包
闭包
this(普通函数)————初版
this(普通函数)————初版
first
first
Hello World
Hello World
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 3
2024
js继承
js继承
节流与防抖
节流与防抖
React实现图片懒加载
React实现图片懒加载
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 3
2024
js继承
js继承
节流与防抖
节流与防抖
React实现图片懒加载
React实现图片懒加载
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 2
2024
canvas进阶
canvas进阶
canvas基础
canvas基础
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 2
2024
canvas进阶
canvas进阶
canvas基础
canvas基础
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 5
2024
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
React实现图片懒加载
React实现图片懒加载
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 5
2024
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
React实现图片懒加载
React实现图片懒加载
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 9
2024
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
React实现图片懒加载
React实现图片懒加载
2023
闭包
闭包
this(普通函数)————初版
this(普通函数)————初版
first
first
Hello World
Hello World
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章总览 - 9
2024
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
React实现图片懒加载
React实现图片懒加载
2023
闭包
闭包
this(普通函数)————初版
this(普通函数)————初版
first
first
Hello World
Hello World
avatar
幺幺一一
Welcome to my blog
Follow Me
公告
This is my Blog
最新文章
canvas进阶
canvas进阶
canvas基础
canvas基础
js继承
js继承
节流与防抖
节流与防抖
网站资讯
文章数目 :
9
已运行时间 :
本站总字数 :
11.4k
本站访客数 :
本站总访问量 :
最后更新时间 :
canvas进阶