用react-flip-move给list加动画

今日需求来咯:给一个垂直排列的list组件,在变换顺序期间,有个过渡效果,最终实现像这样:

用react-flip-move给list加动画

开始之前,我对比了市面上比较主流的几个工具库react-flip-movereact-spring,和react-motion

  • react-flip-move
    用法稍微简单一点,不过只能适用于list,grid这一类的排列类型的组件。
  • react-spring
    很全面的动画库,当然用起来也很复杂,有个springConfig,用来调节动画的参数,学习成本很高。
  • react-motion
    react-spring封装后做了简化,只是用起来还是比react-flip-move要复杂,但适合各种需求,覆盖面很广。

我这个动画是加载可拖拽list上的,因为那个draggable list是用react-dnd实现的(《用react-dnd做一个可拖拽排列的list》),考虑到react-flip-move能更好地和react-dnd结合,我就选用了react-flip-move。如果你的前端项目有很多各种各样的动画需求,还是推荐你用react-motionreact-spring

react-flip-move官方文档中的示例是用react class component实现的,这篇文章我将仿照官网中Shuffle.tsx介绍如何用函数式组件实现,尤其是ref的部分会不太一样。

ListItem

首先画出ListItem组件,后期可能允许使用者传入自己的children,目前我先做出最简单的形式:

// ListItem.tsx
import React from 'react';

type Props = {
  id: number;
  index: number;
  text: string;
}

const ListItem = (props: Props) => {
  const { id, index, text } = props;
  const listClass = `list-item card list`;
  const style = { zIndex: 100 - index, border: '2px blue solid', height: 30 };

  return (
    <li id={id} className={listClass} style={style}>
      {text}
    </li>
  );
};

export default ListItem;

SortableList

SortableListListItem的父组件,我先mock了一点数据(PETS),然后在父组件中引用flip-move

// SortableList.tsx
import shuffle from 'lodash/shuffle';
import React, { useState } from 'react';
import FlipMove from 'react-flip-move';
import ListItem from './components/listItem/ListItem2';


const PETS = [
  { id: 1, name: 'dog' },
  { id: 2, name: 'cat' },
  { id: 3, name: 'fish' },
  { id: 4, name: 'hamster' },
]

const SortableList = () => {
  const [pets, setPets] = useState(PETS)

  const shufflePets = () => {
    setPets(prev => shuffle(prev));
  }
  
  return (
    <div
      style={{
        position: 'relative',
        width: '600px',
        height: '400px',
        border: '2px aqua solid'
      }}
    >
      <button onClick={shufflePets}>Shuffle</button>
      <FlipMove
        staggerDurationBy="30"
        duration={500}
        enterAnimation="accordionVertical"
        leaveAnimation="accordionVertical"
        typeName="ul"
      >
        {pets.map((pet, index) => (
          <ListItem
              key={pet.id}
              id={pet.id}
              index={index}
              text={pet.name}
          />
        ))}
      </FlipMove>
    </div>
  );
}

export default SortableList;

这样我们在页面上可以看到这样的list,点了shuffle按钮后,顺序就重新随机排列,这是一瞬间的变化,没有任何过渡效果。

用react-flip-move给list加动画

moveListItem动画(shuffle)

于class component不同的是,在functional component中,我们需要将目标组件加上ref,让flip-move能get到那个element,才能加上动画。

// ListItem.tsx
import React, { forwardRef } from 'react';

type Props = {
  id: number;
  index: number;
  text: string;
}

const ListItem = forwardRef((props: Props, ref) => {  // <--- use 'forwardRef' to connect ref
  const { id, index, text } = props;
  const listClass = `list-item card list`;
  const style = { zIndex: 100 - index, border: '2px blue solid', height: 30 };

  return (
    <li id={id} className={listClass} style={style} ref={ref}>
      {text}
    </li>
  );
});

export default ListItem;

这样就实现了我们想要的效果了,是不是很简单?

用react-flip-move给list加动画

延展 – FLIP

这里要注意flip-move,顾名思义,flip是这个动画实现的本质。

  • ffirst,即在一个动画周期中组件的初始状态。
  • llast,即组件的最终状态。
  • iinvert,意思是反方向推断出一个变化,比如初始状态到最终状态是向下移动90px,那么inverttransform: -90px,方向是反的,这样让最终状态的组件看上去是在初始状态一样。
  • pplay,在transition后,invert的效果会被removed,这样整个过程看上去像是,从first状态到last状态,实际上是“虚假”的first状态(inverted from last)到last状态。

结尾

我在上一篇文章介绍了如何通过拖拽改变list的顺序(《用react-dnd做一个可拖拽排列的list》),如果加上这篇文章介绍的动画库,我们是不是可以做一个很丝滑的draggable list啦?那么接下来的实现可以参考这一篇文章(期待中)。

原文链接:https://juejin.cn/post/7346128417127874579 作者:利器之路

(0)
上一篇 2024年3月15日 上午10:11
下一篇 2024年3月15日 下午4:05

相关推荐

发表回复

登录后才能评论