实现元素进入界面的平滑效果

先看效果:
在这里插入图片描述
实现思路:获取页面中需要加载动画的节点,用元素的animate()方法创建一个动画对象,并传入两个关键帧,接着使用IntersectionObserverAPI创建观察对象,用于观察元素进入页面。当元素进入界面时,执行动画,最后取消元素的观察即可。

具体实现:

第一步:

<div class="container">
   <div class="module">模块1</div>
   <div class="module">模块2</div>
   <div class="module">模块3</div>
   <div class="module">模块4</div>
   <div class="module">模块5</div>
   <div class="module">模块6</div>
   <div class="module">模块7</div>
   <div class="module">模块8</div>
   <div class="module">模块9</div>
   <div class="module">模块10</div>
 </div>


<script>
const DISTANCE = 100;
onload = function() {
// 页面加载完毕,获取到所有需要加载动画的节点
   document.querySelectorAll('.module').forEach(module => {
   // 循环调用每个模块的animate方法。用法:animate(keyframes, options)
   // keyframes 关键帧对象数组,或一个关键帧对象(其属性为可迭代值的数组)
   // options 代表动画持续时间的整数(以毫秒为单位),或者一个包含一个或多个时间属性的对象
     let animation = module.animate([
       {
         transform: `translateY(${DISTANCE}px)`,
         opacity: 0
       },
       {
         transform: 'translateY(0)',
         opacity: 1
       }
     ], {
       duration: 1000,
       easing: 'ease-in-out'
     })
     animation.pause() // 创建好animation对象后,首先暂停动画的执行,待会儿用监听器监听元素进入界面后开启动画
   })
 }
</script>

第二步:

// 创建一个WeakMap对象,用于存储节点及动画对象,WeakMap是为了防止内存泄漏,当元素消失时,元素会自动销毁在对象中的存储
let map = new WeakMap()
// 创建一个监视器
let observer = new IntersectionObserver((entries, observer) => {
// entries是获取到的所有监听对象
  entries.forEach(entry => {
  // 判断当元素进入到界面
    if (entry.isIntersecting) {
    // 获取每个元素上的动画对象
      const animation = map.get(entry.target)
      // 当动画存在时,执行动画,并取消元素进入界面的观察
      if(animation) {
        animation.play()
        observer.unobserve(entry.target)
      }
    }
  });
});

onload = function() {
   document.querySelectorAll('.module').forEach(module => {
     let animation = module.animate([
       {
         transform: `translateY(${DISTANCE}px)`,
         opacity: 0
       },
       {
         transform: 'translateY(0)',
         opacity: 1
       }
     ], {
       duration: 1000,
       easing: 'ease-in-out'
     })
     animation.pause()
     // 用上方创建的监听器 观察每一个模块节点
     observer.observe(module)
     // 将每个节点及动画存储对象中
     map.set(module, animation)
   })
 }

最后一步:

解决关键性问题,当滚动条滚动到界面中间时,刷新界面后,不论是往上滚还是往下滚,再次进入界面的元素都会执行动画。当然我们所需要的是往下滚动时下面的元素进入界面需要加载动画,而上方的元素进入界面不需要动画。那么我们就可以这样写:

let map = new WeakMap()

    let observer = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const animation = map.get(entry.target)
          if(animation) {
            animation.play()
            observer.unobserve(entry.target)
          }
        }
      });
    });

    const DISTANCE = 100
    function isViewport(element) {
      const rect = element.getBoundingClientRect();
      return rect.top - DISTANCE > window.innerHeight
    }

    onload = function() {
      document.querySelectorAll('.module').forEach(module => {
        // 判断节点是否在视口内
        if(!isViewport(module)) return;
        let animation = module.animate([
          {
            transform: `translateY(${DISTANCE}px)`,
            opacity: 0
          },
          {
            transform: 'translateY(0)',
            opacity: 1
          }
        ], {
          duration: 1000,
          easing: 'ease-in-out'
        })
        animation.pause()
        observer.observe(module)
        map.set(module, animation)
      })
    }

结尾:上面的示例是在html文件中完成的,当然你也可以在Vue中实现,在Vue中,你可以自定义指令,通过获取到的el对象绑定动画、观察,甚至是通过绑定的指令传入动画的参数,来动态执行动画。

