假设我使用.map
函数从状态的支柱渲染列表。
我想改变列表的顺序;所以我改变了我的州或我的道具的顺序。相应地反映了这种变化,但是在这种情况下如何添加平滑过渡以使用户感觉他/她已经做了某些事情。否则用户体验会降低。
他是我想要达到的基本想法
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
export class App extends React.Component {
constructor() {
super();
this.state = {
items: [
{ key: 0, name: "Hello" },
{ key: 0, name: "Sello" }, // move this down with transition
{ key: 0, name: "Wello" }, // move this up with transition
{ key: 0, name: "Zello" },
{ key: 0, name: "Pello" },
{ key: 0, name: "Aello" }
]
};
}
reShuffle = () => {
this.setState({
items: this.state.items.map((item, index) => {
if (index === 1) {
return this.state.items[2];
}
if (index === 2) {
return this.state.items[1];
}
return item;
})
});
};
render() {
return (
<div className="App" style={{ transition: "all 0.5s ease" }}>
<button onClick={this.reShuffle}> Click Me </button>
{this.state.items.map(item => <li key={item.key}> {item.name} </li>)}
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
可以从这里轻松复制https://codesandbox.io/s/648z61kvrn
当对react元素进行css转换时,你需要处理一个额外的状态:转换本身。
因此,首先更改组件的状态,以便css转换将更改它们,然后在转换结束时更改状态,以使反应在转换结束时与组件的样式匹配。
在您单击切换元素的情况下,您必须计算与切换元素具有相同效果的css更改,然后在转换结束时,实际切换元素。
我们需要在项目中添加top属性,并使用正确的密钥:
constructor() {
super();
this.state = {
items: [
{ key: 0, name: "Hello", top: 0 },
{ key: 1, name: "Sello", top: 0 }, // move this down
{ key: 2, name: "Wello", top: 0 }, // move this up
{ key: 3, name: "Zello", top: 0 },
{ key: 4, name: "Pello", top: 0 },
{ key: 5, name: "Aello", top: 0 }
],
transitioning: {}
};
this.itemTransitionCount = 0;
}
请注意itemTransitionCount以供日后使用。
首先将<li>
元素包装在<ul>
元素中,并将引用附加到<ul>
:
ulLoad = c => (this.ulDom = c);
render() {
...
<ul
ref={this.ulLoad}
style={{ position: "relative", display: "inline-block" }}
>
{
this.state.items.map(item => (
<li
key={item.key}
onTransitionEnd={this.itemTransitionEnd}
style={{
transition: item.top ? "top 0.5s ease" : "none",
position: "relative",
top: item.top
}}
>
{item.name}
</li>
))
}
</ul>
....
}
这将允许计算儿童<li>
s的相对位置
然后以这种方式更改你的reShuffle处理程序:
reShuffle = () => {
this.setState({
items: this.state.items.map((item, index) => {
if (index === 1) {
const top2 = this.ulDom.children[2].offsetTop;
const top1 = this.ulDom.children[1].offsetTop;
const top = top2 - top1;
return { ...this.state.items[1], top };
}
if (index === 2) {
const top1 = this.ulDom.children[1].offsetTop;
const top2 = this.ulDom.children[2].offsetTop;
const top = top1 - top2;
return { ...this.state.items[2], top };
}
return item;
})
});
此代码将启动我们要在li items上设置的顶部转换=>切换动画将在下一次渲染期间发生。
我们使用onTransitionEnd处理程序捕获两个动画的结尾(检查evt.target!== evt.currentTarget是因为转换事件起泡,计数在那里因为两个元素都会引发事件但是我们想要在两个过渡的结束):
itemTransitionEnd = evt => {
if (evt.target !== evt.currentTarget) return;
// alert("transitionEnd");
this.itemTransitionCount++;
if (this.itemTransitionCount < 2) return;
this.itemTransitionCount = 0;
this.setState({
items: this.state.items.map((item, index) => {
if (index === 1) {
return { ...this.state.items[2], top: 0 };
}
if (index === 2) {
return { ...this.state.items[1], top: 0 };
}
return item;
})
});
};
上面的代码实际上在转换结束时切换元素并重置它们的相对顶部(转换计数也会重置以进行下一次转换)。
这说明了React中css过渡动画的两步渲染。