Эта статья является частью серии о MarionetteJS и Brunch.io. Хотя я стараюсь делать статьи как можно более абстрактными, чтобы они не слишком сильно зависели от предыдущих, я бы посоветовал вам прочитать все предыдущие статьи, поскольку я буду объяснять множество концепций, которые могут помочь вам лучше понять статьи.

"

Привет всем, надеюсь, у вас все в порядке. Извините за позднюю статью, я переехал в Лондон в начале этого месяца, и между новой работой и поиском нового дома, Рождеством и Новым годом у меня не было много времени, чтобы написать ее, но вот и мы: D

В прошлой статье мы рассказали о представлениях и их свойствах, таких как шаблоны и регионы, но мы говорили только об одном виде представления - Mn.View. Вы можете без проблем использовать его для всех ваших представлений по проекту, но иногда вы столкнетесь с некоторыми конкретными вариантами использования:

Что делать, если у вас есть Collection, и вы хотите визуализировать представление для каждого Model?

Вам нужно было бы сопоставить свою коллекцию и отрендерить View для каждой модели, верно? Хотя это не кажется таким уж проблематичным, это может быть, если вы попытаетесь добавить к нему какую-то причудливую логику, например, что, если коллекция пуста, и вы хотите отобразить для нее другое представление? Вы начинаете ставить определенные условия, которые могут не так красиво выглядеть в вашем коде.

Хорошо, но не волнуйтесь, Марионетка вас прикрыла: D

Помимо Mn.View, Marionette поставляется с еще тремя типами представлений: Mn.CollectionView, Mn.CompositeView и Mn.NextCollectionView, каждый из которых создан для конкретных случаев использования.

Mn.CollectionView

В предыдущей статье у нас было представление для рендеринга пользовательской информации с помощью шаблонов, регионов и пользовательского интерфейса, верно? Но источником данных для этого представления был Mn.Model, что означает, что представление пригодно только для отображения информации об одном пользователе. Но что, если у нас есть набор пользовательских моделей, и мы хотим визуализировать это представление для каждой из них?

Как мы подошли выше, нам нужно будет сопоставить коллекцию и визуализировать представление для каждой модели. Возможно, это не лучший подход, поскольку нам может потребоваться добавить к нему более причудливую логику.

Mn.CollectionView был создан для решения именно этой проблемы (шумиха!). В отличие от Mn.View, этот принимает Bb.Collection в качестве источника данных вместо Bb.Model и не имеет ни шаблона, ни пользовательского интерфейса, что имеет смысл, потому что это очень интересный способ визуализации нескольких представлений. для каждой модели в коллекции, и не столько для самого фактического вида.

Итак, возьмем следующий пример:

import UserView from './UserView'
const UserCollection = Bb.Collection({...})
const UserCollectionView = Mn.CollectionView.extend({
   collection: UserCollection,
   tagName: 'ul',
   className: 'user-list',
   childView: UserView
});

Точно так же мы получили список UserViews (по одному для каждой модели), отображаемых на экране. Ага, вот так!

Каждый раз, когда мы создаем представление, это представление будет заключено в div в DOM, чтобы изменить это поведение, мы можем использовать свойство tagName. В этом случае представление будет заключено в ul вместо div, что может иметь больше смысла, если вы пытаетесь отобразить список элементов.

Кроме того, вы можете захотеть дать определенное имя класса для этого представления, которое вы знаете для целей css и тому подобного. Для этого мы используем свойство className.

Примечание: вы можете использовать эти два свойства в любом типе просмотра, честно говоря, я просто забыл рассказать о них в последнем разделе: P

Теперь у нас есть свойство childView, в которое вы хотите поместить View, отвечающий за рендеринг каждой модели, в нашем случае UserView.

Внутренне Mn.CollectionView отобразит все модели внутри коллекции и отобразит вид, который мы указали для каждой из них. Это также делается в жизненном цикле onRender, как мы подходили до этого, это позволяет отображать представления за одну отрисовку, предотвращая снижение производительности за счет многократного взаимодействия с DOM.

ПОДОЖДИТЕ ПОДОЖДИТЕ! Итак, этот так называемый «CollectionView» хорош только для отображения моделей в коллекции и визуализации представлений для каждой из них? Это звучит точно так же, как создание реальной карты в коллекции, как вы сказали раньше, зачем тогда беспокоиться?

Действительно, основной смысл использования Mn.CollectionView - это действительно модели карт в коллекции и рендеринг представлений для каждой из них, но это только верхушка айсберга, теперь наступает действительно хорошая часть: D

EmptyView

Скажем, вы хотите отобразить представления для каждой модели в коллекции, приведенный выше пример будет работать, но вы должны кое-что запомнить, выборка коллекции является асинхронным процессом, поэтому к тому времени, когда вы визуализируете представление, коллекция все еще может быть пустой. Да, вы можете сделать так, чтобы представление отображалось только после успешной выборки коллекции, но в настоящее время никто этого не делает, потому что вы оставите пользователя с пустой и, вероятно, не отвечающей на запросы страницей.

