【日常记录】【JS】js 实现元素平滑上升

1、效果图

在这里插入图片描述

2、基本骨架

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    .container {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      width: 100%;
      padding-top: 300px;

    }

    .item {
      width: 70vw;
      height: 500px;
      margin-bottom: 20px;
      border-radius: 15px;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="item" style="background-color: #cee288;" data-index="1"></div>
    <div class="item" style="background-color: #775414;" data-index="2"></div>
    <div class="item" style="background-color: #681dd1;" data-index="3"></div>
    <div class="item" style="background-color: #38d1a6;" data-index="4"></div>
    <div class="item" style="background-color: #50e211;" data-index="5"></div>
    <div class="item" style="background-color: #53357b;" data-index="6"></div>
    <div class="item" style="background-color: #f196ee;" data-index="7"></div>
  </div>
</body>

</html>

3、实现

为了不污染原有的样式,就不用css属性了,直接用JS创建动画
创建完动画,不能先让它执行动画,执行与不执行是我们决定

    let itemsEl = document.querySelectorAll('.item');
    itemsEl.forEach(f => {
      // 为了不污染原有的 transition 等其他属性,可以自己创建一个动画
      console.log(isInViewport(f), f);
      if (!isInViewport(f)) return
      let translateYAnimate = f.animate([
        { transform: 'translateY(80px)' },
        { transform: 'translateY(0)' }
      ], {
        duration: 1000, // 动画时常
      })
      translateYAnimate.pause() // 先暂停所有动画,需要通过其他的方法来判断 这个DOM 是否进入可视区

    })

在这里插入图片描述

这样达到的效果是,界面一加载,都做动画了,并不是预想的结果,需要判断这个Item 是否进入可视区,如果进入可视区,才能做动画

      let observe = new IntersectionObserver((entries) => {
        entries.forEach(f => {
          console.log(f);
          if (f.isIntersecting) {
            translateYAnimate.play()
            observe.unobserve(f.target) // 观察一次就行,只需要做一次动画
          } else {
          }
        })
      })
      observe.observe(f)

这样确实可以实现了,但是 浏览器会记住滚动条的位置,就会导致有问题,

  • 刚进来的时候,看到的DOM 并不需要做动画
  • 如果滚动到某一个位置后,刷新界面,再往上滚动,上面的DOM 也不需要做动画了

核心就是判断当前的DOM 距离视口顶部的距离 是否超过了 视口的高度, 如果是,才需要做动画,否则不需要

4、完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    .container {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      width: 100%;
      padding-top: 300px;

    }

    .item {
      width: 70vw;
      height: 500px;
      margin-bottom: 20px;
      border-radius: 15px;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="item" style="background-color: #cee288;" data-index="1"></div>
    <div class="item" style="background-color: #775414;" data-index="2"></div>
    <div class="item" style="background-color: #681dd1;" data-index="3"></div>
    <div class="item" style="background-color: #38d1a6;" data-index="4"></div>
    <div class="item" style="background-color: #50e211;" data-index="5"></div>
    <div class="item" style="background-color: #53357b;" data-index="6"></div>
    <div class="item" style="background-color: #f196ee;" data-index="7"></div>
  </div>

  <script>
  // 判断这个元素,是否在可视区里面
    const isInViewport = (el) => {
      const rect = el.getBoundingClientRect();
      console.log(rect.top);
      return (
        rect.top >= 0 &&
        rect.top >= (window.innerHeight || document.documentElement.clientHeight)
      );
    };
    let itemsEl = document.querySelectorAll('.item');
    // let elAnimateMap = new Map();
    itemsEl.forEach(f => {
      // 为了不污染原有的 transition 等其他属性,可以自己创建一个动画
      if (!isInViewport(f)) return
      let translateYAnimate = f.animate([
        { transform: 'translateY(80px)' },
        { transform: 'translateY(0)' }
      ], {
        duration: 1000, // 动画时常

      })
      translateYAnimate.pause() // 先暂停所有动画,需要通过其他的方法来判断 这个DOM 是否进入可视区
      // elAnimateMap.set(f, translateYAnimate)




      let observe = new IntersectionObserver((entries) => {
        entries.forEach(f => {
          console.log(f);
          if (f.isIntersecting) {
            translateYAnimate.play()
            // elAnimateMap.get(f.target).play()
            observe.unobserve(f.target) // 观察一次就行
          } else {
            // translateYAnimate.pause()
          }
        })
      })
      observe.observe(f)
    })

  </script>
</body>

</html>
  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript(简称JS)是一种广泛应用于网页开发的脚本语言,它可以为网页添加动态功能和交互性。而requestAnimationFrame是JS提供的一个用于优化动画效果的方法,它可以在浏览器的重绘之前执行指定的函数,从而实现平滑的动画效果。 要实现平滑轮播,可以使用requestAnimationFrame方法来更新轮播图的位置。具体步骤如下: 1. 获取轮播图容器和轮播项的相关元素。 2. 设置一个变量来记录当前轮播项的索引。 3. 使用requestAnimationFrame方法创建一个循环函数,用于更新轮播图的位置。 4. 在循环函数中,根据当前轮播项的索引计算出下一个轮播项的位置,并通过CSS属性或transform属性来实现平滑过渡。 5. 更新当前轮播项的索引,使其指向下一个轮播项。 6. 使用requestAnimationFrame方法递归调用循环函数,实现连续的平滑轮播效果。 下面是一个简单的示例代码: ```javascript // 获取轮播图容器和轮播项元素 const slider = document.querySelector('.slider'); const items = document.querySelectorAll('.slider-item'); // 设置当前轮播项的索引 let currentIndex = 0; // 定义循环函数 function animate() { // 计算下一个轮播项的索引 const nextIndex = (currentIndex + 1) % items.length; // 计算下一个轮播项的位置 const nextPosition = -nextIndex * slider.offsetWidth; // 使用CSS属性或transform属性实现平滑过渡 slider.style.transform = `translateX(${nextPosition}px)`; // 更新当前轮播项的索引 currentIndex = nextIndex; // 递归调用循环函数 requestAnimationFrame(animate); } // 启动轮播动画 requestAnimationFrame(animate); ``` 这段代码中,我们使用了translateX属性来实现轮播图的平移效果,通过改变translateX的值来改变轮播图的位置。使用requestAnimationFrame方法来不断更新轮播图的位置,从而实现平滑的轮播效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值