我有一个带分数的项目列表,按分数排序,由react.js呈现为垂直方向的矩形项目列表(顶部最高分)。对各个项目进行悬停和其他点击可能会显示/隐藏额外信息,从而更改其垂直高度。
新信息到达时会略微改变分数,使得某些项目在重新排序后排名更高,而其他项目则更低。我希望这些项目可以同时动画到新的位置,而不是立即出现在新的位置。
是否有推荐的方法在React.js中执行此操作,也许使用流行的附加组件?
(在使用D3的类似过去的情况下,我使用的技术大致是:
现在我希望以React-ish的方式产生类似的效果...)
我刚刚发布了一个模块来解决这个问题
https://github.com/joshwcomeau/react-flip-move
它有一些不同于Magic Move / Shuffle的东西:
查看演示:
http://joshwcomeau.github.io/react-flip-move/examples/#/shuffle
React Shuffle是坚实的,最新的。它的灵感来自Ryan Florences Magic Move演示
我意识到这是一个古老的问题,你现在可能已经找到了解决方案,但对于遇到这个问题的其他人来说,请查看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作为替代方案。
我能想到的最好的方法是首先确保你给每个元素一个键,如下所述:
http://facebook.github.io/react/docs/multiple-components.html#dynamic-children
接下来我将定义类似于此的CSS3动画:
基本上在你的渲染函数中你会计算元素的位置,ReactJS会将元素放在它想象的位置(确保你每次都给每个元素赋予相同的键!这对于确保ReactJS重用你的DOM元素很重要正确)。至少在理论上,CSS应该在reactjs / javascript之外为你处理动画的其余部分。
免责声明......我从未真正尝试过这个;)
我不想为我的动画使用第三方库,所以我使用React生命周期方法getSnapshotBeforeUpdate()和componentDidUpdate()实现了“FLIP”动画技术。
当列表项的props.index更改时,在getSnapshotBeforeUpdate()和componentDidUpdate()中捕获旧位置,将应用css transform: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;
}
因为元素的位置在很大程度上取决于DOM引擎,我发现在React组件中以纯粹的方式实现补间和动画真的很难。如果你想干净利落,我认为你至少需要:一个商店来保存一个元素的当前位置,一个商店来保存一个元素的下一个位置(或者将它与前一个商店结合起来)和一个渲染( )方法应用每个元素的偏移边距直到最后一帧,下一个位置变为当前。如何计算下一个位置也是一个挑战。但是假设元素只交换位置,你可以使用Store与当前位置交换元素#0和元素#1,通过在下一个位置Store中交换它们的偏移量。
最后,使用外部库在渲染后操纵元素的边距会更容易。
只需使用ReactCSSTransitionGroup。它内置于React with Addons包中,非常适合这个用例!只需确保应用转换的组件已安装到DOM。使用链接示例中的CSS进行漂亮的渐变过渡。