Ответ 1
Это отличный вопрос. Магистраль велика из-за отсутствия предположений, которые она делает, но это означает, что вы должны (решать, как) реализовать такие вещи, как это самостоятельно. Изучив мои собственные вещи, я обнаружил, что я (вроде) использую сочетание сценария 1 и сценария 2. Я не думаю, что существует 4-й магический сценарий, потому что, достаточно просто, все, что вы делаете в сценариях 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
, а также несколько дополнительных div, один из которых, #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
, только слушая изменения модели, о которых он заботится.
Надеюсь, это немного помогло, пожалуйста, дайте мне знать, если что-то вводит в заблуждение или недостаточно подробно описано.