三十、UI-Grid Infinite scroll 无限滚动

原文:Tutorial: 212 Infinite scroll

无限滚动功能允许用户将其数据延迟加载到gridOptions.data。

api文档中提供了Infinite scroll功能的文档,特别是:

一旦到达实际数据集的顶部(或底部),无限滚动将停止在该方向上触发事件。 可以通过infiniteScrollUp = true向上或向下通过infiniteScrollDown = true设置触发方向。默认未启动。

默认情况下,距离网格末端20行(在任一方向上)时,会触发数据请求。还可以通过设置infiniteScrollRowsFromEnd = 20指定触发请求时数据集末尾的行数。

还会触发needMoreData(向下)或needMoreDataTop(向上)事件,如果有更多可用数据,必须接收并响应。 一旦检索到数据则将其添加到数据阵列,还需要调用dataLoaded来确认已加载数据,或者没有更多数据,且不会在该方向上再触发更多数据的请求。

加载数据后,会调整网格滚动以显示连续滚动的外观。 假设用户在数据返回时已经到达滚动的末尾(向上或向下),会将用户滚动条到新添加的数据的开头。 在某些情况下,这可能会产生“跳跃式”滚动,特别是如果将rowsFromEnd设置为相当高的值,以便预读取数据 – 如果用户正在缓慢滚动它们可能距离末尾50行,当dataLoaded处理完会突然将滚动条移动到过去的结尾。 为避免这种情况,可以在数据添加之前通过调用saveScrollPercentage保存滚动位置,添加数据后dataLoaded调尝试调整滚动以使相同的行显示。

如果启用了无限滚动并且在该方向上仍有数据,那么当到达末尾时,会抑制将滚动传播到父容器。因此,如果有向上的页面,那么滚动到顶部将获得请求,而不是向上滚动整个页面。

如果正在使用外部排序或外部过滤,则只要发生滚动或过滤事件,就会重新加载数据。 在这种情况下,需要调用resetScroll以告知表格不要尝试保留先前的滚动位置。 当重置表格中的数据时,也可以使用此调用, 调用时必须声明此位置向上或者向下是否允许请求数据。

有时可能会删除数据,例如,如果将10页数据保留在内存中,并且在向底部添加数据时开始从顶部丢弃数据。 可以使用dataRemovedTop和dataRemovedBottom声明已丢弃数据,并将滚动设置回删除数据之前的位置。

为了通过以下示例获得更好的性能,您可以选择加载ui-grid.core.js和特定功能文件:

<script src="/release/ui-grid.core.min.js"></script>
<script src="/release/ui-grid.infinite-scroll.min.js"></script>

Example

在此示例中,我们有一个数据集,从5页数据集的第2页开始。 每页有100条记录,所以从记录200开始,可以向上滚动2页,向下滚动2页。 向上移动时应该看到平滑滚动,当到达记录零时,滚动会传播到父页面。 还可以在向下移动时看到平滑滚动,当到达记录499时,滚动会传播到父页面。

我们还会从内存中的数据集中删除数据,只在内存中保存4个页面,因此将丢弃页面并适当地重置scrollUp和scrollDown。 同样,当发生这种情况时,表格仍应保持滚动位置。

最后,我们可以重置数据,这会让我们回到中间页面并将滚动设置到顶部。

代码

index.html

<!doctype html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular-touch.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular-animate.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular-aria.js"></script>
<script src="http://ui-grid.info/docs/grunt-scripts/csv.js"></script>
<script src="http://ui-grid.info/docs/grunt-scripts/pdfmake.js"></script>
<script src="http://ui-grid.info/docs/grunt-scripts/vfs_fonts.js"></script>
<script src="http://ui-grid.info/docs/grunt-scripts/lodash.min.js"></script>
<script src="http://ui-grid.info/docs/grunt-scripts/jszip.min.js"></script>
<script src="http://ui-grid.info/docs/grunt-scripts/excel-builder.dist.js"></script>
<script src="/release/ui-grid.js"></script>
<script src="/release/ui-grid.css"></script>
<script src="app.js"></script>
</head>
<body>
<div><button id="reset" class="button">Reset</button>
First page: {{ $ctrl.firstPage }}     Last page: {{ $ctrl.lastPage }}     data.length: {{ data.length }}
<div class="grid"></div>
</div>
</body>
</html>

main.css

.grid {
    width: 500px;
    height: 400px;
}

