如何使用样式化的组件在 React 中的滚动条上播放动画

how to use a styled component to play an animation on scroll in react

我一直在尝试使用样式组件动画让我的导航栏在向下滚动时改变颜色,并在我向上滚动时 return 将其恢复为原始颜色。我目前面临的唯一问题是,我不知道如何只在您向下滚动页面时触发它,然后 return 当我再次点击顶部时它恢复正常。

const ChangeColor = keyframes`
0%{
  background-color: #121314;
}
100%{
    background-color: white;
}
`;

const GeneralContainer = styled.body`
  background-color: #121314;
  height: 10000px;

  margin: 0;
`;

const NavBarContainer = styled.div`
  border: 1px green solid;
  height: 64px;
  position: fixed;
  width: 100%;
  animation: ${NavForward} 1s linear alternate forwards 1; //I just want this to fire once when I scroll downward and fire again when I return to the top of the page.
`;

export default function Home() {
  const [offset, setOffset] = useState(0);
  const [isUpper, setIsUpper] = useState(true); // was trying to use this to trigger but couldnt

  useEffect(() => {
    const onScroll = () => {
      setOffset(window.pageYOffset);
      if (window.pageYOffset > 30 && isUpper === true) {
        setIsUpper(false);
      } else if (window.pageYOffset <= 30 && isUpper === false) {
        setIsUpper(true);
      }
    };
    // clean up code
    window.removeEventListener("scroll", onScroll);
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  return (
    <GeneralContainer>
      <NavBarContainer
        isUpper={isUpper}
        scoll={offset}
      ></NavBarContainer>
    </GeneralContainer>
  );
}

我个人不会为此使用动画。添加和删​​除 classes 是更简单的方法。

您想要做的与您已经在做的类似,但基本上是设置另一种效果,以便在 Y 偏移超过您的任意高度时收听。

首先,设置一个我们将在处理滚动的效果中调用的函数:

const handleScroll = () => setOffset(window.pageYOffset);

然后创建一个专门的效果来处理滚动:

useEffect(() => {
  window.addEventListener("scroll", handleScroll);
  return () => {
    window.removeEventListener("scroll", handleScroll);
  };
}, []);

然后,在另一种效果中,我们将听取是否超过了 hide/show 背景颜色的像素数量:

useEffect(() => {
  if (offset > 100) {
    setIsUpper(false);
  } else {
    setIsUpper(true);
  }
}, [offset]);

有了这个,我们需要让样式化的组件知道什么时候发生了变化。使用 css class 很适合这里的工作:

<NavBarContainer className={isUpper ? "active" : ""}></NavBarContainer>

然后在您的 NavBarContainer 样式组件中,只需添加一个 class 确保使用过渡而不是动画:

const NavBarContainer = styled.div`
  // ... the rest of your styles
  transition: 1s ease;

  &.active {
    background-color: white;
  }
`;

所有这些都应该有效。 Check out the sandbox here. 一个工作示例。

此外,我已将您的 GeneralContainer 组件更改为使用 div,因为它是 HTML 标签而不是 body 标签。这是因为您的 React 应用程序安装到 div 并且在 body 中嵌套 body 在技术上是无效的 HTML.

你可以这样做:

// Get a hook function
const {
  useState,
  useEffect
} = React;

const Home = () => {
  const [offset, setOffset] = useState(0);
  const [isUpper, setIsUpper] = useState(true); // was trying to use this to trigger but couldnt

  useEffect(() => {
    const onScroll = () => {
      setOffset(window.pageYOffset);
      if (window.pageYOffset > 30) {
        setIsUpper(false);
      } else if (window.pageYOffset <= 30) {
        setIsUpper(true);
      }
    };
    // clean up code
    window.removeEventListener("scroll", onScroll);
    window.addEventListener("scroll", onScroll, {
      passive: true
    });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  return ( <nav className ={isUpper ? 'top' : ''} > < /nav>
  );
};

// Render it
ReactDOM.render( <
  Home / > ,
  document.getElementById("react")
);
body {
  height: 2000px;
}

nav {
  height: 50px;
  position: fixed;
  top: 0;
  width: 100%;
  background-color: red;
  transition: background-color 1s ease;
}

nav.top {
  background-color: blue;
  transition: background-color 1s ease;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>