У меня есть настройка вложенного просмотра, которая может немного углубиться в мое приложение. Я мог бы подумать о множестве способов инициализации, рендеринга и добавления подвидов, но мне интересно, какова общая практика.
Вот пара, о которой я подумал:
initialize : function () {
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template());
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Плюсы: вам не нужно беспокоиться о поддержании правильного порядка DOM с добавлением. Представления инициализируются на ранней стадии, поэтому в функции рендеринга не так много всего сразу.
Минусы: Вы вынуждены повторно делегировать события (), что может быть дорогостоящим? Функция рендеринга родительского представления захламлена всем рендерингом подвидов, который должен произойти? У вас нет возможности установить tagName
элементы, поэтому шаблон должен поддерживать правильные имена тегов.
По-другому:
initialize : function () {
},
render : function () {
this.$el.empty();
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
this.$el.append(this.subView1.render().el, this.subView2.render().el);
}
Плюсы: вам не нужно повторно делегировать события. Вам не нужен шаблон, который просто содержит пустые заполнители, и ваши tagName возвращаются к определению представлением.
Минусы: теперь вы должны убедиться, что все добавлено в правильном порядке. Визуализация родительского представления по-прежнему загромождена визуализацией подпредставления.
С onRender
событием:
initialize : function () {
this.on('render', this.onRender);
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Плюсы: логика подпредставления теперь отделена от render()
метода представления.
С onRender
событием:
initialize : function () {
this.on('render', this.onRender);
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1 = new Subview();
this.subView2 = new Subview();
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Я как бы смешал и сопоставил кучу разных практик во всех этих примерах (извините за это), но какие из них вы бы сохранили или добавили? а что бы ты не делал?
Краткое изложение практики:
- Создавать подпункты в
initialize
или вrender
? - Выполнить всю логику рендеринга подвидов в
render
или вonRender
? - Использовать
setElement
илиappend/appendTo
?
источник
close
метод и объект,onClose
который очищает детей, но мне просто любопытно, как создать их экземпляры и отрендерить их в первую очередь.delete
в JS отличаетсяdelete
от C ++. Если вы спросите меня, это ключевое слово с очень неудачным названием.Ответы:
Я обычно видел / использовал несколько разных решений:
Решение 1
Это похоже на ваш первый пример, с некоторыми изменениями:
render()
называется ПОСЛЕ того, как элемент внутреннего представления был помещен в DOM, что полезно, еслиrender()
метод вашего внутреннего представления размещает / изменяет размеры на странице в зависимости от положения / размера других элементов (что, на мой взгляд, является распространенным случаем использования)Решение 2
Решение 2 может выглядеть чище, но оно вызвало некоторые странные вещи в моем опыте и отрицательно сказалось на производительности.
Я обычно использую Решение 1 по нескольким причинам:
render()
методеИмейте в виду, что если вы инициализируете
new View()
каждый раз, когдаrender()
вызывается, эта инициализация все равно будет вызыватьсяdelegateEvents()
. Так что это не обязательно должно быть «мошенником», как вы выразились.источник
Это постоянная проблема с Backbone, и, по моему опыту, на этот вопрос нет удовлетворительного ответа. Я разделяю ваше разочарование, тем более что рекомендаций так мало, несмотря на то, насколько распространен этот вариант использования. Тем не менее, я обычно иду с чем-то похожим на ваш второй пример.
Прежде всего, я бы отказался от всего, что требует от вас повторного делегирования событий. Модель представления Backbone, управляемая событиями, является одним из наиболее важных ее компонентов, и потеря этой функциональности просто потому, что ваше приложение нетривиально, оставит дурной привкус во рту любого программиста. Так что поцарапайте номер один.
Что касается вашего третьего примера, я думаю, что это всего лишь конец обычной практики рендеринга, и он не добавляет особого смысла. Возможно, если вы выполняете фактическое инициирование события (т.е. не надуманное «
onRender
» событие), стоило бы просто привязать эти события кrender
себе. Если вы обнаружите, чтоrender
становитесь громоздкими и сложными, у вас слишком мало подпредставлений.Вернемся к вашему второму примеру, который, вероятно, является меньшим из трех зол. Вот пример кода, взятого из Recipes With Backbone , найденного на странице 42 моего PDF-издания:
Это лишь немного более сложная настройка, чем ваш второй пример: они определяют набор функций
addAll
иaddOne
, которые выполняют грязную работу. Я думаю, что этот подход работоспособен (и я, конечно, использую его); но это все еще оставляет странное послевкусие. (Простите за все эти языковые метафоры.)К вашему мнению, добавление в правильном порядке: если вы строго добавляете, конечно, это ограничение. Но обязательно учтите все возможные схемы шаблонов. Возможно, вам действительно нужен элемент-заполнитель (например, пустой
div
илиul
), а затем вы можетеreplaceWith
создать новый (DOM) элемент, содержащий соответствующие подвиды. Добавление не является единственным решением, и вы, конечно, можете обойти проблему заказа, если вы так сильно заботитесь о ней, но я думаю, у вас возникнут проблемы с дизайном, если вас это не устраивает. Помните, у подпредставлений могут быть подпредставления, и они должны, если это уместно. Таким образом, у вас есть довольно древовидная структура, что довольно приятно: каждое подпредставление добавляет все свои подпредставления по порядку, прежде чем родительское представление добавит другое, и так далее.К сожалению, решение №2, вероятно, лучшее, на что вы можете надеяться, используя готовую Backbone. Если вы заинтересованы в проверке сторонних библиотек, то одна из них, которую я изучил (но на самом деле у нее еще не было времени поиграть) - это Backbone.LayoutManager , который, кажется, имеет более полезный метод добавления подпредставлений. Однако даже у них недавно были дебаты по аналогичным вопросам.
источник
model.bind('remove', view.remove);
разве вы не должны просто сделать это в функции инициализации встречи, чтобы разделить их?Удивлен, это еще не было упомянуто, но я серьезно рассмотрю возможность использования марионетки .
Он навязывает немного больше структуры для Backbone приложений, включая типы зрения конкретных (
ListView
,ItemView
,Region
иLayout
), добавляя собственныеController
S и многое другое.Вот проект на Github и отличное руководство Адди Османи в книге Backbone Fundamentals, которое поможет вам начать работу.
источник
У меня есть, как мне кажется, довольно комплексное решение этой проблемы. Это позволяет модели в коллекции изменяться, и визуализируется только ее представление (а не вся коллекция). Он также обрабатывает удаление представлений зомби с помощью методов close ().
Использование:
источник
Проверьте этот миксин для создания и рендеринга подпредставлений:
https://github.com/rotundasoftware/backbone.subviews
Это минималистское решение, которое решает многие проблемы, обсуждаемые в этом потоке, включая порядок рендеринга, отсутствие необходимости повторного делегирования событий и т. Д. Обратите внимание на случай представления коллекции (где каждая модель в коллекции представлена одним subview) - это отдельная тема. Лучшее общее решение, которое мне известно в этом случае, - это CollectionView in Marionette .
источник
Мне не очень нравится ни одно из вышеперечисленных решений. Я предпочитаю эту конфигурацию перед каждым представлением, когда нужно вручную выполнять работу в методе рендеринга.
views
может быть функцией или объектом, возвращающим объект определений представления.remove
вызывается родительский объект,.remove
должны вызываться вложенные дочерние элементы от самого низкого порядка (вплоть до представлений sub-sub-sub)Вот пример:
источник
Магистраль была специально построена таким образом, чтобы не было «общей» практики в отношении этого и многих других вопросов. Предполагается, что он будет как можно более непрочным. Теоретически вам даже не нужно использовать шаблоны с Backbone. Вы можете использовать javascript / jquery в
render
функции представления, чтобы вручную изменить все данные в представлении. Чтобы сделать его более экстремальным, вам даже не нужна одна конкретнаяrender
функция. Вы можете вызвать функцию,renderFirstName
которая обновляет имя в dom иrenderLastName
обновляет фамилию в dom. Если вы воспользуетесь этим подходом, это будет намного лучше с точки зрения производительности, и вам больше никогда не придется вручную делегировать события. Код также будет иметь смысл для того, кто его читает (хотя это будет более длинный / беспорядочный код).Однако, как правило, нет недостатка в использовании шаблонов и в простом разрушении и перестройке всего представления и его подпредставлений при каждом вызове рендеринга, поскольку спрашивающему даже не приходило в голову сделать что-то иначе. Вот что делает большинство людей практически в любой ситуации, с которой они сталкиваются. И поэтому самоуверенные фреймворки просто делают это поведением по умолчанию.
источник
Вы также можете вставить визуализированные подвиды как переменные в основной шаблон как переменные.
сначала визуализируйте подвиды и преобразуйте их в HTML следующим образом:
var subview1 = $(subview1.render.el).html(); var subview2 = $(subview2.render.el).html();
(таким образом, вы также можете динамически объединять строки, как
subview1 + subview2
при использовании в циклах), а затем передавать его в главный шаблон, который выглядит следующим образом:... some header stuff ... <%= sub1 %> <%= sub2 %> ... some footer stuff ...
и, наконец, введите его так:
this.$el.html(_.template(MasterTemplate, { sub1: subview1, sub2: subview2 } ));
Относительно событий в подпредставлениях. Скорее всего, они должны быть связаны в родительском (masterView) при таком подходе, а не в подпредставлениях.
источник
Мне нравится использовать следующий подход, который также обеспечивает правильное удаление дочерних представлений. Вот пример из книги Адди Османи.
источник
Нет необходимости повторно делегировать события, так как это дорого. Увидеть ниже:
источник