【问题标题】:How to make a React component fade in on scroll using IntersectionObserver, but only once?如何使用 IntersectionObserver 使 React 组件在滚动时淡入,但只有一次?
【发布时间】:2020-01-04 23:22:49
【问题描述】:

我试图在用户滚动时在 React 中为组件提供淡入效果,但我希望淡入效果仅在元素第一次移入视口时发生。

目前,我使用的代码在每次元素移入视口时都会导致淡入,因此它们会不断淡入和淡出。

这是我的淡入组件:

import React, {useState, useRef, useEffect} from 'react';
import './styles/FadeInSection.css';

export default function FadeInSection(props) {
  const [isVisible, setVisible] = useState(true);

  const domRef = React.useRef();

  useEffect(() => {
    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => setVisible(entry.isIntersecting));
    });

    observer.observe(domRef.current);

    return () => observer.unobserve(domRef.current);
  }, []);

  return (
    <div ref={ domRef } className={ `fade-in-section ${ isVisible ? 'is-visible' : '' }` }>
      { props.children }
    </div>
  )
}

这些是我正在使用的样式:

.fade-in-section {
  opacity: 0;
  transform: translateY(20vh);
  isibility: hidden;
  transition: opacity 0.2s ease-out, transform 0.6s ease-out;
  will-change: opacity, visibility;
}

.fade-in-section.is-visible {
  opacity: 1;
  transform: none;
  visibility: visible;
  display: flex; 
}

这是我的网站,它不断地淡入淡出组件,提供了糟糕的体验:

这是想要的效果:

怎样才能达到想要的效果?

这里是代码沙箱的链接来测试它:Code sandbox link

【问题讨论】:

    标签: javascript reactjs scroll fadein intersection-observer


    【解决方案1】:

    如果entry.isIntersectingtrue,你只需要调用setVisible,所以只需替换:

    setVisible(entry.isIntersecting);
    

    与:

    entry.isIntersecting && setVisible(true);
    

    这样,一旦一个条目已经被标记为可见,即使你向上滚动,它也不会被取消标记,因此元素会离开视口,entry.isIntersecting 再次变为false

    实际上,您甚至可以在那时致电observer.unobserve,因为您不再关心了。

    const FadeInSection = ({
      children,
    }) => {
      const domRef = React.useRef();
      
      const [isVisible, setVisible] = React.useState(false);
    
      React.useEffect(() => {
        const observer = new IntersectionObserver(entries => {
          // In your case there's only one element to observe:     
          if (entries[0].isIntersecting) {
          
            // Not possible to set it back to false like this:
            setVisible(true);
            
            // No need to keep observing:
            observer.unobserve(domRef.current);
          }
        });
        
        observer.observe(domRef.current);
        
        return () => observer.unobserve(domRef.current);
      }, []);
    
      return (<section ref={ domRef } className={ isVisible ? ' is-visible' : '' }>{ children }</section>);
    };
    
    const App = () => {  
      const items = [1, 2, 3, 4, 5, 6, 7, 8].map(number => (
        <FadeInSection key={ number }>Section { number }</FadeInSection>
      ));
    
      return (<main>{ items }</main>);
    }
    
    ReactDOM.render(<App />, document.querySelector('#app'));
    body {
      font-family: monospace;
      margin: 0;
    }
    
    section {
      padding: 16px;
      margin: 16px;
      box-shadow: 0 0 8px rgba(0, 0, 0, .125);
      height: 64px;
      opacity: 0;
      transform: translate(0, 50%);
      visibility: hidden;
      transition: opacity 300ms ease-out, transform 300ms ease-out;
      will-change: opacity, visibility;
    }
    
    .is-visible {
      opacity: 1;
      transform: none;
      visibility: visible;
      display: flex; 
    }
    <script src="https://unpkg.com/react@16.12.0/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js"></script>
    
    <div id="app"></div>

    【讨论】:

    • 我在我的代码中将 setVisible 更改为 setVisible(prevValue => prevValue || entry.isIntersecting) ,无论出于何种原因,它都停止了淡入淡出效果。组件现在总是在那里,没有淡入。不知道我做错了什么
    • @klaurtar1 没有更多细节很难说。也许尝试将您的代码与上面 sn-p 中的代码进行比较。如您所见,这很有效。否则,请尝试在问题中发布您当前的代码。
    • 感谢您的帮助。我在原始帖子的底部包含了一个指向带有工作代码的沙箱的链接。如果你能看一看,我将不胜感激
    • 你有useState(true)而不是useState(false)if (entries.isIntersecting)而不是if (entries[0].isIntersecting)。固定在这里:codesandbox.io/s/musing-bush-xys5b.
    • 感谢分享答案。我学到了很多@Danziger
    猜你喜欢
    • 1970-01-01
    • 2020-11-30
    • 1970-01-01
    • 1970-01-01
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    相关资源
    最近更新 更多