react.js

时间:2015-06-28 13:23:49

标签: javascript reactjs

关于使用react.js进行无限滚动,我有一个特别有趣的问题。

这里的目标是确保无论桌子有多大,我们都只允许render()返回所有行的固定子集。

我们会让lowerVisualBoundupperVisualBound将行的子集表示为render()到DOM上。

注意这些边界设置为大于视口,导致滚动条出现。

我们将修改lowerVisualBound和{{ 1}}当用户滚动时。

在这里,我们进一步表示

  • upperVisualBound作为表可见部分的高度
  • height作为整个表格的高度(包括totalHeightlowerVisualBound之间的所有行
  • 分别为
  • upperVisualBoundscrollTop作为当前和上一个滚动顶部

以下片段类型的诡计 - 除了滚动条本身在加载其他数据后没有改变位置(即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?

注意我认为这应该在理论上是可行的,因为上面和下面之间的行数#下视觉界限设定为>可以在视口中显示的内容。因此,在这些边界中的每个突变之后,用户不会丢失他在突变之前立即查看的任何行。这只是计算滚动条后突变的正确位置的问题。

1 个答案:

答案 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);
}