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