如何在样式组件中获取当前窗口的pageYOffset?

时间:2019-05-29 15:08:26

标签: javascript reactjs styled-components

我在努力依赖于窗口的scrollYOffset的翻译动画。

我有这样的东西:

const StyledHeading = styled.h1`
  font-size: ${({ theme }) => theme.fontSize.l};
  letter-spacing: 1px;
  font-family: ${({ theme }) => theme.font.firaSans};
  margin: 0;
  transition: 0.25s ease-in-out;
  transform: translateX(${({ offset }) => (offset > 100 ? '-50px' : '0px')});
`;

export default function Navbar() {
  const [offset, setOffset] = useState(window.pageYOffset);

  useEffect(() => {
    window.addEventListener('scroll', () => {
      setOffset(window.pageYOffset);
    });
  });

  return (
    <StyledHeader >
      <StyledWrapper>
        <StyledHeading offset={offset}>
          Bookphiles <i className="fas fa-book-open" />
        </StyledHeading>
        <nav>
          <NavLinks  />
        </nav>
      </StyledWrapper>
    </StyledHeader>
  );
}

但是它似乎以非常低效的方式完成,因为每次滚动都会导致DOM重新呈现。可以用更好的方法吗?

2 个答案:

答案 0 :(得分:1)

恕我直言,如果您想避免动画不连贯,则应该依靠refs DOM管理而不是React render():

import React, { useState, useEffect, createRef } from 'react';

export default function Navbar() {
  const ref = createRef();

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
  });

  handleScroll = (e) => {
      const offset = window.pageYOffset;
      ref.current.style.transform = `translateX(${({ offset }) => (offset > 100 ? '-50px' : '0px')})`;
  }

  return (
    //...code
        <StyledHeading ref={ref}>
          Bookphiles <i className="fas fa-book-open" />
        </StyledHeading>
    //..code
  );
}

请注意,我的代码中可能会有一些错别字,但概念是在滚动管理中不涉及重新渲染。 在卸载组件之前,请记住要删除侦听器。

答案 1 :(得分:0)

尝试使用lodash中的节流或防反弹功能来限制事件处理程序功能的执行次数。这样,事件处理程序最多仅每200毫秒执行一次:

window.addEventListener('scroll', _.throttle(() => {
  setOffset(window.pageYOffset);
}, 200));

这是一篇很好的文章,它更详细地解释了这个想法并提供了更多示例:https://css-tricks.com/debouncing-throttling-explained-examples/