使用AngularJs和Firebase实现无限滚动

7

如何在从Firebase获取的数据中实现无限滚动?到目前为止,我发现了一个AngularJS 指令,它非常好用,但我很难将其与Firebase一起实现,因为Firebase会在一个请求中返回所有数据,而这不是我想要的。


1
如果Firebase没有分页数据的方法,那么无限滚动就没有意义。但是我很难相信他们没有分页功能 - 你有查看过他们的API文档吗? - jraede
4
实际上,这就是分页。 :) http://jsfiddle.net/katowulf/yumaB/ - Kato
1个回答

19
几周前,我写了一个JS函数,实现了在我的应用中的无限滚动。

首先,当用户访问网站时,一组数据将被显示出来:

// Add a callback that is triggered for each message.
var n = 25; // Step size for messages display.
$(window).load(function() {
lastMessagesQuery = messagesRef.limit(n); 
lastMessagesQuery.on('child_added', function (snapshot) {
  var message = snapshot.val();
  $('<div/>').text(message.text).prependTo($('#messagesDiv'));
  $('#messagesDiv')[0].scrollTop = $('#messagesDiv')[0].scrollHeight;
});
$('#messagesDiv').fadeTo(1000, 1);
});

接下来,是实现无限滚动的函数:

// Pagination.
var i = 0; // Record variable.
function moreMessages () { 
i += n; // Record pagination updates. 
moreMessagesQuery = messagesRef; // Firebase reference.
moreMessagesQuery.on('value', function (snapshot) {
  var data = snapshot.exportVal(); // Fetch all data from Firebase as an Object.
  var keys = Object.keys(data).reverse(); // Due to the Keys are ordered from the oldest to the newest, it nessesary to change its sequence in order to display Firebase data snapshots properly.
  var total_keys = Object.keys(data).length;
  var k = keys[i]; // Key from where to start counting. Be careful what Key you pick.
  if (i < total_keys) { // Stop displaying messages when it reach the last one.
    lastMessagesQuery = messagesRef.endAt(null, k).limit(n); // Messages from a Key to the oldest.
    lastMessagesQuery.on('child_added', function (snapshot) {
      var message = snapshot.val();
      $('<div/>').text(message.text).appendTo($('#messagesDiv')).hide().fadeIn(1000); // Add set of messages (from the oldest to the newest) at the end of #messagesDiv.
    });
  }  
});
}

最后,无限滚动:

// Load more messages when scroll reach the bottom.
$(window).scroll(function() { 
if (window.scrollY == document.body.scrollHeight - window.innerHeight) {
  moreMessages();
}  
}); 

它在小数据集上表现很好。我希望这能帮助您解决问题(或给您更多的想法)。


2015年10月更新

Firebase自原回答以来已经发展壮大,这意味着现在只需使用其Javascript API就可以轻松实现无限滚动:

首先,我建议在Firebase中创建一个索引。对于这个答案,我创建了这个索引:

{
   "rules": {
      ".read": true,
      ".write": false,
      "messages": {
         ".indexOn": "id"
      }
   }
}

现在,让我们用Firebase创造一些奇迹吧:

// @fb: your Firebase.
// @data: messages, users, products... the dataset you want to do something with.
// @_start: min ID where you want to start fetching your data.
// @_end: max ID where you want to start fetching your data.
// @_n: Step size. In other words, how much data you want to fetch from Firebase.
var fb = new Firebase('https://<YOUR-FIREBASE-APP>.firebaseio.com/');
var data = [];
var _start = 0;
var _end = 9;
var _n = 10;
var getDataset = function() {
   fb.orderByChild('id').startAt(_start).endAt(_end).limitToLast(_n).on("child_added", function(dataSnapshot) {
      data.push(dataSnapshot.val());
   });
   _start = _start + _n;
   _end = _end + _n;
}

终于,更好的无限滚动功能(不需要jQuery):

window.addEventListener('scroll', function() {
  if (window.scrollY === document.body.scrollHeight - window.innerHeight) {
     getDataset();
  } 
});

我正在使用这种方法与 React 一起,无论数据有多大,它都非常快。

你要在哪里添加无限滚动?我滚动时没有反应。 - WJA
@JohnAndrews 我将它添加到我的主JS文件中。如果你正在使用React,只需查看此示例:https://github.com/heartyrobot/brands/blob/master/src/js/app.js#L56(顺便说一下,你需要显示“data”才能使事情发生。) - Jobsamuel
每次调用 getDataSet() 都注册一个 on 监听器... 这样做合理吗?而且只有在需要升序排列时才有效。 - Antoine
如果已经加载了页面并添加了一个子元素,您的代码会将它推到列表末尾而不是插入到正确的位置。 - Antoine
你说得对 @antoine129,我的代码只适用于升序排列,但这完全取决于你的需求。你可以轻松地反转data数组以满足你的需求...像这样var _data = data.reverse()或使用sort - Jobsamuel
@Jobsamuel 这是一个惊人的实现。我正在尝试使用Observable在Angular 2中完成完全相同的操作,看起来像这样:getUsers(): Observable<any> { return this.http.get(${baseUrl}.json).map((res: Response) => { this.data = res.json(); return this.data; }); }但是我无法实现,typescript一直说没有OrderByChild属性,请问您如何在Angular 2中实现它。谢谢 - Vijay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接