滚动React时更改样式

时间:2018-12-12 13:58:53

标签: reactjs scroll

我想添加滚动效果。首先,元素具有opacity: 0.2属性。在浏览器窗口中到达element时,它将用opacity: 1替换属性。此时,当我滚动时,所有元素都将属性更改为opacity: 1。当在浏览器中到达元素时,如何使该值生效,其余元素具有属性opacity: 0.2

class QuestionListItem extends Component {
  constructor() {
    super();
    this.state = {
      opacity: 0.2,
    };
  }

  componentDidMount = () => {
    window.addEventListener('scroll', () => {
      this.setState({
        opacity: 1,
      });
    });
  };

  render() {
    const { question } = this.props;
    const { opacity } = this.state;
    return (
      <div>
        <li
          key={question.id}
          className="Test__questions-item"
          style={{ opacity: `${opacity}` }}
          ref={
            (listener) => { this.listener = listener; }
          }
        >
          <p>
            {question.question}
          </p>
          <QuestionAnswerForm />
        </li>
      </div>
    );
  }
}

我想要这样的效果https://anemone.typeform.com/to/jgsLNG

2 个答案:

答案 0 :(得分:1)

正确的解决方案可能如下所示。当然,这只是一个概念。您可以使用top以外的getBoundingClientRect中的道具(例如,高度,底部等)微调激活/停用逻辑。 重要的是不要在每个滚动事件上都设置组件的状态。

class ScrollItem extends React.Component {
  state = {
    isActive: false
  }
  
  componentDidMount = () => {
    window.addEventListener('scroll', this.handleScroll);
    this.handleScroll();
  };
  
  handleScroll = () => {
    const { top } = this.wrapRef.getBoundingClientRect();
    if (top > 20 && top < 100 && !this.state.isActive) {
      this.setState({ isActive: true });
    }
    if ((top <= 20 || top >= 100) && this.state.isActive) {
      this.setState({ isActive: false });
    }
  }
  
  setWrapRef = ref => {
    this.wrapRef = ref;
  }
  
  render() {
    const { isActive } = this.state;
    return (
      <div
        className={`scroll-item ${isActive && 'scroll-item--active'}`}
        ref={this.setWrapRef}
        >
        {this.props.children}
      </div>
    )
  }
}


class ScrollExample extends React.Component {  
  render() {
    return (
      <div className="scroll-wrap">
        <ScrollItem>foo</ScrollItem>
        <ScrollItem>bar</ScrollItem>
        <ScrollItem>eh</ScrollItem>
      </div>);
  }
}

ReactDOM.render(<ScrollExample />, document.getElementById('root'))
.scroll-wrap {
  height: 300vh;
  background: lightgray;
  padding-top: 55px;
}

.scroll-item {
  height: 60vh;
  background: lightcyan;
  margin: 10px;
  opacity: 0.2;
}

.scroll-item--active {
  opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

答案 1 :(得分:0)

您可以在该组件中包含一个类似于 isInViewport 的实现:https://gist.github.com/davidtheclark/5515733,然后在您的组件上使用它。

componentDidMount = () => {
  window.addEventListener('scroll', (event) => {
    if (isElementInViewport(event.target) {
      this.setState({
        opacity: 1,
      });
    }
  });
};

对此也有一些阅读使用的react-addons:https://github.com/roderickhsiao/react-in-viewport