在React中滚动时添加和删除css类?

时间:2018-04-14 03:41:04

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

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

但是我注意到,滚动页面时,指针会挂起卡片,并在启用动画时停止注册滚动。我已经看到这篇文章(https://www.thecssninja.com/javascript/pointer-events-60fps)讨论了在滚动时禁用指针事件对主体的性能优势,但我无法弄清楚如何做出反应。

滚动事件结束后,如何滚动并删除该类时,如何在React ONLY中向文档正文添加类?也许以某种方式使用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>
    );
  }
}

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

1 个答案:

答案 0 :(得分:0)

切换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>
)