当用户在粘性定位的 div 上滚动时为文本添加动画

问题描述 投票:0回答:2

我正在尝试在用户滚动时为四个标题设置动画。首先,我创建一个

sticky
定位的 div,然后用户滚动标题,一次切换一个类
.active
,使最后一个可见并继续滚动到最后一个 div。

我遇到的问题是,一旦

.sticky
div 变得粘性,浏览器就不再检测到进一步滚动,直到 div 再次变得不粘性。

--- 更新

我已经更改了代码以按顺序转换并且效果更好,但我想仅当

.sticky
div 变得粘滞时才启动动画,但我尝试了,滚动动画完全停止工作。另外,我想将所有标题保留在同一个块上,但如果我对它们执行
position: absolute
,它也会破坏动画。

const headings = Array.from(document.querySelectorAll('.animated-text'));
const sticky = document.querySelector('.sticky');

let currentActive = null;

window.addEventListener('scroll', () => {
  const viewportHeight = window.innerHeight;
  headings.forEach((heading, index) => {
    const headingRect = heading.getBoundingClientRect();

    if (headingRect.top <= viewportHeight / 2) {
      if (currentActive) {
        currentActive.classList.remove('active');
      }
      heading.classList.add('active');
      currentActive = heading;
    }
  });
});
body {
  margin: 0
}

section {
  position: relative;
}

.sticky {
  padding-bottom: 150px;
  background: #2d232c;
  position: sticky;
  top: 0;
  overflow: hidden;
  height: auto;
  color: white;
}

.animated-text {
  opacity: 0;
  height: 0;
  overflow: hidden;
  transition: opacity 1s ease, height 1s ease, transform 1s ease;
  transform: translateY(0);
}

.animated-text.active {
  height: auto;
  opacity: 1;
  transform: translateY(-20px);
}

.hero, .end {
  height: 100px;
  background: white;
}
<section class='hero'>
  <p>Start</p>
</section>

<section class='sticky'>
  <div class='text-animations'>
    <h1 class='animated-text active'>Intro</h1>
    <h2 class='animated-text'>First</h2>
    <h2 class='animated-text'>Second</h2>
    <h2 class='animated-text'>Third</h2>
  </div>
  <p class='intro_content'>
     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam
  </p>  
</section>

<section class='end'>
  <p>End<p>
</section>

javascript html css sticky
2个回答
0
投票

看起来您正试图在用户滚动并且粘性 div 进入视图时为标题创建动画效果。但是,当前代码只处理一次滚动事件,并且在 .sticky div 变得粘性后滚动不会继续。

为了达到在用户滚动时逐一切换标题的“活动”类的预期效果,您需要不断检查滚动位置并相应地更新活动标题。您可以通过使用 getBoundingClientRect() 方法来确定标题相对于视口的位置来实现此目的。

const headings = document.querySelectorAll('.animated-text');
const sticky = document.querySelector('.sticky');

window.addEventListener('scroll', () => {
  const stickyRect = sticky.getBoundingClientRect();

  headings.forEach((heading, index) => {
    const headingRect = heading.getBoundingClientRect();

    // Check if the heading is inside the sticky div and has come into view
    if (headingRect.top >= stickyRect.top && headingRect.bottom <= stickyRect.bottom) {
      // Add 'active' class to the current heading and remove it from the others
      heading.classList.add('active');
      for (let i = 0; i < headings.length; i++) {
        if (i !== index) {
          headings[i].classList.remove('active');
        }
      }
    }
  });
});
body {
  margin: 0;
}
section {
  position: relative;
}
.sticky {
  padding-bottom: 150px;
  background: #2d232c;
  position: sticky;
  top: 0;
  overflow: hidden;
  height: auto;
  color: white;
}
.animated-text {
  opacity: 0;
  max-height: 0;
  transition: opacity 1s ease, max-height 1s ease;
}
.animated-text.active {
  max-height: 1000px;
  opacity: 1;   
}
.hero, .end {
  height: 100px;
  background: white;
}
<!DOCTYPE html>
<html>
<head>
  <title>Scroll Animation</title>
 
</head>
<body>
  <section class='hero'>
    <p>Hero space</p>
  </section>

  <section class='sticky'>
    <div class='text-animations'>
      <h1 class='animated-text active'>Intro</h1>
      <h2 class='h1 animated-text'>First</h2>
      <h2 class='h1 animated-text'>Second</h2>
      <h2 class='h1 animated-text'>Third</h2>
      <h3 class='intro_content'>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam
      </h3>
    </div>      
  </section>

  <section class='end'>
    <p>Ends<p>
  </section>