app.js

var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.infiniteScroll']);
 
app.controller('MainCtrl', function ($scope, $http, $timeout) {
    var vm = this;

    vm.gridOptions = {
        infiniteScrollRowsFromEnd: 40,
        infiniteScrollUp: true,
        infiniteScrollDown: true,
        columnDefs: [
            { name:'id'},
            { name:'name' },
            { name:'age' }
        ],
        data: 'data',
        onRegisterApi: function(gridApi){
            gridApi.infiniteScroll.on.needLoadMoreData($scope, getDataDown);
            gridApi.infiniteScroll.on.needLoadMoreDataTop($scope, getDataUp);
            vm.gridApi = gridApi;
        }
    };

    $scope.data = [];

    vm.firstPage = 2;
    vm.lastPage = 2;

    function getFirstData() {
        return $http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/10000_complex.json').then(function(response) {
            var newData = getPage(response.data, vm.lastPage);             
            $scope.data = $scope.data.concat(newData);
        });
    }

    function getDataDown() {
        return $http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/10000_complex.json').then(function(response) {
            vm.lastPage++;
            var newData = getPage(response.data, vm.lastPage);
            vm.gridApi.infiniteScroll.saveScrollPercentage();
            $scope.data = $scope.data.concat(newData);
            return vm.gridApi.infiniteScroll.dataLoaded(vm.firstPage > 0, vm.lastPage < 4).then(function() {checkDataLength('up');});
        })
        .catch(function(error) {
            return vm.gridApi.infiniteScroll.dataLoaded();
        });
    }

    function getDataUp() {
        return $http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/10000_complex.json').then(function(response) {
            vm.firstPage--;
            var newData = getPage(response.data, vm.firstPage);
            vm.gridApi.infiniteScroll.saveScrollPercentage();
            $scope.data = newData.concat($scope.data);
            return vm.gridApi.infiniteScroll.dataLoaded(vm.firstPage > 0, vm.lastPage < 4).then(function() {checkDataLength('down');});
        })
        .catch(function(error) {
            return vm.gridApi.infiniteScroll.dataLoaded();
        });
    }

    function getPage(data, page) {
        var res = [];
        for (var i = (page * 100); i < (page + 1) * 100 && i < data.length; ++i) {
            res.push(data[i]);
        }
        return res;
    }

    function checkDataLength( discardDirection) {
        // work out whether we need to discard a page, if so discard from the direction passed in
        if( vm.lastPage - vm.firstPage > 3 ){
            // we want to remove a page
            vm.gridApi.infiniteScroll.saveScrollPercentage();

            if( discardDirection === 'up' ){
                $scope.data = $scope.data.slice(100);
                vm.firstPage++;
                $timeout(function() {
                    // wait for grid to ingest data changes
                    vm.gridApi.infiniteScroll.dataRemovedTop(vm.firstPage > 0, vm.lastPage < 4);
                });
            } else {
                $scope.data = $scope.data.slice(0, 400);
                vm.lastPage--;
                $timeout(function() {
                    // wait for grid to ingest data changes
                    vm.gridApi.infiniteScroll.dataRemovedBottom(vm.firstPage > 0, vm.lastPage < 4);
                });
            }
        }
    }

    vm.reset = function() {
        vm.firstPage = 2;
        vm.lastPage = 2;

        // turn off the infinite scroll handling up and down - hopefully this won't be needed after @swalters scrolling changes
        vm.gridApi.infiniteScroll.setScrollDirections( false, false );
        $scope.data = [];

        getFirstData().then(function(){
            $timeout(function() {
                // timeout needed to allow digest cycle to complete,and grid to finish ingesting the data
                vm.gridApi.infiniteScroll.resetScroll( vm.firstPage > 0, vm.lastPage < 4 );
            });
        });
    };

    getFirstData().then(function(){
        $timeout(function() {
            // timeout needed to allow digest cycle to complete,and grid to finish ingesting the data
            // you need to call resetData once you've loaded your data if you want to enable scroll up,
            // it adjusts the scroll position down one pixel so that we can generate scroll up events
            vm.gridApi.infiniteScroll.resetScroll( vm.firstPage > 0, vm.lastPage < 4 );
        });
    });
});

作者水平有限,不当之处敬请指正。
感谢您的阅读,如果觉得文章对您有帮助,请支持一下。

发表评论

电子邮件地址不会被公开。 必填项已用*标注