Это большой вопрос. Магистраль великолепна из-за отсутствия допущений, которые она делает, но это означает, что вы должны (решить, как) реализовать подобные вещи самостоятельно. Просматривая свои собственные материалы, я обнаружил, что я (вроде) использую сочетание сценария 1 и сценария 2. Я не думаю, что существует четвертый магический сценарий, потому что достаточно просто все, что вы делаете в сценарии 1 и 2, должно быть сделано.
Я думаю, что было бы проще объяснить на примере, как мне нравится справляться с этим. Скажем, у меня есть эта простая страница, разбитая на указанные виды:
Скажем, HTML после рендеринга выглядит примерно так:
<div id="parent">
<div id="name">Person: Kevin Peel</div>
<div id="info">
First name: <span class="first_name">Kevin</span><br />
Last name: <span class="last_name">Peel</span><br />
</div>
<div>Phone Numbers:</div>
<div id="phone_numbers">
<div>#1: 123-456-7890</div>
<div>#2: 456-789-0123</div>
</div>
</div>
Надеюсь, это довольно очевидно, как HTML совпадает с диаграммой.
ParentView
Имеет 2 дочерние представления, InfoView
и PhoneListView
, а также несколько дополнительных дивы, один из которых, #name
, должен быть установлен в какой - то момент. PhoneListView
содержит собственные дочерние представления, массив PhoneView
записей.
Итак, к вашему актуальному вопросу. Я занимаюсь инициализацией и рендерингом по-разному в зависимости от типа представления. Я делю свои взгляды на два типа: Parent
взгляды и Child
взгляды.
Разница между ними проста: Parent
представления содержат дочерние представления, а Child
представления - нет. Так что в моем примере, ParentView
и PhoneListView
являются Parent
мнением, в то время как InfoView
и PhoneView
записи являются Child
взглядами.
Как я уже упоминал ранее, самая большая разница между этими двумя категориями заключается в том, что им разрешено отображать. В идеальном мире я хочу, чтобы Parent
представления отображались только один раз. Их дочерние представления должны обрабатывать любой повторный рендеринг при изменении модели. Child
виды, с другой стороны, я разрешаю перерисовывать в любое время, когда им нужно, поскольку у них нет других представлений, полагающихся на них.
Чуть более подробно, для Parent
представлений мне нравится, что мои initialize
функции выполняют несколько вещей:
- Инициализировать мой собственный взгляд
- Предоставить мой собственный взгляд
- Создайте и инициализируйте любые дочерние представления.
- Назначьте каждому дочернему виду элемент в моем представлении (например
InfoView
, будет назначен #info
).
Шаг 1 довольно понятен.
Шаг 2, рендеринг, сделан таким образом, что любые элементы, на которые полагаются дочерние представления, уже существуют, прежде чем я попытаюсь назначить их. Делая это, я знаю, что все дочерние events
элементы будут правильно установлены, и я могу перерисовывать их блоки столько раз, сколько захочу, не беспокоясь о необходимости повторного делегирования. На самом деле я не вижу render
здесь никаких детских взглядов, я позволяю им делать это в рамках их собственных initialization
.
Шаги 3 и 4 фактически обрабатываются в то же время, что и я, el
при создании дочернего представления. Мне нравится передавать элемент здесь, так как я считаю, что родитель должен определить, где, по его собственному мнению, ребенку разрешено размещать его содержимое.
Для рендеринга я стараюсь сделать его довольно простым для Parent
представлений. Я хочу, чтобы render
функция не делала ничего, кроме визуализации родительского представления. Без делегирования событий, без представления дочерних представлений, ничего. Просто простой рендер.
Иногда это не всегда работает, хотя. Например, в моем примере выше, #name
элемент должен будет обновляться каждый раз, когда меняется имя в модели. Тем не менее, этот блок является частью ParentView
шаблона и не обрабатывается специальным Child
представлением, поэтому я работаю над этим. Я создам какую-то subRender
функцию, которая только заменяет содержимое #name
элемента и не должна уничтожать весь #parent
элемент. Это может показаться хаком, но я действительно обнаружил, что это работает лучше, чем беспокоиться о повторном рендеринге всего DOM и повторного присоединения элементов и тому подобного. Если бы я действительно хотел сделать его чистым, я бы создал новое Child
представление (похожее на InfoView
), которое будет обрабатывать #name
блок.
Теперь для Child
представлений initialization
это очень похоже на Parent
представления, только без создания каких-либо дальнейших Child
представлений. Так:
- Инициализировать мой взгляд
- Настройка связывает прослушивание любых изменений в модели, которая мне нужна
- Отдай мой взгляд
Child
Просмотр рендеринга также очень прост, просто отрендерите и установите содержимое моего el
. Опять же, не возиться с делегацией или что-то в этом роде.
Вот пример кода того, как ParentView
может выглядеть мой :
var ParentView = Backbone.View.extend({
el: "#parent",
initialize: function() {
// Step 1, (init) I want to know anytime the name changes
this.model.bind("change:first_name", this.subRender, this);
this.model.bind("change:last_name", this.subRender, this);
// Step 2, render my own view
this.render();
// Step 3/4, create the children and assign elements
this.infoView = new InfoView({el: "#info", model: this.model});
this.phoneListView = new PhoneListView({el: "#phone_numbers", model: this.model});
},
render: function() {
// Render my template
this.$el.html(this.template());
// Render the name
this.subRender();
},
subRender: function() {
// Set our name block and only our name block
$("#name").html("Person: " + this.model.first_name + " " + this.model.last_name);
}
});
Вы можете увидеть мою реализацию subRender
здесь. При наличии изменений , связанных с subRender
вместо того render
, я не должен беспокоиться о палить и восстановление всего блока.
Вот пример кода для InfoView
блока:
var InfoView = Backbone.View.extend({
initialize: function() {
// I want to re-render on changes
this.model.bind("change", this.render, this);
// Render
this.render();
},
render: function() {
// Just render my template
this.$el.html(this.template());
}
});
Связи являются важной частью здесь. Привязываясь к моей модели, мне никогда не придется беспокоиться о том, чтобы позвонить render
мне вручную . Если модель изменится, этот блок будет перерисован сам, не влияя на другие виды.
Это PhoneListView
будет аналогично тому ParentView
, что вам просто понадобится немного больше логики в ваших функциях initialization
и render
функциях для обработки коллекций. То, как вы обрабатываете коллекцию, действительно зависит от вас, но вам, по крайней мере, нужно будет слушать события коллекции и решать, как вы хотите визуализировать (добавить / удалить или просто заново визуализировать весь блок). Лично мне нравится добавлять новые виды и удалять старые, а не заново отображать весь вид.
PhoneView
Будет почти идентичен InfoView
, только прислушиваясь к модели изменений , которые она заботится о.
Надеюсь, это немного помогло, пожалуйста, дайте мне знать, если что-то сбивает с толку или недостаточно подробно.