什么是react.js友好的动态列表重新排序的方式?

goj*_*omo 45 javascript css jquery reactjs

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

新信息到达时会略微改变分数,使得某些项目在重新排序后排名更高,而其他项目则更低.我希望这些项目可以同时动画到新的位置,而不是立即出现在新的位置.

是否有推荐的方法在React.js中执行此操作,也许使用流行的附加组件?

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

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

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

Jos*_*eau 40

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

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

它有一些不同于Magic Move/Shuffle的东西:

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

查看演示:

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

  • 几年后,这个模块仍然很强大:) 从那时起,我们引入了进入/离开动画,添加了更多可定制的道具,提高了性能,并缩小了包大小(现在低于 5kb gzip!) (2认同)

And*_*dru 9

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

看到它的实际效果:https://www.youtube.com/watch?v = z5e7kWSHWTg#t = 424

编辑:这在React 0.14中被破坏了.请参阅下面的Tim Arney建议的React Shuffle.


Tim*_*ney 9

React Shuffle是坚实的,最新的.它的灵感来自Ryan Florences Magic Move演示

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


Boo*_*oog 5

我不想为我的动画使用第三方库,因此我使用 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>;
  }
}
Run Code Online (Sandbox Code Playgroud)
.animate-on-transforms {
  /* animate list item reorder */
  transition: transform 300ms ease;
}
Run Code Online (Sandbox Code Playgroud)

  • 我在这个列表中最喜欢的答案是因为它不需要第三方库来实现OP所要求的。 (2认同)

And*_*oyd 5

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

开源并获得 MIT 许可,希望对您有所帮助!