还在 jQuery 时代,就看到那种无限滚动按需加载效果,后来用 [ngInfiniteScroll(https://sroze.github.io/ngInfiniteScroll) 实现了一个。最近深度使用 material 时,发现框架自带的 md-virtual-repeat-container 结合 md-virtual-repeat 也能很好地实现无限滚动。
md-virtual-repeat-container
md-virtual-repeat-container 是 md-virtual-repeat 组件的滚动容器。它有以下属性:
md-top-index
:将滚动容器顶部项索引绑定到 $scope。它可以读取和设置滚动位置;md-orient-horizontal
:确定容器是否应水平滚动 (默认为方向是垂直滚动);md-auto-shrink
:当该数值小于原始尺寸时, 容器将收缩以适合项目数量;md-auto-shrink-min
:`md-auto-shrink 将收缩到的最小项目数(默认值 : 0)。
md-virtual-repeat
md-virtual-repeat
替换 ng-repeat
只呈现足够的 html 元素来填充容器并在用户滚动时重用它们。它有以下属性:
md-item-size
:重复元素的高度或宽度 (每个元素必须相同)。这是可选的。如果丢失, 则尝试从 DOM 读取大小, 但仍假定所有重复的节点具有相同的高度或宽度;md-extra-name
:为重复作用域上可以分配当前迭代项计算其他名称(用于md-autocomplete
中);md-on-demand
:如果设置,将md-virtual-repeat
参数视为可以获取行的对象而不是数组。此对象必须使用两个方法实现以下接口。- getItemAtIndex − function(index) [object]:尚未加载时该索引对应的项或
null
(应在该情况下开始下载该项目)。 - getLength − function() [number]:
md-virtual-repeat-container
调整大小后的数据长度。理想情况下, 当计数已知时, 此方法应返回它。否则, 返回比当前加载的项更高的数字以生成无限滚动行为。
代码实现
angular
.module('myApp', ['ngMaterial'])
.controller('AppCtrl', function($timeout, $filter) {
this.infiniteItems = {
loaded: 0,
toLoad: 0,
items: [],
getItemAtIndex: function(index) {
if (index > this.loaded) {
this.fetchMore(index);
return null;
}
return this.items[index];
},
getLength: function() {
return this.loaded + 5;
},
fetchMore: function(index) {
if (this.toLoad < index) {
this.toLoad += 20;
$timeout(function() {
var arr = [];
for (var i = 1; i < 21; i++) {
arr.push({
name: 'file' + (i + this.loaded).toString(),
size: 1000 + Math.ceil(1000 * Math.random()),
createTime: new Date().getTime() - Math.ceil(3600000 * 24 * 30 * Math.random())
});
}
this.items = this.items.concat(arr);
this.loaded = this.toLoad;
}.bind(this), 300);
}
}
}
})
本实例中,由于使用了 md-on-demand
属性,所以必须 getItemAtIndex
和 getLength
两个方法。其中 getLength
返回 this.loaded + 5
,比当前加载的项更高,这样才能生成无限滚动行为。
参考示例
访问 codepen 查看示例代码及效果。
为了演示方便我们用的异步模拟数据,我们在真实环境中应该是调用 Service 来实现。
评论 (0)