关于使用react.js进行无限滚动,我有一个特别有趣的问题。
这里的目标是确保无论桌子有多大,我们都只允许render()
返回所有行的固定子集。
我们会让lowerVisualBound
和upperVisualBound
将行的子集表示为render()
到DOM上。
注意这些边界设置为大于视口,导致滚动条出现。
我们将修改lowerVisualBound
和{{ 1}}当用户滚动时。
在这里,我们进一步表示
upperVisualBound
作为表可见部分的高度height
作为整个表格的高度(包括totalHeight
和lowerVisualBound
之间的所有行upperVisualBound
和scrollTop
作为当前和上一个滚动顶部 以下片段类型的诡计 - 除了滚动条本身在加载其他数据后没有改变位置(即state.lastScrollTop
VisualBound重置)。这会导致用户的数据视图跳转。
upper or lower
任何人都可以建议算法来计算新的 const rowDisplayBoundry = 2 * this.props.pageSize;
if (scrollTop < this.state.lastScrollTop && scrollTop <= 0.0 * totalHeight) {
// up scroll limit triggered
newState.lowerVisualBound = Math.max(this.state.lowerVisualBound - this.props.pageSize, 0);
newState.upperVisualBound = newState.lowerVisualBound + rowDisplayBoundry;
} else if (scrollTop > this.state.lastScrollTop && (scrollTop + height) > totalHeight) {
// down scroll limit triggered
newState.upperVisualBound = this.state.upperVisualBound + this.props.pageSize;
newState.lowerVisualBound = newState.upperVisualBound - rowDisplayBoundry;
}
// TODO now what do we set scrollTop to, post these mutations? (presumably using a setTimeout())
,以便更改视觉边界可以保留用户和#39; s view?
注意我认为这应该在理论上是可行的,因为上面和下面之间的行数#下视觉界限设定为>可以在视口中显示的内容。因此,在这些边界中的每个突变之后,用户不会丢失他在突变之前立即查看的任何行。这只是计算滚动条后突变的正确位置的问题。
答案 0 :(得分:1)
以下似乎有效......虽然不确定是否存在不存在的极端情况(请原谅相当自由地使用jQuery选择器进行此演示)
handleScroll: function (e) {
const $target = $(e.target);
const scrollTop = $target.scrollTop();
const height = $target.height();
const totalHeight = $target.find("tbody").height();
const avgRowHeight = totalHeight / (this.state.upperVisualBound - this.state.lowerVisualBound);
/**
* always update lastScrollTop on scroll event - it helps us determine
* whether the next scroll event is up or down
*/
var newState = {lastScrollTop: scrollTop};
/**
* we determine the correct display boundaries by keeping the distance between lower and upper visual bound
* to some constant multiple of pageSize
*/
const rowDisplayBoundry = 2 * this.props.pageSize;
if (scrollTop < this.state.lastScrollTop && scrollTop <= 0) {
// up scroll limit triggered
newState.lowerVisualBound = Math.max(this.state.lowerVisualBound - this.props.pageSize, 0);
newState.upperVisualBound = newState.lowerVisualBound + rowDisplayBoundry;
// if top most rows reached, do nothing, otherwise reset scrollTop to preserve current view
if (!(newState.lowerVisualBound === 0))
setTimeout(function () {
$target.scrollTop(Math.max(scrollTop + this.props.pageSize * avgRowHeight, 0));
}.bind(this));
} else if (scrollTop > this.state.lastScrollTop && (scrollTop + height) >= totalHeight) {
// down scroll limit triggered
newState.upperVisualBound = this.state.upperVisualBound + this.props.pageSize;
newState.lowerVisualBound = newState.upperVisualBound - rowDisplayBoundry;
setTimeout(function () {
// TODO ensure that new scrollTop doesn't trigger another load event
// TODO ensure this computationally NOT through flagging variables
$target.scrollTop(scrollTop - this.props.pageSize * avgRowHeight);
}.bind(this));
}
this.setState(newState);
}