什么是对列表重新排序进行动画处理.js反应友好方式

What's a react.js-friendly way to animate a list-reordering?

本文关键字:js 处理 动画 方式 列表 新排序 排序 什么      更新时间:2023-09-26

我有一个带有分数的项目列表,按分数排序,按 react 呈现.js作为垂直方向的矩形项目列表(最高分数在顶部)。悬停和对单个项目的其他单击可能会显示/隐藏额外信息,从而更改其垂直高度。

新信息到达,略微改变分数,使一些项目在重新排序后排名更高,而另一些项目排名更低。我希望这些物品同时动画化到它们的新位置,而不是立即出现在它们的新位置。

有没有推荐的方法可以在 React.js 中做到这一点,也许使用流行的附加组件?

(在过去使用 D3 的类似情况下,我使用的一种技术大致是:

  1. 按自然顺序显示包含项目 DOM 节点的列表,并具有相对定位。通过相对定位,其他小的变化(CSS或JS触发)在一定程度上会按预期移动其他项目。
  2. 在一个
  3. 步骤中改变所有 DOM 节点,使其实际相对坐标作为新的绝对坐标 - DOM 更改不会导致视觉变化。
  4. 将项 DOM 节点在其父节点中重新排序为新的排序顺序 - 另一个不会导致视觉变化的 DOM 更改。
  5. 根据
  6. 新排序中所有先前项的高度,将所有节点的顶部偏移量动画化为新的计算值。这是唯一视觉活动步骤。
  7. 将所有项目 DOM 节点突变回非偏移相对定位。同样,这不会导致视觉变化,但是现在相对定位的 DOM 节点,按照底层列表的自然顺序,将通过适当的移动来处理内部悬停/展开/等样式更改。

现在我希望以类似 React 的方式产生类似的效果......

我刚刚发布了一个模块来解决这个问题

https://github.com/joshwcomeau/react-flip-move

它与魔术移动/随机播放有一些不同的事情:

  1. 它使用FLIP技术进行硬件加速的60FPS +动画
  2. 它提供了通过增量抵消延迟或持续时间来"人性化"随机播放的选项
  3. 它优雅地处理中断,没有奇怪的故障效果
  4. 一堆其他整洁的东西,如开始/结束回调

查看演示:

http://joshwcomeau.github.io/react-flip-move/examples/#/shuffle

React Shuffle 是可靠的和最新的。 它的灵感来自Ryan Florences Magic Move演示

https://github.com/FormidableLabs/react-shuffle

我意识到这是一个有点老的问题,你现在可能已经找到了解决方案,但对于遇到这个问题的其他人,请查看 Ryan Florence 的 MagicMove 库。这是一个 React 库来处理你描述的确切场景:https://github.com/ryanflorence/react-magic-move

查看实际操作:https://www.youtube.com/watch?v=z5e7kWSHWTg#t=424

编辑:这在 React 0.14 中被破坏了。 参见 React Shuffle 作为替代方案,正如下面 Tim Arney 所建议的那样。

我不想为我的动画使用第三方库,所以我使用 React 生命周期方法 getSnapshotBeforeUpdate() 和 componentDidUpdate() 实现了"FLIP"动画技术。

当列表项的 props.index 更改时,将在 getSnapshotBeforeUpdate() 中捕获旧位置,并在 componentDidUpdate() 中应用 css 转换:translateY(),以便该项目看起来从旧位置到当前位置进行动画处理。

class TreeListItem extends Component {
  constructor(props) {
    super(props);
    this.liRef = React.createRef();
  }
  getSnapshotBeforeUpdate(prevProps) {
    if (prevProps.index !== this.props.index) {
      // list index is changing, prepare to animate
      if (this.liRef && this.liRef.current) {
        return this.liRef.current.getBoundingClientRect().top;
      }
    }
    return null;
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
    if (prevProps.index !== this.props.index && snapshot) {
      if (this.liRef && this.liRef.current) {
        let el = this.liRef.current;
        let newOffset = el.getBoundingClientRect().top;
        let invert = parseInt(snapshot - newOffset);
        el.classList.remove('animate-on-transforms');
        el.style.transform = `translateY(${invert}px)`;
        // Wait for the next frame so we
        // know all the style changes have
        // taken hold.
        requestAnimationFrame(function () {
          // Switch on animations.
          el.classList.add('animate-on-transforms');
          // GO GO GOOOOOO!
          el.style.transform = '';
        });
      }
    }
  }
  render() {
    return <li ref={this.liRef}>
    </li >;
  }
}
class TreeList extends Component {
  render() {
    let treeItems = [];
    if (this.props.dataSet instanceof Array) {
      this.props.dataSet.forEach((data, i) => {
        treeItems.push(<TreeListItem index={i} key={data.value} />)
      });
    }
    return <ul>
      {treeItems}
      </ul>;
  }
}
.animate-on-transforms {
  /* animate list item reorder */
  transition: transform 300ms ease;
}

这里来晚了,但我们刚刚发布了AutoAnimate,它允许您使用一行代码为在DOM元素内进入,离开或移动的元素添加动画。可与 React、Vue 或任何其他 Javascript 框架配合使用,大小小于 2kb。

开源和麻省理工学院许可,希望对您有所帮助!

我能想到的最好的方法来做到这一点是首先确保你给每个元素一个键,如下所述:

http://facebook.github.io/react/docs/multiple-components.html#dynamic-children

接下来,我将定义类似于以下内容的 CSS3 动画:

使用 CSS3 对列表进行动画处理

基本上在你的渲染函数中,你会计算元素应该去哪里,ReactJS 会把元素放在它应该去的地方(确保你每次都给每个元素相同的键!这对于确保 ReactJS 正确重用您的 DOM 元素非常重要)。 至少在理论上,CSS 应该在 reactjs/javascript 之外为你处理动画的其余部分。

声明者...我从来没有真正尝试过这个;)

我刚刚找到了这个库: https://www.npmjs.com/package/react-animated-list,它非常神奇,你只需要通过孩子:

import { AnimatedList } from 'react-animated-list';
import { MyOtherComponent } from './MyOtherComponent';
const MyComponent = ({myData}) => (
  <AnimatedList animation={"grow"}>
    {otherComponents.map((c) => (
      <MyOtherComponent key={c.id} />
    ))}
  </AnimatedList>
)

演示:https://codesandbox.io/s/nifty-platform-dj1iz?fontsize=14&hidenavigation=1&theme=dark

繁荣它会为你工作。

因为元素的位置在很大程度上取决于 DOM 引擎,我发现很难在 React 组件中以纯粹的方式实现补间和动画。如果你想干净利落地做到这一点,我认为你至少需要:一个存储来保存元素的当前位置,一个存储来保存元素的下一个位置(或将其与上一个存储组合),以及一个 render() 方法,该方法应用每个元素的偏移边距直到最后一帧, 下一个位置变为当前位置。首先如何计算下一个位置也是一个挑战。但是,鉴于元素仅交换位置,您可以使用具有当前位置的存储来将元素 #0 与元素 #1 交换,方法是在下一个位置存储中交换它们的偏移量。

最后,在渲染元素后,使用外部库来操作元素的边距会更容易。

只需使用 ReactCSSTransitionGroup。它内置在 React with Addons 包中,非常适合这个用例!只需确保应用过渡的组件已挂载到 DOM 即可。 使用链接示例中的 CSS 进行漂亮的淡入淡出过渡。