为什么需要使用animate方法,而不是在节点的style中添加动画?

因为我们是要封装公用指令、组件,如果我们继续使用style,向其添加动画,有可能和节点原有的动画冲突,为了不对元素本身的动画照成影响,我们可以使用AnimationAPI,它的好处就在于 不会改变元素的DOM树,不会改变元素本身的属性,这样就可以避免两者的冲突。

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

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

相关文章

【数据分享】1929-2023年全球站点的逐年平均气温数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01;本次我们为大家带来的就是具体到气象监…

CSS--Emmet 语法

Emmet语法的前身是Zen coding,它使用缩写,来提高html/css的编写速度, Vscode内部已经集成该语法. 目录 1. 快速生成HTML结构语法 1.1 快速生成HTML结构语法 2. 快速生成CSS样式语法 2.1 快速生成CSS样式语法 1. 快速生成HTML结构语法 1.1 快速生成HTML结构语法 1. 生成标…

2.【Vue3】Vue 基本使用——局部使用Vue

文章目录 1. 快速入门2. 常用指令2.1 v-for2.2 v-bind2.3 v-if 与 v-show2.4 v-on2.5 v-model 3. 生命周期4. Ajax 函数库 Axios4.1 Axios 基本使用4.2 Axios 请求方式别名 1. 快速入门 现在需要将 “hello vue3” 这样一个字符串渲染到页面上进行展示。 这个需求并不陌生&…

JVM系列——对象管理

JVM对象分布 对象头 第一类是用于存储对象自身的运行时数据&#xff0c;如哈希码&#xff08;HashCode&#xff09;、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等 另外一部分是类型指针&#xff0c;即对象指向它的类型元数据的指针&#xff0c;Java 虚…

【ArcGIS微课1000例】0096:dem三维块状表达(层次地形模型)

文章目录 一、DEM表达方式二、层次模型表达三、注意事项一、DEM表达方式 DEM数字高程模型的表达方式通常有以下4种: 1. 规则格网 2. 不规则三角网 3. 等高线 4. 层次地形模型 作为栅格地理数据,DEM 数据具有2.5维的特征,能够以三维表面的形式进行三维空间表达。但受其数…

Web 开发 6:Redis 缓存(Flask项目使用Redis并同时部署到Docker详细流程 附项目源码)

大家好&#xff01;欢迎来到第六篇 Web 开发教程&#xff0c;今天我们将探讨一个非常重要的话题&#xff1a;Redis 缓存。作为一个互联网开发者&#xff0c;你一定知道在处理大量请求时&#xff0c;性能优化是至关重要的。而 Redis 缓存正是帮助我们提升系统性能的利器。Redis …

爬虫基础-计算机网络协议

一个数据的传输 这些设备的数据转发是通过协议来完成的&#xff0c;整个互联网可以说是完全由网络协议来维持的 不同的协议分工不同&#xff0c;比如ip协议确保了ip寻址&#xff0c;tcp协议确保了数据完整性 IP地址和URL ip地址 整个网络传输可以比作快递&#xff0c;数据就…

2023年度总结——忙忙碌碌,终有归章

思来想去&#xff0c;还是决定写一篇年终总结&#xff0c;一来算是对23年的一年的回顾&#xff0c;二来是对24年的展望。记得22年也写过一篇年度总结&#xff0c;题目是《2022年度总结——一切都在慢慢变好》。今年&#xff0c;我想起的题目是《2023年度总结——忙忙碌碌&#…

在Temu跨境电商平台上,如何快速出单?

随着越来越多的商家选择入驻Temu跨境电商平台&#xff0c;一旦入驻申请通过&#xff0c;商家就可以开始上架商品并等待订单的产生。然而&#xff0c;很多新手跨境电商卖家都面临一个共同的问题&#xff0c;那就是&#xff1a;Temu出单快吗&#xff1f;Temu上架多久能出单&#…

STM32CubeMX教程27 SDIO - 读写SD卡

目录 1、准备材料 2、实验目标 3、轮询方式读取SD卡流程 3.0、前提知识 3.1、CubeMX相关配置 3.1.0、工程基本配置 3.1.1、时钟树配置 3.1.2、外设参数配置 3.1.3、外设中断配置 3.2、生成代码 3.2.0、配置Project Manager页面 3.2.1、外设初始化调用流程 3.2.2、外设中断调用流…

