react+IntersectionObserver实现页面丝滑帧动画

news/2024/7/15 19:12:21 标签: react.js, 前端, 前端框架

实现效果:

加入帧动画前:

1695911105187.gif

普通的静态页面

加入帧动画后:

1695946149547.gif

可以看到,加入帧动画后,页面效果还是比较丝滑的。

技术实现

加入animation动画类

先用 **scss **定义三种动画类:

.withAnimation {
  .fade1 {
    animation: fadeInDown1 1s;
  }

  .fade2 {
    animation: fadeInDown2 1.25s;
  }

  .fade3 {
    animation: fadeInDown2 1.5s;
  }
}

@keyframes fadeInDown1 {
  0% {
    transform: translate3d(0, 40px, 0);
    opacity: 0;
  }

  22% {
    transform: translate3d(0, 40px, 0);
    opacity: 0;
  }

  100% {
    -webkit-transform: none;
    transform: none;
    opacity: 1;
  }
}
@keyframes fadeInDown2 {
  0% {
    transform: translate3d(0, 40px, 0);
    opacity: 0;
  }

  44% {
    transform: translate3d(0, 40px, 0);
    opacity: 0;
  }

  100% {
    -webkit-transform: none;
    transform: none;
    opacity: 1;
  }
}
@keyframes fadeInDown3 {
  0% {
    transform: translate3d(0, 40px, 0);
    opacity: 0;
  }

  66% {
    transform: translate3d(0, 40px, 0);
    opacity: 0;
  }

  100% {
    -webkit-transform: none;
    transform: none;
    opacity: 1;
}

注意:.fade类前面需要有.withAnimation,作为接下来实现帧动画,添加.withAnimation .fade类帧动画的工具。

加入IntersectionObserver监听

IntersectionObserver

先简单过一下IntersectionObserver的使用:

var observer = new IntersectionObserver(callback,options);

IntersectionObserver支持两个参数:

  1. callback是当被监听元素的可见性变化时,触发的回调函数
  2. options是一个配置参数,可选,有默认的属性值
//初始化一个实例
var observer = new IntersectionObserver(changes => {
    for (const change of changes) {
        console.log(change.time);
        // Timestamp when the change occurred
        // 当可视状态变化时,状态发送改变的时间戳
        // 对比时间为,实例化的时间,
        // 比如,值为1000时,表示在IntersectionObserver实例化的1秒钟之后,触发该元素的可视性变化

        console.log(change.rootBounds);
        // Unclipped area of root
        // 根元素的矩形区域信息,即为getBoundingClientRect方法返回的值

        console.log(change.boundingClientRect);
        // target.boundingClientRect()
        // 目标元素的矩形区域的信息

        console.log(change.intersectionRect);
        // boundingClientRect, clipped by its containing block ancestors,
        // and intersected with rootBounds
        // 目标元素与视口(或根元素)的交叉区域的信息

        console.log(change.intersectionRatio);
        // Ratio of intersectionRect area to boundingClientRect area
        // 目标元素的可见比例,即intersectionRect占boundingClientRect的比例,
        // 完全可见时为1,完全不可见时小于等于0

        console.log(change.target);
        // the Element target
        // 被观察的目标元素,是一个 DOM 节点对象
        // 当前可视区域正在变化的元素

    }
}, {});

// Watch for intersection events on a specific target Element.
// 对元素target添加监听,当target元素变化时,就会触发上述的回调
observer.observe(target);

// Stop watching for intersection events on a specific target Element.
// 移除一个监听,移除之后,target元素的可视区域变化,将不再触发前面的回调函数
observer.unobserve(target);

// Stop observing threshold events on all target elements.
// 停止所有的监听
observer.disconnect();

实现

页面组件中加入IntersectionObserver

  useEffect(() => {
    const options = {
      rootMargin: '0px',
      threshold: 0.2 // 指定交叉比例为 20% 时触发回调函数
    };
    const observer = new IntersectionObserver(([entry]) => {
      // ...
    }, options);
  }, []);

监听dom元素的进入,添加对应class

fadeClass类的添加

  • 确保父元素加入了fadeClass类,便于后续对加动画的dom元素进行锁定
  • 子元素添加对应的fade动画类
      <div className={cName([styles.rootFront,'fadeClass'])}>
        <p className={cName([styles.text1, styles.fade1])}>123</p>
        <p className={cName([styles.text2, styles.fade2])}>123</p>
        <p className={cName([styles.text3, styles.fade3])}>123</p>
      </div>

cName()是classnames中给dom元素添加多个class的方法,也可以用其他方法实现。

  • 引入:“import cName from ‘classnames’”
  • 依赖:npm i classnames

IntersectionObserver监听fadeClass元素的进入

  useEffect(() => {
    const elements = document.querySelectorAll('.fadeClass');
    const options = {
      rootMargin: '0px',
      threshold: 0.2 // 指定交叉比例为 20% 时触发回调函数
    };
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        entry.target.classList.add(styles.withAnimation);
      }
      // 进入时添加withAnimation类
    }, options);
    elements.forEach((dom) => {
      observer.observe(dom);//每个元素,添加聆听事件
    });
  }, []);

