Backbone.js: просмотр вложений через шаблоны
Возможно технически можно вставить точки зрения, используя шаблоны, что-то вроде этого:
<%= new PhotoCollectionView({model:new PhotoCollection(model.similarPhotos)}).render().el) %>
Я могу поместить все вещи в метод рендеринга, но шаблоны дают гораздо больше возможностей для гибкости и макета.
Я попробовал вышеупомянутый вариант, но все, что я получаю в результате на экране, - [HTMLDivElement]
.
Если я попытаюсь извлечь только HTML из него, используя jQuery HTML, я получаю его визуализацию, но оказывается, что узлы DOM, которые распечатываются, отличаются от тех, на которые ссылаются ссылки, потому что без взаимодействия с этими DOM-узлами невозможно использование экземпляра представления. Например, если в представлении я скажу $(this.el).hide()
, ничего не произойдет.
Каков правильный способ, если он есть?
Ответы
Ответ 1
Обычно я сначала представляю родительское представление. Затем я использую метод this.$('selector')
для поиска дочернего элемента, который я могу использовать как el дочернего представления.
Вот полный пример:
var ChildView = Backbone.View.extend({
//..
})
var ParentView = Backbone.View.extend({
template: _.template($('#parent-template').html()),
initialize: function() {
_.bindAll(this, 'render');
}
render: function() {
var child_view = new ChildView({ el: this.$('#child-el') }); //This refers to ParentView.
return this;
}
});
var v = new ParentView();
v.render();
Ответ 2
Принятый ответ имеет серьезный недостаток, который заключается в том, что ChildView будет повторно инициализироваться каждый раз, когда он отображается. Это означает, что вы потеряете состояние и, возможно, придется повторно инициализировать сложные представления для каждого рендеринга.
Я написал блог об этом здесь: http://codehustler.org/blog/rendering-nested-views-backbone-js/
Подводя итог, я бы предложил использовать что-то вроде этого:
var BaseView = Backbone.View.extend({
// Other code here...
renderNested: function( view, selector ) {
var $element = ( selector instanceof $ ) ? selector : this.$el.find( selector );
view.setElement( $element ).render();
}
});
var CustomView = BaseView.extend({
// Other code here...
render: function() {
this.$el.html( this.template() );
this.renderNested( this.nestedView, ".selector" );
return this;
}
});
Вам не нужно расширять представление Backbone, если вы этого не хотите, метод renderNested можно поместить куда угодно.
С помощью кода выше вы можете инициализировать ChildView в методе инициализации, а затем просто визуализировать его при вызове render().
Ответ 3
Ознакомьтесь с Backbone.Subviews mixin. Это минималистский mixin, созданный для управления вложенными представлениями и не повторно инициализирующий дочерние представления каждый раз, когда выдается родительский.
Ответ 4
Я не знаю, что внутри самого шаблона, но я делал это с таблицами и списками раньше. Во внешнем шаблоне просто закройте заглушку:
<script type="text/template" id="table-template">
<table>
<thead>
<th>Column 1</th>
</thead>
<tbody>
</tbody>
</table>
</script>
и для отдельных элементов: <% = field1% >
то в вашем методе рендеринга просто отрисуйте отдельные элементы и добавьте их в элемент tbody...
Ответ 5
Решение инициализировать новый объект при каждом рендеринге кажется мне очень неэффективным.
Особенно это:
render: function() {
var child_view = new ChildView({ el: this.$('#child-el') }); //This refers to ParentView.
return this;
}
В идеале рендеринг родителя должен быть чем-то вроде
render: function() {
this.$el.html(this.template());
this.childView1.render();
this.childView2.render();
}
И создание детей должно происходить только при инициализации родителя:
initialize: function() {
this.childView1 = new ChildView1(selector1);
this.childView2 = new ChildView2(selector2);
}
проблема заключается в том, что перед отображением родительского шаблона мы не имеем selector1 и selector2. Здесь я застреваю прямо сейчас:)