Чтобы решить эту проблему, Mn.CollectionView предлагает способ отображать другое представление, когда ваша коллекция пуста. Это представление может быть обычным представлением, которое вы можете настроить, возможно, для отображения некоторых заполнителей или сообщения типа «Загрузка…», эта часть действительно зависит от вас.

import UserView from './UserView.js'
const UserCollection = Bb.Collection({...})
const EmptyView = Mn.View({
  initialize(){
    console.log('Loading...');
  }
});
const UserCollectionView = Mn.CollectionView.extend({
   ...
   childView: UserView,
   emptyView: EmptyView
});

Просто так Mn.CollectionView автоматически переключает просмотры в зависимости от длины вашей коллекции. Вы даже можете настроить собственное поведение для отображения пустого представления, скажем, вы хотите отображать его до тех пор, пока в вашей коллекции не будет как минимум 5 моделей:

...
const UserCollectionView = Mn.CollectionView.extend({
   ...
   emptyView: EmptyView,
   isEmpty(options){
      return this.collection.length < 5;
   }
});

Вы можете сделать это с помощью свойства isEmpty, таким образом, пустое представление будет отображаться до тех пор, пока в коллекции не будет не менее 5 моделей, после чего он автоматически переключится на дочернее представление.

Слушатели

Вся эта магия возможна, потому что Mn.CollectionView привязывается к паре Bb.Collection событий: add, remove и reset.

Каждый раз, когда вы запускаете одно из этих событий в коллекции, Mn.CollectionView творит чудеса!

Если вы активируете reset, Mn.CollectionView будет повторно отрисовывать себя автоматически, если вы активируете add или remove, Mn.CollectionView отобразит / удалит из DOM только определенное представление для этой модели. Это позволяет вам динамически управлять коллекцией и всегда иметь самую свежую информацию о DOM с минимальным влиянием на производительность и 0 дополнительных строк кода, хорошо, правда? : D

Также, если вы хотите повторно визуализировать весь Mn.CollectionView, не манипулируя коллекцией, вы можете использовать метод render: Mn.CollectionView.render()

Mn.CompositeView

Как мы узнали, Mn.CollectionView - это не столько само представление, у него нет собственного шаблона, поэтому он в основном контейнер для хранения других представлений, но иногда нам может понадобиться шаблон и назначить область этого шаблона для рендеринга дочернего представления. .

По сути, это Mn.CompositeView, расширенный тип Mn.CollectionView, который позволяет вам определять для него шаблон.

В отличие от View, который использует модель в качестве источника данных, или CollectionView, который использует коллекцию, Mn.CompositeView, являющийся сочетанием двух, может содержать как модель, так и коллекцию. Он использует модель для заполнения своего собственного шаблона и коллекцию для визуализации дочерних представлений в указанной области шаблона.

...
const UserCompositeView = Mn.UserCompositeView.extend({
   template: ...,
   model: ...,
   collection: ...,
   childView: ...,
   childViewContainer: ".childview-container"
});

Все используемые свойства уже известны, единственное, что нам нужно охватить, - это childViewContainer, поскольку название предполагает, что это просто свойство для хранения селектора jQuery для элемента в DOM, который будет использоваться для рендеринга дочерних представлений.

Свойства

Поскольку он является расширением Mn.CollectionView, все его свойства доступны по адресу Mn.CompositeView.

Слушатели

Те же слушатели из Mn.CollectionView присутствуют с таким же поведением, за исключением метода render, в этом случае, если вы вызовете render, будет повторно визуализирован весь Mn.CompositeView, включая его шаблон. Если вы хотите повторно отрендерить дочерние представления, вам нужно вызвать метод renderChildren

Mn.NextCollectionView

Хорошие разработчики Marionette работали над новой версией CollectionView, чтобы заменить старую. Эта версия имеет более простой поток и более последовательное поведение, что приводит к повышению производительности. Эта версия все еще находится на тестировании и, надеюсь, выйдет на Marionette v4, до тех пор вы можете прочитать о ней на https://medium.com/blog-marionettejs/next-collection-view-d335f5a9736a

Вот и все, ребята, надеюсь, теперь вы лучше понимаете, как работают Views в Marionette. Еще многое предстоит сделать для просмотров, но давайте оставим это для предварительного раздела позже. Надеюсь, эта статья была полезной, еще раз извиняюсь за задержку и, как всегда, увидимся, ребята, в следующий раз: D

Я добавлю на github простой проект, охватывающий то, что мы изучаем до сих пор, и буду добавлять его в каждой новой статье. Надеюсь, я буду готов на следующей неделе: D