用react-flip-move给list加动画

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

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

  • react-flip-move 用法稍微简单一点,不过只能适用于list,grid这一类的排列类型的组件。
  • react-spring 很全面的动画库,当然用起来也很复杂,有个springConfig,用来调节动画的参数,学习成本很高。
  • react-motionreact-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,目前我先做出最简单的形式:

tsx 复制代码
// 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

tsx 复制代码
// 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按钮后,顺序就重新随机排列,这是一瞬间的变化,没有任何过渡效果。

moveListItem动画(shuffle)

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

tsx 复制代码
// 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;

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

延展 - 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啦?那么接下来的实现可以参考这一篇文章(期待中)。

相关推荐
我认不到你23 分钟前
antd proFromSelect 懒加载+模糊查询
前端·javascript·react.js·typescript
scc214033 分钟前
spark的学习-06
javascript·学习·spark
我是苏苏1 小时前
C# Main函数中调用异步方法
前端·javascript·c#
转角羊儿1 小时前
uni-app文章列表制作⑧
前端·javascript·uni-app
Bio Coder2 小时前
学习用 Javascript、HTML、CSS 以及 Node.js 开发一个 uTools 插件,学习计划及其周期
javascript·学习·html·开发·utools
凹凸曼打不赢小怪兽3 小时前
react 受控组件和非受控组件
前端·javascript·react.js
鑫宝Code4 小时前
【React】状态管理之Redux
前端·react.js·前端框架
忠实米线4 小时前
使用pdf-lib.js实现pdf添加自定义水印功能
前端·javascript·pdf
明辉光焱5 小时前
[Electron]总结:如何创建Electron+Element Plus的项目
前端·javascript·electron
牧码岛5 小时前
Web前端之汉字排序、sort与localeCompare的介绍、编码顺序与字典顺序的区别
前端·javascript·web·web前端