在React中创建交换列表时,我遇到了一个奇怪的过渡错误。列表的工作方式很简单:单击元素(A),其背景转换为较浅的颜色,然后单击另一个(B),它们交换位置,而现在位于新位置的元素A转换回该位置。原始颜色。
至少当元素A的索引高于元素B的索引时,会发生这种情况。反之亦然,交换后的过渡将被削减。
我设法找到了使用window.requestAnimationFrame
的解决方法,但这并不完美。过渡状态不会保留,这意味着它总是从完整的浅色过渡回来。这无关紧要,但这是我其他项目中的一个问题。有时,过渡也总是被切断。
代码很简单。需要注意的是,元素在交换后保留其键。我创建了a code sandbox供您玩耍。
import React, { useState } from "react";
const Item = props => {
let classes = "item";
if (props.selected) {
classes += " selected";
}
return (
<div className={classes} onClick={props.onClick}>
{props.value}
</div>
);
};
const App = () => {
const [list, setList] = useState([1, 2, 3]);
const [selected, setSelected] = useState(-1);
const select = index => {
setSelected(index);
};
const swap = index => {
const newList = [...list];
[newList[index], newList[selected]] = [newList[selected], newList[index]];
setList(newList);
setSelected(-1);
};
// The workaround that kind of works, but is not perfect.
// const swap = index => {
// const newList = [...list];
// [newList[index], newList[selected]] = [newList[selected], newList[index]];
// setList(newList);
// window.requestAnimationFrame(() => {
// setSelected(index);
// window.requestAnimationFrame(() => {
// setSelected(-1);
// });
// });
// };
const onClick = selected < 0 ? select : swap;
const items = list.map((value, index) => (
<Item
key={value}
value={value}
selected={selected === index}
onClick={onClick.bind(this, index)}
/>
));
return <div className="list">{items}</div>;
}
以下是关键的CSS规则:
.item {
background: #0b7189; // darker
transition: background-color 1s;
}
.item.selected {
background-color: #228cdb; //lighter
}
我正在寻找比解决方法更可靠的解决方案。
所有帮助将不胜感激! :)
答案 0 :(得分:0)
I've made three changes in your code,因此在交换突出显示的框时,框保持不变,然后将其关闭:
setSelected(index);
。setTimeout
以延迟颜色更改。key
循环内的map
更改为index
的值,因为它必须是唯一的,因此使用索引是一种更好的做法。function App() {
const [list, setList] = useState([1, 2, 3]);
const [selected, setSelected] = useState(-1);
const select = index => {
setSelected(index);
};
const swap = index => {
const newList = [...list];
[newList[index], newList[selected]] = [newList[selected], newList[index]];
setList(newList);
// This was added in order to keep the highlight after swap.
// Note that it takes a second to take place
setSelected(index);
// And this was added in order to allow the colour to lighten,
// before returning to the original colour
setTimeout(() => setSelected(-1), 1000);
};
const onClick = selected < 0 ? select : swap;
const items = list.map((value, index) => (
<Item
key={index}
value={value}
selected={selected === index}
onClick={onClick.bind(this, index)}
/>
));
return <div className="list">{items}</div>;
}