在React Typescript中检测窗口onscroll

时间:2017-10-01 07:24:20

标签: reactjs typescript

我正在使用React Typescript创建一个APP。我尽量避免在可能的情况下使用Jquery。

我需要检测窗口何时滚动到某个点,以便我可以更新标题类。这是如何在Jquery中完成的:

  $(window).scroll(function() {
    var scroll = $(window).scrollTop();
    if(scroll >= 200) {
      $(".navbar-default").addClass("dark");
    } else {
      $(".navbar-default").removeClass("dark");
    }
  });

我的入口点HTML看起来像这样(缩减)

<body>
<noscript>
  You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<body>

条目tsx文件:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Layout from './views/layout/layout';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { enthusiasm } from './reducers/index';
import { StoreState } from './types/index';

const store = createStore<StoreState>(enthusiasm, {
  enthusiasmLevel: 1,
  languageName: 'TypeScript',
});

ReactDOM.render(
  <Provider store={store}>
    <Layout />
  </Provider>,
  document.getElementById('root') as HTMLElement
);
registerServiceWorker();

复制此类事件的推荐方法是什么?

3 个答案:

答案 0 :(得分:1)

请记住更新状态,而不是dom元素。如果要在componentDidMount上添加新的liistener,则还必须删除componentWillUnmount上的侦听器。

componentDidMount: function() {
    window.addEventListener('scroll', this.handleScroll);
},

componentWillUnmount: function() {
    window.removeEventListener('scroll', this.handleScroll);
},

handleScroll: function(event) {
 //your code to handle scroll
},

答案 1 :(得分:0)

我们遇到了类似的问题,我们通过构建具有子功能的组件来解决它,如此

export interface ScrollElementProps {
  children?: (isInRange) => any
  throttle?: number
  maxScroll?: number
  minScroll?: number
}

export interface ScrollElementState {
  isInRange: boolean
}

export default
class ScrollElement extends React.Component<ScrollElementProps, ScrollElementState> {
  static defaultProps: Partial<ScrollElementProps> = {
    throttle: 200,
    minScroll: 0,
    maxScroll: Number.MAX_VALUE
  };

  state: ScrollElementState = {
    isInRange: false
  };

  private listenToScroll =
      _.throttle(this.props.throttle, () => this.scrollListener());

  componentWillMount() {
    window.addEventListener('scroll', this.listenToScroll);
  }

  componentDidMount() {
    this.listenToScroll();
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.listenToScroll);
  }

  render() {
    return this.props.children(this.state.isInRange);
  }

  private scrollListener() {
    this.setState({ isInRange: this.isWithinScrollRange() });
  }

  private isWithinScrollRange() {
    const { minScroll, maxScroll } = this.props;
    return _.inRange(minScroll, maxScroll, documentScrollTop());
  }
}

然后你可以像这样使用它:

<ScrollElement maxScroll={200}>
{isInRange => (
    <NavBar className={isInRange ? 'dark' : ''}/>
)}
</ScrollElement>

答案 2 :(得分:0)

我写了一个小型的React / Typescript解决方案,可以满足您的需求。

打字稿:

  interface AppState {
    scroller: number;
  }

  class Application extends React.Component<{}, AppState> {

    state = { scroller: 0 };

    handleScroll = () => {
      this.setState({ scroller: document.documentElement.scrollTop });
    };

    componentDidMount() {
      window.addEventListener("scroll", this.handleScroll);
    }

    componentWillUnmount() {
      window.removeEventListener("scroll", this.handleScroll);
    }

    render() {
      return (
        <div>
          <nav className={this.state.scroller > 200 ? 'dark' : 'normal'}>This is the nav bar (scroller: {this.state.scroller})</nav>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
          <p>Lorem ipsum dolor sit Lorem ipsum dolor sit Lorem ipsum dolor sit</p>
        </div>
      );
    }
  }

  /*
   * Render the above component into the div#app
   */
  React.render(<Application />, document.getElementById("root"));

HTML:

<div id="root"></app>

CSS(Sass):

body
  padding: 3rem
  background: #333
  display: flex
  font-family: Helvetica Neue

nav
  font-size: 2em
  display: inline-block
  position: fixed
  top: 0
  padding: 1rem

nav.dark
  background-color: black
  color: white

nav.normal
  background-color: lightgrey
  color: black

p
  margin-top: 1em
  color: #aaa
  width: 300px

在CodePen上尝试: https://codepen.io/anon/pen/oMQRqV

请注意,当滚动超过200时,“ nav”元素的颜色将如何变化。

希望这会有所帮助!