Marionette.CollectionView
Блок кода CollectionView будет перебирать все модели в указанной коллекции, рендерить каждую из них, используя указанный childView, затем добавлять результат рендеринга представления дочернего элемента (el) к представлению коллекции (el). По умолчанию CollectionView сохраняет порядок отсортированной коллекции в DOM. Это поведение можно отключить, указав {sort: false} при инициализации.
CollectionView имеет базовые функции, предоставляемые миксином View.
Индекс документации
-
childViewпредставления CollectionView -
emptyViewпредставления CollectionView -
renderпредставления CollectionView destroyпредставления CollectionView- События
-
Рендеринг
CollectionView - Расширенное использование CollectionView
childView представления CollectionView
Укажите childView в определении представления коллекции. Это должно быть определение класса представления Backbone, а не экземпляр. Это может быть любое Backbone.View или быть производным от Marionette.View.
var Mn = require('backbone.marionette');
var MyChildView = Mn.View.extend({});
Mn.CollectionView.extend({
childView: MyChildView
});
Дочерние представления должны быть определены до того, как они будут использованы в атрибуте childView в определении представления коллекции.
В качестве альтернативы, вы можете указать childView в опциях конструктора:
var Mn = require('backbone.marionette');
var MyCollectionView = Mn.CollectionView.extend({...});
new MyCollectionView({
childView: MyChildView
});
Если вы не укажете childView, будет выброшено исключение, требующее указать childView.
Вы также можете определить childView как функцию. В этом формате значение, возвращаемое этой функцией, будет классом ChildView, который будет создан, когда необходимо первоначально рендерить Model. Эта функция также позволяет настраивать параметры для каждого Model ChildViews.
var Bb = require('backbone');
var Mn = require('backbone.marionette');
var FooBar = Bb.Model.extend({
defaults: {
isFoo: false
}
});
var FooView = Mn.View.extend({
template: '#foo-template'
});
var BarView = Mn.View.extend({
template: '#bar-template'
});
var MyCollectionView = Mn.CollectionView.extend({
collection: new Bb.Collection(),
childView: function(item) {
// Choose which view class to render,
// depending on the properties of the item model
if (item.get('isFoo')) {
return FooView;
}
else {
return BarView;
}
}
});
var collectionView = new MyCollectionView();
var foo = new FooBar({
isFoo: true
});
var bar = new FooBar({
isFoo: false
});
// Renders a FooView
collectionView.collection.add(foo);
// Renders a BarView
collectionView.collection.add(bar);
childViewOptions представления CollectionView
Возможны сценарии, когда вам нужно передать данные из родительского представления коллекции в каждый экземпляр дочернего представления. Для этого укажите определение childViewOptions в вашем представлении коллекции в виде объекта. Это будет передано в конструктор вашего дочернего представления в качестве части options.
var Mn = require('backbone.marionette');
var ChildView = Mn.View.extend({
initialize: function(options) {
console.log(options.foo); // => "bar"
}
});
var CollectionView = Mn.CollectionView.extend({
childView: ChildView,
childViewOptions: {
foo: 'bar'
}
});
Вы также можете указать childViewOptions как функцию, если вам нужно рассчитать значения во время выполнения. Модель будет передана в функцию, если вам нужно получить к ней доступ при расчете childViewOptions. Функция должна вернуть объект, а атрибуты объекта будут скопированы в параметры экземпляра childView.
var Mn = require('backbone.marionette');
var CollectionView = Mn.CollectionView.extend({
childViewOptions: function(model, index) {
// do some calculations based on the model
return {
foo: 'bar',
childIndex: index
}
}
});
emptyView представления CollectionView
Когда коллекция не имеет дочерних элементов, и вам нужно рендерить представление, отличное от списка дочерних представлений, вы можете указать атрибут emptyView в представлении вашей коллекции. emptyView , как и childView, также может быть передан в качестве параметра при создании или быть функцией, которая возвращает emptyView.
var Mn = require('backbone.marionette');
var MyEmptyView = Mn.View.extend({
template: _.template('Nothing to display.')
});
var MyCollectionView = Mn.CollectionView.extend({
// ...
emptyView: MyEmptyView
});
emptyViewOptions представления CollectionView
Аналогично childView и childViewOptions, существует свойство emptyViewOptions, которое будет передано в конструктор emptyView. Оно может быть предоставлено как объект или как функция.
Если emptyViewOptions не указаны, CollectionView по умолчанию передаст childViewOptions в emptyView.
var Mn = require('backbone.marionette');
var EmptyView = Mn.View({
initialize: function(options){
console.log(options.foo); // => "bar"
}
});
var CollectionView = Mn.CollectionView({
emptyView: EmptyView,
emptyViewOptions: {
foo: 'bar'
}
});
isEmpty представления CollectionView
Если вы хотите контролировать, когда рендерится пустое представление, вы можете переопределить isEmpty:
var Mn = require('backbone.marionette');
var MyCollectionView = Mn.CollectionView.extend({
isEmpty: function(options) {
// some logic to calculate if the view should be rendered as empty
return this.collection.length < 2;
}
});
render представления CollectionView
Метод render представления коллекции отвечает за рендеринг всей коллекции. Он перебирает каждый дочерний элемент в коллекции и рендерит их по отдельности как childView. По умолчанию, когда представление collectionView полностью рендерится, изменения в DOM буферизуются для одного изменения attachBuffer DOM.
var Mn = require('backbone.marionette');
var MyCollectionView = Mn.CollectionView.extend({...});
// all of the children views will now be rendered.
new MyCollectionView().render();
Дополнительную информацию о технике рендеринга см. в разделе: Рендеринг CollectionView.
Автоматический рендеринг
После первоначального рендеринга представление коллекции подключается к событиям add, remove и reset коллекции, которая указана.
Когда коллекция для представления "сбрасывается", представление вызывает render на себе и повторно рендерит всю коллекцию.
Когда в коллекцию добавляется модель, представление коллекции рендерит эту модель в коллекцию дочерних представлений.
Когда модель удаляется из коллекции (или уничтожается/удаляется), представление коллекции уничтожит и удалит дочернее представление этой модели.
Когда коллекция для представления сортируется, представление автоматически сортирует свои дочерние представления. Если опция reorderOnSort установлена, оно попытается переупорядочить DOM без полного перерендеринга, иначе перерендерит, если порядок изменился. Обратите внимание, что если вы применяете фильтр к представлению коллекции, и отфильтрованные представления изменяются во время сортировки, оно всегда будет перерендериться.
var Bb = require('backbone');
var Mn = require('backbone.marionette');
var collection = new Bb.Collection();
var MyChildView = Mn.View.extend({
template: _.noop
});
var MyCollectionView = Mn.CollectionView.extend({
childView: MyChildView,
collection: collection,
});
var myCollectionView = new MyCollectionView();
// Collection view will not re-render as it has not been rendered
collection.reset([{foo: 'foo'}]);
myCollectionView.render();
// Collection view will re-render displaying the new model
collection.reset([{foo: 'bar'}]);
Повторный рендеринг представления CollectionView
Если вам нужно повторно рендерить всю коллекцию, вы можете вызвать метод view.render. Этот метод позаботится об уничтожении всех дочерних представлений, которые ранее могли быть открыты.
attachHtml представления CollectionView
По умолчанию представление коллекции добавляет HTML каждого дочернего представления в буфер элемента и затем вызывает метод jQuery .append один раз в конце, чтобы переместить HTML в элемент el представления коллекции.
Вы можете переопределить это, указав метод attachHtml в определении вашего представления. Этот метод принимает три параметра и не имеет значения возврата.
var Mn = require('backbone.marionette');
Mn.CollectionView.extend({
// The default implementation:
attachHtml: function(collectionView, childView, index){
if (collectionView._isBuffering) {
// buffering happens on reset events and initial renders
// in order to reduce the number of inserts into the
// document, which are expensive.
collectionView._bufferedChildren.splice(index, 0, childView);
} else {
// If we've already rendered the main collection, append
// the new child into the correct order if we need to. Otherwise
// append to the end.
if (!collectionView._insertBefore(childView, index)){
collectionView._insertAfter(childView);
}
}
}
});
Первый параметр - экземпляр представления коллекции, который получит HTML из второго параметра, текущего экземпляра дочернего представления.
Третий параметр, index, - индекс модели, который представляет этот экземпляр childView, в коллекции, из которой модель пришла. Это полезно для понимания порядка сортировки дочерних элементов.
Переопределения attachHtml , которые не учитывают буфер элемента, будут работать нормально, но не будут использовать увеличение производительности в 60 раз, которое обеспечивает буфер.
attachBuffer представления CollectionView
При переопределении attachHtml может потребоваться переопределить способ присоединения буфера. Этот метод получает два параметра. collectionView и HTML-буфер всех дочерних представлений.
var Mn = require('backbone.marionette');
var MyCollectionView = Mn.CollectionView.extend({
// The default implementation:
// Called after all children have been appended into the buffer
attachBuffer: function(collectionView, buffer) {
collectionView.$el.append(buffer);
}
});
destroy представления CollectionView
CollectionView реализует метод destroy, который автоматически уничтожает дочерние элементы и очищает слушателей.
var Bb = require('backbone');
var Mn = require('backbone.marionette');
var MyChildView = Mn.View.extend({
template: _.template('ChildView'),
onDestroy: function() {
console.log('I will get destroyed');
}
})
var myCollectionView = new Mn.CollectionView({
childView: MyChildView,
collection: new Bb.Collection([{ id: 1 }])
});
myCollectionView.render();
myCollectionView.destroy(); // logs "I will get destroyed"
События
CollectionView, как и View, могут генерировать и реагировать на события, происходящие в течение их жизненного цикла. В Документации по событиям содержится полная документация по настройке и обработке событий в представлениях.
Прослушивание событий дочерних элементов
Представление коллекции может отслеживать и реагировать на события любых своих дочерних элементов, используя childViewEvents и childViewTriggers. Кроме того, когда дочернее представление генерирует событие, это событие поднимается на один уровень к родительскому представлению коллекции. Пример:
var Mn = require('backbone.marionette');
var Item = Mn.View.extend({
tagName: 'li',
triggers: {
'click a': 'select:item'
}
});
var Collection = Mn.CollectionView.extend({
tagName: 'ul',
onChildviewSelectItem: function(childView) {
console.log('item selected: ' + childView.model.id);
}
});
Событие получит префикс childview: перед применением логики связывания с магическим методом. Подробнее см. в документации по событиям дочерних представлений.
События жизненного цикла
CollectionView содержит свои собственные события жизненного цикла, помимо обычных событий жизненного цикла View. Более подробную информацию о них и о том, как их использовать, см. в Документации по событиям жизненного цикла CollectionView
Рендеринг CollectionView
Marionette 3 устарела (для удаления в v4) CompositeView, в пользу более гибкого рендеринга View и CollectionView. Этот раздел охватывает наиболее распространенные варианты использования CollectionView и как заменить CompositeView.
Рендеринг списков
Списки, возможно, являются простейшим использованием CollectionView — просто задайте опцию childView:
var Bb = require('backbone');
var Mn = require('backbone.marionette');
var ListItemView = Mn.View.extend({
tagName: 'li',
template: '#list-item-text'
});
var ListView = Mn.CollectionView.extend({
tagName: 'ul',
className: 'list-unstyled',
childView: ListItemView
});
var list = new Bb.Collection([
{id: 1, text: 'My text'},
{id: 2, text: 'Another Item'}
]);
var listView = new ListView({
collection: list
});
listview.render();
С шаблоном:
<%- text %>
Это отобразит следующее:
<ul class="list-unstyled">
<li>My text</li>
<li>Another Item</li>
</ul>
Отображение таблиц
Marionette 3 внес существенное улучшение в View для возможности реализации таблиц, используя только View и CollectionView. В этом разделе будет продемонстрировано, как создать таблицу в Marionette 3, а также эквивалент в Marionette 2, используя CompositeView.
Таблицы с использованием Marionette 2
Примечание Следующий код устарел и предназначен только для демонстрационных целей
Для создания таблицы в Marionette 2 требуется CompositeView , который мы создадим так:
var Bb = require('backbone');
var Mn = require('backbone.marionette');
var RowView = Mn.LayoutView.extend({
tagName: 'tr',
template: '#table-row'
});
var TableView = Mn.CompositeView.extend({
tagName: 'table',
className: 'table table-hover',
template: '#table',
childView: RowView,
childViewContainer: 'tbody'
});
var list = new Bb.Collection([
{id: 1, text: 'My text'},
{id: 2, text: 'Another Item'}
]);
var myTable = new TableView({
collection: list
});
myTable.render();
Учитывая следующие #table и #table-row шаблоны:
<thead>
<tr>
<th>ID</th>
<th>Body</th>
</tr>
</thead>
<tbody></tbody>
<td><%- id %></td>
<td><%- text %></td>
Что отобразит следующее:
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>Body</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>My text</td>
</tr>
<tr>
<td>2</td>
<td>Another Item</td>
</tr>
</tbody>
</table>
### Серьезным недостатком этого метода было то, что невозможно было добавить дополнительные области внутри CompositeView - если элемент заголовка необходимо было перерисовать на основе ввода пользователя, то нужно было перерисовать всю таблицу или манипулировать DOM с помощью ui элементов.
Для решения этой проблемы Marionette 3 улучшает View для возможности создания таблиц без CompositeView.
Таблицы с использованием Marionette 3
Marionette 3 больше не использует CompositeView. Теперь мы создаем таблицы, используя View и regions. Следующий код отобразит ту же таблицу, что и в Marionette 2:
var Bb = require('backbone');
var Mn = require('backbone.marionette');
var RowView = Mn.View.extend({
tagName: 'tr',
template: '#row-template'
});
var TableBody = Mn.CollectionView.extend({
tagName: 'tbody',
childView: RowView
});
var TableView = Mn.View.extend({
tagName: 'table',
className: 'table table-hover',
template: '#table',
regions: {
body: {
el: 'tbody',
replaceElement: true
}
},
onRender: function() {
this.showChildView('body', new TableBody({
collection: this.collection
}));
}
});
var list = new Bb.Collection([
{id: 1, text: 'My text'},
{id: 2, text: 'Another Item'}
]);
var myTable = new TableView({
collection: list
});
myTable.render();
В этом примере мы можем оставить шаблоны без изменений. Основное преимущество этого стиля заключается в том, что мы можем создать область в любой части TableView а также в RowView и рассматривать её как любой независимый виджет.
Отображение деревьев
Структуры деревьев — очень полезные макеты для многократного вложения данных одного типа. Примером является проводник файлов Windows Explorer.
Деревья в Marionette 2
var Bb = require('backbone');
var Mn = require('backbone.marionette');
var TreeView = Mn.CompositeView.extend({
tagName: 'ul',
template: '#tree-template'
});
var TreeRoot = Mn.CollectionView.extend({
tagName: 'ul',
childView: TreeView
});
var tree = new Bb.Collection([
{
id: 5,
nodes: [
{id: 9, nodes: []},
{id: 1, nodes: [...]}
],
},
{
id: 12,
nodes: []
}
]);
new TreeRoot({
collection: tree
});
В Marionette 2 CompositeView по умолчанию устанавливает childView на себя. Хотя это хорошо для построения древовидных структур, такое поведение изменилось в Marionette 3 с введением более универсального представления.
Деревья в Marionette 3
Как и в таблицах, деревья в Marionette 3 требуют от нас комбинировать View и CollectionView для явного построения дерева более явным образом, чем неявная версия, предоставляемая Marionette 2.
var Bb = require('backbone');
var Mn = require('backbone.marionette');
var TreeNode = Mn.View.extend({
tagName: 'li',
template: '#tree-template',
regions: {
tree: {
el: 'ul',
replaceElement: true
}
},
onRender: function() {
var nodes = this.model.get('nodes');
//show child nodes if they are present
if (nodes.length) {
var treeView = new TreeView({
collection: new Bb.Collection(nodes)
});
this.showChildView('tree', treeView);
}
}
});
var TreeView = Mn.CollectionView.extend({
tagName: 'ul',
childView: TreeNode
});
var tree = new Bb.Collection([
{
id: 5,
nodes: [
{id: 9, nodes: []},
{id: 1, nodes: [...]}
],
},
{
id: 12,
nodes: []
}
]);
new TreeView({
collection: tree
});
Этот более явный стиль предоставляет нам два основных преимущества:
- Меньше ошибок — теперь невозможно случайно создать древовидную структуру
- Больше областей для подключения различных представлений, чего невозможно добиться с
CompositeView
Расширенное использование CollectionView
Для получения подробной информации о фильтрации, сортировке или управлении CollectionView см. Расширенное использование CollectionView
Управление потомками
CollectionView может хранить и управлять своими дочерними представлениями. Это позволяет легко получить доступ к представлениям внутри представления коллекции, перебрать их, найти их по заданному индексатору, такому как модель или коллекция представления, и многое другое. Дополнительная информация...
Фильтрация
CollectionView позволяет настроить опцию filter , если вы хотите предотвратить отображение некоторых моделей базовых collection в качестве дочерних представлений. Дополнительная информация...
Сортировка
По умолчанию CollectionView будет поддерживать порядок отсортированной коллекции в DOM. Дополнительная информация...
© 2017 Muted Solutions, LLC
Licensed under the MIT License.
https://marionettejs.com/docs/v3.5.1/marionette.collectionview.html