React中如何实现当列表项顺序发生改变时进行动画效果?

8
我是一位有用的助手,可以为您进行翻译。以下是需要翻译的内容:

我有一个项目列表。当顺序改变时,我希望它们能够动画到它们的新位置。

之前:

<ul>
  <li>One</li>
  <li>Two</li>
</ul>

之后:

<ul>
  <li>Two</li>
  <li>One</li>
</ul>

有没有能够实现这一功能的库?我已经尝试过React Transition Group、React Pose和React Spring,但都不支持该功能,它们侧重于当项目进入和离开DOM时的动画效果。我有点惊讶,因为在我的看来,这似乎是一个常见的使用场景。

https://reactcommunity.org/react-transition-group/

https://popmotion.io/pose/

https://www.react-spring.io/


1个回答

17

在react-spring中有一个相关的示例,但它相当复杂,有很多事情发生。我从中创建了一个简化版本。

你有一个名称数组。你根据索引定义y值,并且可以使用translate属性移动元素。位置设置为absolute。

一次点击即可打乱数组顺序。另一个点击可以删除元素。在React Transition中,您可以定义进入和离开动画。离开动画会在删除元素时调用。

import { render } from 'react-dom';
import React, { useState } from 'react';
import { useTransition, animated } from 'react-spring';
import shuffle from 'lodash/shuffle';
import './styles.css';

let data = [
  {
    name: 'Rare Wind'
  },
  {
    name: 'Saint Petersburg'
  },
  {
    name: 'Deep Blue'
  },
  {
    name: 'Ripe Malinka'
  },
  {
    name: 'Near Moon'
  },
  {
    name: 'Wild Apple'
  }
];

function App() {
  const [rows, set] = useState(data);
  let height = 20;
  const transitions = useTransition(
    rows.map((data, i) => ({ ...data, height, y: i * height })),
    d => d.name,
    {
      from: { position: 'absolute', height: 20, opacity: 0 },
      leave: { height: 0, opacity: 0 },
      enter: ({ y, height }) => ({ y, height, opacity: 1 }),
      update: ({ y, height }) => ({ y, height })
    }
  );

  return (
    <div class="list" style={{ height }}>
      <button onClick={() => set(shuffle(rows))}>click</button>
      <button onClick={() => set(rows.slice(1))}>remove first</button>
      {transitions.map(({ item, props: { y, ...rest }, key }, index) => (
        <animated.div
          key={key}
          class="card"
          style={{
            zIndex: data.length - index,
            transform: y.interpolate(y => `translate3d(0,${y}px,0)`),
            ...rest
          }}
        >
          <div class="cell">
            <div class="details">{item.name}</div>
          </div>
        </animated.div>
      ))}
    </div>
  );
}

const rootElement = document.getElementById('root');
render(<App />, rootElement);

这是沙盒代码: https://codesandbox.io/s/animated-list-order-example-with-react-spring-teypu

编辑:我还添加了一个元素,因为这样更好看。:)

更新:这个沙盒代码来自necrifede,他将我的示例更新到了版本9.: https://codesandbox.io/s/animated-list-order-example-with-react-spring-forked-nhwqk9?file=/src/index.js


1
你能否友好地更新以适应Spring 9版本?usetransition稍有改动。 - Amin Noura
2
你好 @amin-noura,我在这里更新了使用 react-spring 版本 9。 https://codesandbox.io/s/animated-list-order-example-with-react-spring-forked-nhwqk9?file=/src/index.js - necrifede

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接