激光雷达,角力「降本增效」

高工智能汽车研究院最新发布的数据显示&#xff0c;2023年1-11月&#xff0c;中国市场&#xff08;不含进出口&#xff09;乘用车前装标配激光雷达搭载量为46.48万颗&#xff0c;同比增长372.35%&#xff0c;继续保持高增长态势。 随着激光雷达在中国市场完成规模化上量的节点&…

Promethues是什么?

什么是Prometheus&#xff1f; Prometheus是一个开源的系统监控以及报警系统。整和zabbix的功能&#xff0c;系统&#xff0c;网络&#xff0c;设备。 promethues可以兼容网络、设备、容器监控、告警系统。因为和k8s是一个项目基金开发的产品&#xff0c;天生就匹配k8s的原生…

离线安装nginx_银河麒麟系统_nginx报错_503_500 Internal Server Error----nginx工作笔记007

如果报这个错误,意思就是,对于nginx.conf文件中指定的,文件夹没有权限 那么这个是去给对应的文件夹赋权限: chmod 777 /opt/module/test_web 就可以了,然后再去访问就不会报错了,还有 503的错误都可以这样解决 然后关于离线安装nginx,尝试了一下如果把之前安装过的nginx,直接…

AI-数学-高中-10-2-分数指数幂计算

原作者视频&#xff1a;初等函数】2分数指数幂的计算&#xff08;基础&#xff09;_哔哩哔哩_bilibili 方法1&#xff1a; 方法2&#xff1a;

Matlab绘图技巧-NAN元素绘图出现锯齿状解决办法

Matlab绘图技巧-NAN元素绘图出现锯齿状解决办法 想必有很多同学遇到绘制3维曲面热力图&#xff0c;有一些数据是nan&#xff0c;绘制出来的图会出现锯齿状&#xff1a;如下图&#xff1a;    如果用matlab直接绘制带nan的矩阵的话&#xff0c;则会像上图一样&#xff0c;当然…

【教程】iOS 手机抓包工具介绍及教程

&#x1f4f1; 最近又发现APP Store一款宝藏软件&#xff0c;克魔助手抓包工具&#xff0c;app刚上架&#xff0c;功能不断迭代中&#xff0c;目前18软妹币实惠价可享受终身版&#xff01;现在是下手的最好时机。 引言 移动端开发中&#xff0c;抓包工具已成为必备的工具之一…

电脑文件夹怎么加密保护?文件夹加密软件推荐

电脑文件夹可以帮助我们管理各种文件&#xff0c;而文件夹加密则可以有效地保护数据安全。那么&#xff0c;电脑文件夹该怎么加密保护呢&#xff1f;下面我们就一起来了解一下。 超大文件夹加密 电脑中会有一些存放着视频、图纸等大文件的文件夹。这些文件夹体积庞大&#xff…

面试官:Mysql中EXISTS与IN的使用有哪些差异

在数据库查询优化中&#xff0c;查询效率直接关系到应用程序性能。其中&#xff0c;IN和EXISTS是两种常见的子查询操作符&#xff0c;广泛应用于SQL查询语句&#xff0c;但它们在执行效率上有所不同。 本文深入探讨IN和EXISTS的工作原理&#xff0c;以及在何种情境下选择更为合…

QGIS使用地理配准将3857坐标系转成上海城建坐标

控制点格式 如 mapX mapY sourceX sourceY enable dX dY residual -58653 70641 13452659.39 3746386.025 1 0 0 0 -58653 65641 13452693.09 3740477.283 1 0 0 0 ......保存为.points格式 图层预处理 图层投影为3857坐标系 地理配准 1. 打开图层-地理配准 工具 2. 导入…

ATAC-seq发篇测序文章就结束了吗?看如何利用ATAC-seq数据为后续关键基因的转录调控研究提供重要依据

染色质可及性&#xff08;Chromatin Accessibility&#xff09;是染色质的一种特性&#xff0c;为转录因子结合靶基因提供了空间。转座酶可及染色质测序分析&#xff08;ATAC-seq&#xff09;是常见的研究染色质可及性的方法&#xff0c;ATAC-seq联合RNA-seq是一种新的研究思路…