使用此更新的代码,当用户滚动并且 .sticky div 变得粘性时,浏览器将继续检测进一步的滚动并相应地更新标题的“active”类,为标题一一提供所需的动画效果。


0
投票

根据将所有标题置于顶部的要求,添加

position:absolute; 
top:0;

.active
课程中解决了问题。

并且只有当

div
变得粘性时才开始动画,需要比较stickyDiv位置,然后应该实现动画逻辑。

我也尝试将标题转换的逻辑基于向上或向下滚动事件,以便无论滚动方向如何,标题都能正确地按顺序转换。 我知道代码需要大量重构,但我希望它能够按照要求工作。

let headings = Array.from(document.querySelectorAll('.animated-text'));
const sticky = document.querySelector('.sticky');
let lastScrollTop = 0;
let currentActive=0;
window.addEventListener('scroll', () => {
  const stickyDiv=sticky.getBoundingClientRect(); 
  let st = window.pageYOffset || document.documentElement.scrollTop; 
  if (st > lastScrollTop) {
     if (stickyDiv.top===0) {
     for(let i=currentActive;i<headings.length-1;i++)
        {
         const headingRect = headings[i].getBoundingClientRect();
         if(headingRect.top<=0){
                currentActive=i+1;
                headings[i].classList.remove('active');
                headings[i+1].classList.add('active');
         }
     }
  }
} else if (st < lastScrollTop) {
    if (stickyDiv.top===0) {
    for(let i=currentActive;i>0;i--)
    {
     const headingRect = headings[i].getBoundingClientRect();
     if(headingRect.top<=0){
            currentActive=i-1;
            headings[i].classList.remove('active');
            headings[i-1].classList.add('active');
     }
   }
  } }
  if(stickyDiv.top>0){
        headings[currentActive].classList.remove('active');
        currentActive=0;
        headings[0].classList.add('active');
  }
   lastScrollTop = st <= 0 ? 0 : st; 
   });

完整代码片段如下:-

let headings = Array.from(document.querySelectorAll('.animated-text'));
const sticky = document.querySelector('.sticky');
let lastScrollTop = 0;
let currentActive=0;
window.addEventListener('scroll', () => {
  const stickyDiv=sticky.getBoundingClientRect(); 
  let st = window.pageYOffset || document.documentElement.scrollTop; 
  if (st > lastScrollTop) {
     if (stickyDiv.top===0) {
     for(let i=currentActive;i<headings.length-1;i++)
        {
         const headingRect = headings[i].getBoundingClientRect();
         if(headingRect.top<=0){
                currentActive=i+1;
                headings[i].classList.remove('active');
                headings[i+1].classList.add('active');
         }
     }
  }
} else if (st < lastScrollTop) {
    if (stickyDiv.top===0) {
    for(let i=currentActive;i>0;i--)
    {
     const headingRect = headings[i].getBoundingClientRect();
     if(headingRect.top<=0){
            currentActive=i-1;
            headings[i].classList.remove('active');
            headings[i-1].classList.add('active');
     }
   }
  } }
  if(stickyDiv.top>0){
        headings[currentActive].classList.remove('active');
        currentActive=0;
        headings[0].classList.add('active');
  }
   lastScrollTop = st <= 0 ? 0 : st; 
   });
body {
  margin: 0
}

section {
  position: relative;
}

.sticky {
  padding-bottom: 150px;
  background: #2d232c;
  position: sticky;
  top: 0;
  overflow: hidden;
  height: auto;
  color: white;
}

.animated-text {
  opacity: 0;
  height: 0;
  overflow: hidden;
  transition: opacity 1s ease, height 1s ease, transform 1s ease;
  transform: translateY(0);
}

.animated-text.active {
  position:absolute;
  top:0;
  height: auto;
  opacity: 1;
  transform: translateY(-20px);
}

.hero, .end {
  height: 100px;
  background: white;
}
<section class='hero'>
  <p>Start</p>
</section>

<section class='sticky'>
  <div class='text-animations'>
    <h1 class='animated-text active'>Intro</h1>
    <h2 class='animated-text'>First</h2>
    <h2 class='animated-text'>Second</h2>
    <h2 class='animated-text'>Third</h2>
  </div>
  <p class='intro_content'>
     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam
  </p>  
</section>

<section class='end'>
  <p>End<p>
</section>

如果逻辑有任何不清楚或需要澄清的部分,请随时询问。

© www.soinside.com 2019 - 2024. All rights reserved.