不出意外,到这来就基本实现完成了,其他动画效果实现类似。


http://www.niftyadmin.cn/n/5057263.html

相关文章

前缀、中缀、后缀表达式相互转换工具

目录 1. 界面一览 2. 使用说明 3. 实例演示 3.1 输入中缀 3.2 输入前缀 3.3 输入后缀 3.4 选择错误的类型 4. 代码 5. 资源地址 关于什么是前缀、中缀、后缀表达式&#xff0c;相信你不知道这个东西&#xff0c;那你也不会点进来这篇博客&#xff0c;当然&#xff0c;…

buildroot移植Qt5无法显示字体问题

报错&#xff1a;QFontDatabase: Cannot find font directory /usr/lib/fonts. Note that Qt no longer ships fonts. Deploy some (from DejaVu Fonts for example) or switch to fontconfig. 原因&#xff1a;很明显是Qt没有找到字库文件&#xff1b; 解决方法&#xff1a; 1…

Spring后处理器-BeanPostProcessor

Spring后处理器-BeanPostProcessor Bean被实例化后&#xff0c;到最终缓存到名为singletonObjects单例池之前&#xff0c;中间会经过bean的初始化过程&#xff08;&#xff08;该后处理器的执行时机&#xff09;&#xff09;&#xff0c;例如&#xff1a;属性的填充、初始化方…

【数据结构】抽象数据类型

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f38f;数据类型 &#x1f38f;抽象数据类型 结语 &#x1f38f;数据类型 数据类型:是指一组性质相同的值的集合及定义在此集合上的一些操作的总称. 数据类型(d…

代码随想录—力扣算法题:07.链表相交. Java版(示例代码与导图详解)

版本说明 当前版本号[20230923]。 版本修改说明20230923初版 07. 链表相交 同&#xff1a;160.链表相交 力扣题目链接 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示…

【青书学堂】2023年第二学期 PhotoShop基础与应用(高起专) 作业

【青书学堂】2023年第二学期 作业-PhotoShop基础与应用(高起专) 为了方便日后复习&#xff0c;青书学堂成人大专试题整理&#xff0c; 若有未整理的课程&#xff0c;请私信我补充&#xff0c;欢迎爱学习的同学们收藏点赞关注&#xff01;文章内容仅限学习使用&#xff01;&…

JavaScript强制转换数字类型并设置默认值为0

你可以创建一个函数&#xff0c;使用JavaScript的parseFloat或parseInt函数尝试转换输入到数字。如果转换失败&#xff0c;那么返回默认值0。这是一个示例函数&#xff1a; function toNumberOrDefault(input, defaultValue 0) {const number parseFloat(input);return isNa…

spark相关网站

maven-assembly-plugin&#xff08;官方标准打包插件&#xff09; https://blog.csdn.net/qq_43529621/article/details/106550551 Git 重置本地分支为远程分支 https://www.cnblogs.com/CF1314/p/14276355.html git cherry-pick用法详解 https://www.jianshu.com/p/e05bf997…