3

Поскольку Backbone.js довольно гибкий, мне интересно, как лучше всего подходить к определенным вещам. Здесь мне интересно, должен ли я создавать представления моего приложения так, чтобы «.render()» и «.remove()» правильно меняли друг друга.Backbone.js: Должны ли .render() и .remove() иметь возможность обращать друг друга?

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

App.ChromeView = Backbone.View.extend({ 
    render: function() { 
    // Instantiate some "sub" views to handle the responsibilities of 
    // their respective elements. 
    this.sidebar = new App.SidebarView({ el: this.$(".sidebar") }); 
    this.menu = new App.NavigationView({ el: this.$("nav") }); 
    } 
}); 

$(function() { 
    App.chrome = new App.ChromeView({ el: $("#chrome") }); 
}); 

кажется предпочтительней мне настроить его так, что .remove() и .render() являются точными противоположностями:

App.ChromeView = Backbone.View.extend({ 
    render: function() { 
    this.$el.appendTo('body'); 
    this.sidebar = new App.SidebarView({ el: this.$(".sidebar") }); 
    this.menu = new App.NavigationView({ el: this.$("nav") }); 
    } 
}); 

$(function() { 
    App.chrome = new App.ChromeView(); 
}); 

Что говорит сообщество Backbone.js? Должны ли .remove() и .render() быть противоположными сторонами одной и той же монеты?

ответ

2

Я предпочитаю, чтобы render НЕ прикреплял элемент вида к dom. Я думаю, что это способствует ослаблению связи, высокой сплоченности, повторному использованию вида и облегчает модульное тестирование. Я оставляю прикрепленный визуализированный элемент к контейнеру до самого маршрутизатора или основного контейнера типа «макет».

Приятная вещь о remove заключается в том, что она работает без представления о родительском элементе и, следовательно, все еще свободно связана и многократно используется. Мне определенно не хочется помещать случайные DOM-селектора из моего макета HTML (#main или что-то еще) в мои взгляды. Определенно плохая связь.

Замечу, что в некоторых неприятных ситуациях некоторые вещи, такие как chosen jQuery plugin, нуждаются в некотором коде для запуска ПОСЛЕ того, как элемент был прикреплен к DOM. Для этих случаев я обычно реализую обратный вызов postAttach() в представлении и стараюсь, чтобы количество кода было как можно меньше.

+0

Хм ... Как отменить мой .remove(), а затем? Есть ли .add(), который я должен реализовать, или я его переусердствую? Я думаю о случаях использования, таких как лайтбоксы, уведомления и другие элементы пользовательского интерфейса, которые добавят себя в дом, когда они будут использованы, и удалятся, когда они будут сделаны. – SimplGy

+0

Мне нравится этот подход больше, чем мой. Используйте мой только в экстремальных случаях, для остальных используйте это решение _not-connection_ – fguillen

+0

@SimpleAsCouldBe (как @PeterLyons sais) вы можете вызывать «NotificationView» из внешнего компонента, «NotificationView.el» будет анонимным элементом auto- созданный 'View' it self, а внешний компонент - тот, который будет прикреплять' NotificationView.el' к DOM, поэтому 'NotificationView.remove()' можно вызвать без проблем. – fguillen

2

Да, в доме View.remove() очень agressive.

Для предложить из Пересоздайте View снова с помощью внешнего el я привык переписать так:

remove: function(){ 
    this.$el.empty(); 
    return this; 
} 

Но я не думаю, что основа должна реализовать волшебную поведение, чтобы избежать это внешние элементы DOM удаление.

Это каркасное поведение является агрессивным, хорошо, но очень дешево настраивать его при необходимости, как мы видим выше.

+0

Я был вот-вот предложит это. Это кажется идеальным. Является ли слишком много неожиданно-волшебным, чтобы фреймворк обнаружил, был ли он отправлен элемент dom или нет, и либо пустил ранее существовавший элемент dom, либо удалил себя? На самом деле это просто «вернуло то, что было». – SimplGy

+0

Кажется, что единственное решение - либо переопределить .remove, либо реализовать собственный .derender. – SimplGy

0

Как насчет этого? Если мы просто .initialize и .render принять свойство parentSelector, мы можем сделать это, и в конечном итоге с обычаем, который:

  • слабосвязанной
  • обратимых .remove() /.Render()
  • единственный метод конкретизации & рендеринга для метода вызова

например:

// Bootstrap file 
curl(['views/app']).then(
    function(App){ 
     app = new App('body'); 
    }); 



// view/app.js 
    define([ 
     'text!views/app.tmpl.html' 
    , 'link!views/app.css' 
    ] 
, function (template) { 

    var App 

    // Set up the Application View 
    App = Backbone.View.extend({ 
     // Standard Backbone Methods 
     initialize: function (parentSel) { 
      console.log('App view initialized') 
      if (parentSel) { this.render(parentSel) } 
     } 
    , render: function (parentSel) { 
      if (parentSel) { this._sel = parentSel } // change the selector if render is called with one 
      if (!this._sel) { return this } // exit if no selector is set 

      this.$el.appendTo(this._sel) 

      this.$el.html(
       this.compiledTemplate({ 'content':'test content' }) 
      ); 
      return this 
     } 
     // Custom Properties 
    , compiledTemplate: _.template(template) 
    }) 

    return App 
}); 


// External usage 
// I can call .remove and .render all day long now: 
app.remove() 
app.render() 
app.remove() 
+0

Если вы просто хотите, чтобы представление переключалось между видимым и нет, выполнение show/hide более эффективно и более прямо выражает ваши намерения, я думаю. Например, нет необходимости повторно отображать шаблон каждый раз. Но это сказало, что у вас здесь тоже кажется разумным. –