React项目实战(四)滚动的数字

需求

分析:我们要实现一个数字滚动效果,保证每个位上的数字都至少滚动一周,滚动效果是自下往上。让我们先思考一下几个细节:
① 方案的选取:css?js?
② 滚动的内容是什么?如果使用css动画用什么实现,如果使用js用什么实现?
③ 怎么实现每个位上的数字依次停止?

目前实现

基于background-position-y实现定位到具体数字,使用transition-duration实现每个位上的数字依次暂停,模仿掘金页面的实现实现效果如下:
滚动的数字

可以跳过的一节

说一下我的思路历程吧,我一开始居然没想到用动画来实现,而是用setTimeout递归地插入每个位上的数字,写完之后才发现没有实现滚动。然后又search了一下滚动效果,发现了一个HTML标签<marquee>,虽然我在浏览器上可以用,但是MDN提示我们这个标签已废弃惹。好吧,一开始就应该想到动画的。
marquee

预备知识

  • react提供了一个react-transition-group库,我们可以通过几种方式实现

    • 定义className结合css样式
        //官方案例
        function App() {
          const [inProp, setInProp] = useState(false);
          return (
            <div>
              <CSSTransition in={inProp} timeout={200} classNames="my-node">
                <div>
                  {"I'll receive my-node-* classes"}
                </div>
              </CSSTransition>
              <button type="button" onClick={() => setInProp(true)}>
                Click to Enter
              </button>
            </div>
          );
        }
      
        .my-node-enter {
          opacity: 0;
        }
        .my-node-enter-active {
          opacity: 1;
          transition: opacity 200ms;
        }
        .my-node-exit {
          opacity: 1;
        }
        .my-node-exit-active {
          opacity: 0;
          transition: opacity 200ms;
        }
      
    • 使用钩子
      • 进入状态:onEnter、onEntering、onEntered
      • 退出状态:onExit、onExiting、onExited
  • css的background属性

    | 属性 | 值 | 作用 |
    |——|————|————|
    | background-size | length|percentage|cover|contain | 规定背景图像的尺寸,可用于自适应 |
    | background-repeat | repeat|repeat-x|repeat-y|no-repeat|inherit |定义了图像的平铺模式 |
    | background-image | url | 元素设置背景图像 |

具体实现

  • 背景图片的设置
    因为找不到掘金的图片,所以自己用ps做了一个24px ✖ 480px的背景图片,在实际使用中,我们要记住这个长宽比是1:2,方便后面做自适应调整,初始style设置如下:
      span {
          display: inline-block;
          background-image: url("number-bg-24-480.png");
          background-repeat: repeat-y;
          background-position: center 0;
          background-size: 1.5rem 30rem;
          width: 1.5rem;
          height: 3rem;
      }
    
  • 切分字符串为数组
        this.setState({
          data: nextProps.str.split('')
        })
    
  • 具体动画设置:回顾一下我们预先定义的每个位上数字大小为1.5rem ✖ 3rem,那么总长度为30rem,我们要使得每个数字至少滚动一周,最后依次停止,具体设置如下:
      <TransitionGroup className="text-list">
          {this.state.data.map((val, index) => {
              return (
              <CSSTransition
                  key={index}
                  timeout={500}
                  onEnter={e => {
                    e.style.backgroundPositionY=`0`
                  }}
                  onEntering={
                    e => {
                      e.style.backgroundPositionY=`${-3*val - 30}rem`
                      e.style.transitionProperty="background-position-y"
                      e.style.transitionDuration=`${(index+1)*this.state.delay}ms`
                    }
                  }
                >
                  <span key={index} />
              </CSSTransition>
              )
           })}
      </TransitionGroup>
    

大功告成啦,虽然是一个很简单的小动画,看起来还是很炫酷的嘛,顺带回顾了一下css的一些基础知识。
项目地址


 上一篇
【翻译】为什么我们需要写super(props) 【翻译】为什么我们需要写super(props)
原文链接Why Do We Write super(props)? 我听说Hooks是最近的热点。讽刺的是,我将从类组件的有趣之处开始这篇博客。这也不错吧! 对于高效地使用React来说,这些陷阱并不是非常重要。但是如果你想更加深
2019-05-15
下一篇 
React项目实战(三)拉动刷新组件的实现 React项目实战(三)拉动刷新组件的实现
总结下实现组件过程中遇到的问题;可能还有需要改进的地方 上一篇React项目实践(二)一个登录页面的状态迁移 需求分析:我们需要实现两个方向(向下拉动,向上滑动)上的拉动刷新,考虑完成 PullDownRefresh 和 PullUpR
2019-04-16
  目录