Бесконечный свиток с ember.js(ленивая загрузка)
У меня есть представление, где может быть большое количество элементов для прокрутки пользователя, и я хотел бы реализовать бесконечную прокрутку, чтобы обеспечить прогрессивную загрузку содержимого.
Похоже, что некоторые люди сделали разбивку на страницы, но Google не вызывает никого, кто обсуждает, как они делали бесконечные списки с данными Ember/Ember. Кто-нибудь уже работал над этим и имеет код для публикации в блоге/пример для совместного использования?
Ответы
Ответ 1
Вы знали о недавно выпущенном компоненте Ember.ListView?
https://github.com/emberjs/list-view
Это было объявлено на февральском собрании в Сан-Франциско. Здесь slidedeck от Эрика Брина, одного из разработчиков Ember Core об использовании его:
http://talks.erikbryn.com/ember-list-view/
Ответ 2
Я реализовал бесконечный механизм прокрутки в проекте GitHub Dashboard
, который я сейчас разрабатываю. Функция добавлена в commit 68d1728.
Основная идея состоит в том, чтобы иметь LoadMoreView
, который вызывает метод loadMore
на контроллере каждый раз, когда вид виден в текущем окне просмотра. Для этого я использую плагин jQuery inview. Он позволяет вам регистрироваться для события inview
, которое запускается, когда элемент указанного селектора отображается на экране и когда он исчезает.
Контроллер также имеет свойства, указывающие, есть ли больше загружаемых товаров, и если в данный момент есть элементы. Эти свойства называются canLoadMore
и isLoading
.
LoadMoreView
в основном выглядит следующим образом:
App.LoadMoreView = Ember.View.extend({
templateName: 'loadMore',
didInsertElement: function() {
var view = this;
this.$().bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
if (isInView) Ember.tryInvoke(view.get('controller'), 'loadMore');
});
}
});
где шаблон loadMore
определяется следующим образом:
{{#if isLoading}}
fetching some more stuff <img width="10" src="img/ajax-loader.gif" >
{{else}}
{{#if canLoadMore}}
<a {{action "loadMore" target="controller" }}>click to load more items</a>
{{else}}
<i>no more items</i>
{{/if}}
{{/if}}
Затем контроллер, который обрабатывает выборку большего количества элементов, реализуется следующим образом. Обратите внимание, что в методе loadMore
выполняется запрос в хранилище, который загружает определенную страницу записей для модели.
App.EventsController = Ember.ArrayController.extend({
currentPage: 1,
canLoadMore: function() {
// can we load more entries? In this example only 10 pages are possible to fetch ...
return this.get('currentPage') < 10;
}.property('currentPage'),
loadMore: function() {
if (this.get('canLoadMore')) {
this.set('isLoading', true);
var page = this.incrementProperty('currentPage');
// findQuery triggers somehing like /events?page=6 and this
// will load more models of type App.Event into the store
this.get('store').findQuery(App.Event, { page: page });
} else {
this.set('isLoading', false);
}
}
});
Осталось только сначала установить content
контроллера на результат функции filter
, поэтому content
обновляется при загрузке новых моделей в магазин (что происходит из-за findQuery
в loadMore
контроллера). Кроме того, при вызове filter
добавляется хэш query
. Это гарантирует, что будет выполнен первоначальный запрос на сервер.
App.eventsController = App.EventsController.create({
content: []
});
var events = App.store.filter(App.Event, { page: 1 }, function(data) {
// show all events; return false if a specific model - for example a specific
// type of event - shall not be included
return true;
});
Ответ 3
Я пишу бесконечный плагин для разбивки на страницы для Ember на основе работы @pangratz.
Если у вас есть вопросы или улучшения, пожалуйста, пожалуйте любые проблемы.
Ответ 4
Я бы рекомендовал использовать Ember Infinity. Он поддерживает Ember от 1.10 до 2.0 +.. Он относительно прост в настройке. Вам нужно только изменить маршрут и шаблон.
Маршрут (Product
- пример модели):
import InfinityRoute from 'ember-infinity/mixins/route';
export default Ember.Route.extend(InfinityRoute, {
model() {
/* Load pages of the Product Model, starting from page 1, in groups of 12. */
return this.infinityModel('product', { perPage: 12, startingPage: 1 });
}
});
Шаблон:
{{#each model as |product|}}
...
{{/each}}
{{infinity-loader infinityModel=model}}
Когда компонент {{infinity-loader}}
становится видимым, он отправляет действие на ваш маршрут, поэтому он знает обновить массив модели новыми (извлеченными) записями.
Первый запрос будет отправлен по адресу:
/products?per_page=12&page=1
Таким образом, вам также необходимо подготовить свой API-интерфейс для обработки этих параметров запроса. Он, очевидно, настраивается, взгляните на раздел расширенного использования Readme.
Примечание
Оба с использованием ListView
(@commadelimited answer) и представления с ArrayController
(ответ @pangratz) устарели/удалены, поскольку версия Ember 2.0 является стабильной версией.