我正在尝试以与React-Virtualized相同的方式实现虚拟列表。
我已经让它工作了大部分但是当你滚动超过某个阈值时,列表会继续滚动而无需用户输入,直到它到达列表的末尾。我在做什么导致了这个?
这是Codepen。
有问题的组件是VirtualList组件。
const todoHeight = 40;
const viewport = { height: 800, width: 750 };
const itemsAllowedInView = viewport.height / todoHeight;
const numItems = 10000;
const maxScrollItems = numItems - itemsAllowedInView;
const maxScrollTop = todoHeight * maxScrollItems;
class VirtualList extends React.Component {
constructor(props) {
super(props);
this.state = {
currentIndex: 0,
amountRowsToRender: itemsAllowedInView * 2,
topPadding: 0,
bottomPadding: maxScrollTop - viewport.height
}
this.lastTop = 0;
}
scrollFunction(currentTop) {
if (this.lastTop === currentTop || currentTop >= maxScrollTop || currentTop < 0) { return; }
let currentIndex = Math.floor(currentTop / todoHeight);
let endIndex = Math.min(currentIndex + itemsAllowedInView, numItems);
// We want to render some extra for padding.
let bufferItems = itemsAllowedInView / 2;
let bufferSize = bufferItems * todoHeight;
// Create top Padding
let topPaddingHeight = 0;
let bottomPaddingHeight = 0;
topPaddingHeight = Math.max(0, currentTop - (bufferItems * todoHeight));
// bottomPaddingHeight = Math.min((currentTop - (bufferItems * todoHeight)) + itemsAllowedInView, maxScrollTop);
bottomPaddingHeight = Math.min(maxScrollTop - currentTop - viewport.height - (bufferItems * todoHeight), maxScrollTop);
this.lastTop = currentTop;
this.setState({
currentIndex: currentIndex,
topPadding: topPaddingHeight >= 0 ? topPaddingHeight : 0,
bottomPadding: bottomPaddingHeight >= 0 ? bottomPaddingHeight : 0,
})
}
catchScroll(e) {
this.scrollFunction.call(this, e.target.scrollTop);
}
paddingDiv(height) {
return (<div className='todo' style={{ height: height + 'px' }} />);
}
paddingTop() {
// if(this.state.topPadding > 0){
return (this.paddingDiv(this.state.topPadding));
// }
}
paddingBottom() {
// if(this.state.bottomPadding > 0){
return (this.paddingDiv(this.state.bottomPadding));
// }
}
render() {
return (
<div
className={'list-container'}
onScroll={this.catchScroll.bind(this)}
>
<div className={'inner-list'}>
{this.paddingTop.call(this)}
{!!this.props.todos && this.props.todos.slice(this.state.currentIndex, this.state.currentIndex + this.state.amountRowsToRender).map((todo, i) =>
<Todo content={todo.content}
height={todo.height ? todo.height : null}
id={i}
key={i}
completed={todo.completed}
/>
)}
{this.paddingBottom.call(this)}
</div>
</div>
)
}
}