React countup 动画在页面加载后立即开始,应该在滚动到组件时开始(没有 jquery)

IT技术 reactjs counter react-animations
2021-04-11 20:42:25

我有一个包含多个组件的 React 单页应用程序。对于第 5 个组件(仅在向下滚动时可见),我有一个 counter 。现在我使用 react-countup 库来实现计数器功能。但是,计数器会在页面加载后立即启动。一旦我们向下滚动到组件,是否可以开始计数。页面加载后动画只发生一次(这很好),但我希望计数器不要在页面加载后不久开始,而是当用户第一次向下滚动到组件时。我的代码如下所示:

    render() {
         return (
         <div className={style.componentName}>
         <h2>Heading</h2>
         <div className={style.col}>
         <div>My counter</div>
         <CountUp className={style.countup} decimals={1} start={0} end={25} suffix=" %" duration={3} />
        </div>
        </div>)}

更新代码:

    import CountUp, { startAnimation } from 'react-countup';
    import VisibilitySensor from 'react-visibility-sensor';

    class className extends Component {

        state = {
            scrollStatus: true
        };


        onVisibilityChange = isVisible => {
            if (isVisible) {
                if (this.state.scrollStatus) {
                    startAnimation(this.myCountUp);
                    this.setState({ scrollStatus: false });
                }
            }
        }
    render() {
             return (
            <div className={style.componentName}>
             <h2>Heading</h2>
             <VisibilitySensor onChange={this.onVisibilityChange} offset = {{ top: 
              10}} delayedCall>
             <CountUp className={style.countup} decimals={1} start={0} end={25} 
             suffix=" %" duration={3} ref={countUp => { this.myCountUp= countUp;}}/>
             </VisibilitySensor>
            </div>)}
}
6个回答

API 可能自去年以来发生了变化。我现在设法使用此代码进行这项工作:

import React from "react";
import CountUp from "react-countup";
import VisibilitySensor from 'react-visibility-sensor';

const MyComponent = () => (
  <>
    <CountUp end={100} redraw={true}>
        {({ countUpRef, start }) => (
            <VisibilitySensor onChange={start} delayedCall>
                <span ref={countUpRef} />
            </VisibilitySensor>
        )}
    </CountUp>
  </>
);

export default App;

我在选项卡中使用此组件,因此该redraw={true}props仅用于在 tabChange 上重绘动画。

findDOMNode is deprecated in StrictMode 和解决办法?
2021-05-26 20:42:25
这应该是当前版本的答案
2021-05-31 20:42:25
干净简单。谢谢。
2021-06-03 20:42:25
如何让它只运行一次而不是每次进入视口?
2021-06-04 20:42:25
在与尝试其他方法的两个图书馆斗争数小时后,对我有用。谢谢!
2021-06-17 20:42:25

根据React CountUp 的 README,您可以使用startAnimation钩子手动启动动画。将它与react-visibility-sensor 之类的东西结合起来,您可以等待开始动画,直到它在用户的浏览器中可见。

import React, {Component} from 'react';
import CountUp, {startAnimation} from 'react-countup';
import './App.css';
import VisibilitySensor from 'react-visibility-sensor';

const style = {
  componentName: {},
  col: {},
  countup: {},
};

class App extends Component {
  constructor(props) {
    super(props);
    this.onVisibilityChange = this.onVisibilityChange.bind(this); // Bind for appropriate 'this' context
  }

  onVisibilityChange(isVisible) {
    if (isVisible) {
      startAnimation(this.myCountUp);
    }
  }

  render() {
    return (
      <div className={style.componentName}>
        <h2>Heading</h2>
        <div className={style.col}>
          <div>My counter</div>
          <VisibilitySensor
            onChange={this.onVisibilityChange}
            delayedCall // Prevents react apps triggering elements as visible before styles are loaded
          >
            <CountUp className={style.countup} decimals={1} start={0} end={25} suffix=" %" duration={3}
                     ref={countUp => { this.myCountUp = countUp; }} // From react-countup README 
            />
          </VisibilitySensor>
        </div>
      </div>
    );
  }
}

