【问题标题】:Add and remove css class only during scroll in React?仅在 React 滚动期间添加和删除 css 类?
【发布时间】:2018-09-24 10:37:44
【问题描述】:

我正在为我的投资组合制作一个模型博客,其中有一个帖子网格,这些帖子是 400x400 卡片,具有悬停效果,可增加比例并添加阴影(在仪表板路线中呈现)。

然而,我注意到当滚动我的页面时,指针会挂在卡片上并在启用动画时停止注册滚动。我看到这篇文章 (https://www.thecssninja.com/javascript/pointer-events-60fps) 讨论了在滚动时禁用指向正文的指针事件的性能优势,但是我不知道如何在反应中做到这一点。

如何在 React 中仅在滚动时向文档正文添加一个类,并在滚动事件结束后立即删除该类?也许以某种方式使用setTimeOut?我觉得那将是一个笨拙的解决方案......

我包含了我希望在其中实现它的代码,我不知道这是否会有所帮助。我已经设置的滚动事件是在扩展导航栏的同时保持页面的滚动位置。

export default class Layout extends Component {
  constructor(props) {
    super(props);
    this.state = {
      hasMenuOpen: false,
      scroll: {x: 0, y: 0},
    };
    this.handleScrollY = _.debounce(this.handleScrollY, 250);
    this.handleWidthChange = _.debounce(this.handleWidthChange, 250);
  }
  componentDidMount() {
    window.addEventListener('scroll', this.handleScrollY);
    window.addEventListener('resize', this.handleWidthChange);
    console.log('mount');
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
    if (prevState.hasMenuOpen) {
      /* eslint-disable */
      let {x, y} = prevState.scroll;
      /* eslint-enable */
      // correct scroll y position back to 0 for positions <= 100
      window.scrollTo(x, (y <= 100 ? y = 0 : y));
    }
  }
  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScrollY);
    window.removEventListener('resize', this.handleWidthChange);
  }
  // if menu is open an y = 0 (i.e position: fixed was added),
  // scroll = previous states scroll
  // else if you scroll and the menu isn't open, scroll = windows new scroll pos
  handleScrollY = () => {
    const y = window.scrollY;
    const x = window.scrollX;
    this.setState((prevState) => {
      if (this.state.hasMenuOpen && y === 0) {
        return {scroll: Object.assign({}, prevState.scroll)};
      }
      return {scroll: Object.assign({}, prevState.scroll, {x}, {y})};
    });
  }
  handleWidthChange = () => {
    console.log(window.innerWidth);
    if (this.state.hasMenuOpen) {
      return this.handleBurgerClick();
    }
    return null;
  }
  handleBurgerClick = () => {
    this.setState((prevState) => ({
      hasMenuOpen: !prevState.hasMenuOpen
    }));
  }
  handleLinkClick = () => {
    this.setState((prevState) => ({
      hasMenuOpen: false
    }));
  }
  render() {
    const scrollTop = {
      top: `-${this.state.scroll.y}px`,
    };
    console.log(this.state.scroll);
    return (
      <React.Fragment>
        <Navbar onClick={this.handleBurgerClick} hasMenuOpen={this.state.hasMenuOpen} onLinkClick={this.handleLinkClick} />
        <div className={this.state.hasMenuOpen ? styles.scroll_lock : ''} style={this.state.hasMenuOpen ? scrollTop : {}}>
          <main className={styles.page_margin} >
            <div className={this.state.hasMenuOpen ? styles.margin_extended : styles.margin_top}>
              <Route path='/' exact component={Dashboard} />
              <Route path='/new-post' component={NewPost} />
            </div>
          </main>
        </div>
      </React.Fragment>
    );
  }
}

例如,我尝试在componentDidMount() 中设置document.body.style.pointerEvents = 'auto' 并在handleScrollY() 中禁用它,但这显然不起作用,因为一旦发生滚动事件,指针事件就永远不会恢复。我也尝试在componentDidUpdate() 中设置它,但这似乎也不起作用,因为当滚动事件没有发生时,没有更新任何组件。

【问题讨论】:

  • TL;DR 如果用户正在滚动,您需要切换className?如果是这样,为什么不采用一种更简单的方法来向滚动添加事件侦听器并切换状态?
  • 我需要在正文上添加它,但是我只需要在窗口滚动时添加类,并在滚动停止后立即删除它。滚动停止后如何切换状态,事件仅在滚动发生时触发?
  • 检查您是否可以根据您的目的调整我的答案。

标签: javascript css reactjs event-handling css-animations


【解决方案1】:

切换 CSS 类的一种方法是:

componentWillUnmount() {
  document.removeEventListener('scroll');
}
componentDidMount() {
  document.addEventListener('scroll', (event) => {
    const that = this;
    if (!that.state.isScrolling) {
      that.setState({ isScrolling: true });
      setTimeout(() => {
        that.setState({ isScrolling: false });
      }, 300);
    }
  });
}

然后使用stateprops 切换className

在你的 JSX 中类似于

return (
  <div className={`class1 class2 class99 ${this.state.isScrolling ? 'scrolling' : 'not-scrolling'}`} >Content</div>
)

【讨论】:

  • 在 render 中添加会不会很糟糕,因为它会在每次重新渲染后不断向 dom 添加事件侦听器?
  • 你是对的!你教会了我一些新东西。对其进行了编辑,在使用 Chrome devTools 检查后,我一次只能看到一个事件侦听器。
猜你喜欢
  • 2017-10-02
  • 1970-01-01
  • 2016-12-25
  • 1970-01-01
  • 2021-10-14
  • 2013-10-26
  • 2018-01-06
  • 1970-01-01
  • 2023-03-14
相关资源
最近更新 更多