export default App;

startAnimation按原样每次滚动到计数时都会如此。如果您只想这样做一次,只需添加一个在第一次渲染后设置的状态(然后startAnimation根据更改的状态防止它再次执行)。

实现相同效果的不太优雅(不推荐)的方法可能包括:

  • 使用内置动画触发器(即更改 props duration, end, start),将它们设置为等于用户向下滚动时更改的某个状态
  • 利用在onStart动画开始之前调用props来延迟启动动画,直到用户向下滚动

编辑:更新以解决您的第二个问题

不幸的是,该react-countup库似乎没有公开防止startAnimation启动的方法。

但是我们可以通过end使用 state 来操纵prop 来组合一个相当优雅的修复

import React, {Component} from 'react';
import CountUp, {startAnimation} from 'react-countup';
import './App.css';
import VisibilitySensor from 'react-visibility-sensor';

const style = {
  componentName: {},
  col: {},
  countup: {},
};

class App extends Component {
  state = {
    didViewCountUp: false
  };


  onVisibilityChange = isVisible => {
    if (isVisible) {
      this.setState({didViewCountUp: true});
    }
  }

  render() {
    return (
      <div className={style.componentName}>
        <h2 style={{fontSize: '40em'}}>Heading</h2>
        <VisibilitySensor onChange={this.onVisibilityChange} offset={{
          top:
            10
        }} delayedCall>
          <CountUp className={style.countup} decimals={1} start={0} end={this.state.didViewCountUp ? 25 : 0}
                   suffix=" %" duration={3} />
        </VisibilitySensor>
      </div>)
  }
}

export default App;

你能用更新的代码编辑你的问题吗?将有助于尝试一下,也许可以根据您拥有的内容提出修复建议
2021-06-03 20:42:25
使用状态在第一次渲染后设置一个值。它完美地工作!非常感谢你。:) 但是有一个小错误,开头的计数器是 end count=25 并且动画从滚动到组件开始。即在 0-25 开始动画之前有一小段时间。
2021-06-12 20:42:25
我更新了代码。它与您回答的代码完全相同。使用 state 只执行一次“startAnimation”。
2021-06-17 20:42:25

这是我的实现。它只运行一次,并且每次组件进入视口以检查可见性时也不会重新渲染。

依赖项:
1. react- countup v.4.3.2
2. react-visibility-sensor v.5.1.1

import React, { useState } from "react";
import CountUp from "react-countup";
import VisibilitySensor from "react-visibility-sensor";

const Ticker = ({ className, ...rest }) => {
  const [viewPortEntered, setViewPortEntered] = useState(false);

  return (
    <CountUp {...rest} start={viewPortEntered ? null : 0}>
      {({ countUpRef }) => {
        return (
          <VisibilitySensor
            active={!viewPortEntered}
            onChange={isVisible => {
              if (isVisible) {
                setViewPortEntered(true);
              }
            }}
            delayedCall
          >
            <h4 className={className} ref={countUpRef} />
          </VisibilitySensor>
        );
      }}
    </CountUp>
  );
};

export default Ticker;

以下是如何使用它:

<Ticker className="count" end={21} suffix="M+" />

这是我使用基于类的组件的解决方案注意:导入两个库首先运行此代码 react-visibility-sensor react-countup

该库的文档有一种手动启动计数器的方法。一旦用户滚动到所需的距离,我就会使用这种方法来启动计数器。

import React, { Component } from 'react';
import CountUp, { startAnimation } from 'react-countup';

const MyComponent = () => (
  <div>
    <CountUp className="CountUp" start={0} end={100} duration={3} ref={(countUp) => {
      this.myCountUp = countUp;
    }} />
    <button className="Button" onClick={(event) => {
      startAnimation(this.myCountUp);
    }}>Count me up!</button>
  </div>
);

export default App;

链接到 Github阅读最底部的自述文件。