2016-09-20 2 views
0

Ich habe drei console.log in den folgenden Code eingefügt, der aus dem Tutorial Your First Backbone.js App stammt.Welche Funktion einer Ansicht wird zuerst ausgeführt? initialisieren oder rendern?

Meine Frage ist: Warum console.log(this.el) zeigt das Element ist innerHtml bereits "gerendert", aber die console.log('render runs!') Nachricht druckt danach?

Welche Funktion der View wird zuerst ausgeführt? initialisieren oder rendern?

$(function(){ 

    // Create a model for the services 
    var Service = Backbone.Model.extend({ 

     // Will contain three attributes. 
     // These are their default values 

     defaults:{ 
      title: 'My service', 
      price: 100, 
      checked: false 
     }, 

     // Helper function for checking/unchecking a service 
     toggle: function(){ 
      this.set('checked', !this.get('checked')); 
     } 
    }); 


    // Create a collection of services 
    var ServiceList = Backbone.Collection.extend({ 

     // Will hold objects of the Service model 
     model: Service, 

     // Return an array only with the checked services 
     getChecked: function(){ 
      return this.where({checked:true}); 
     } 
    }); 

    // Prefill the collection with a number of services. 
    var services = new ServiceList([ 
     new Service({ title: 'web development', price: 200}), 
     new Service({ title: 'web design', price: 250}), 
     new Service({ title: 'photography', price: 100}), 
     new Service({ title: 'coffee drinking', price: 10}) 
     // Add more here 
    ]); 

    // This view turns a Service model into HTML 
    var ServiceView = Backbone.View.extend({ 
     tagName: 'div', 

     events:{ 
      'click': 'toggleService' 
     }, 

     initialize: function(){ 

      // Set up event listeners. The change backbone event 
      // is raised when a property changes (like the checked field) 
      console.log(this); 
      console.log(this.el); 

      this.listenTo(this.model, 'change', this.render); 
     }, 

     render: function(){ 

      // Create the HTML 
      console.log("render runs!"); 

      this.$el.html('<input type="checkbox" value="1" name="' + this.model.get('title') + '" /> ' + this.model.get('title') + '<span>$' + this.model.get('price') + '</span>'); 
      this.$('input').prop('checked', this.model.get('checked')); 

      // Returning the object is a good practice 
      // that makes chaining possible 
      return this; 
     }, 

     toggleService: function(){ 
      this.model.toggle(); 
     } 
    }); 

    // The main view of the application 
    var App = Backbone.View.extend({ 

     // Base the view on an existing element 
     el: $('#main'), 

     initialize: function(){ 

      // Cache these selectors 
      this.total = $('#total span'); 
      this.list = $('#services'); 


      // Listen for the change event on the collection. 
      // This is equivalent to listening on every one of the 
      // service objects in the collection. 
      this.listenTo(services, 'change', this.render); 


      // Create views for every one of the services in the 
      // collection and add them to the page 

      services.each(function(service){ 

       var view = new ServiceView({ model: service }); 
       this.list.append(view.render().el); 

      }, this); // "this" is the context in the callback 
     }, 

     render: function(){ 

      // Calculate the total order amount by agregating 
      // the prices of only the checked elements 

      var total = 0; 

      _.each(services.getChecked(), function(elem){ 
       total += elem.get('price'); 
      }); 

      // Update the total price 
      this.total.text('$'+total); 

      return this; 

     } 

    }); 

    new App(); 

}); 

Ausgabe von der Konsole ist wie folgt:

child {cid: "view7", model: child, $el: init[1], el: div} 
<div> 
<input type="checkbox" value="1" name="web development"> web development 
<span>$200</span></div> 
render runs! 

Antwort

1

initialize immer an erster Stelle genannt wird, wie es in dem Standard-Backbone Sicht Konstruktor ist.

render wird aufgerufen, wenn Sie es manuell aufrufen.

services.each(function(service) { 

    // ServiceView 'initialize' is called here. 
    var view = new ServiceView({ model: service }); 
    // ServiceView 'render' is called here. 
    this.list.append(view.render().el); 

}, this); 

Warum zeigt die Konsole die el vor dem Rendern?

Tatsächlich zeigt die Konsole das Element nicht vor dem Rendern, aber es wird ausgewertet, wenn Sie es in der Konsole überprüfen.

Hier ist ein einfaches Beispiel:

var myObject = {}; 

console.log(myObject); 

myObject.test = "value"; 

Wenn Sie zu erraten hätte, würde man sagen, dass ein leeres Objekt angemeldet ist und Sie würden nicht völlig falsch sein.

Logged object being evaluated

Die kleinen blauen ! sagt:

Objektwert links Snapshot von ihr erstellt wurde, als angemeldet, unter Wert gerade ausgewertet.

Wie erwähnt "zu kurz mu ist",

die Konsole live references enthält, und kopieren Sie nichts. Wenn Sie also an die Konsole kommen, um this.el zu betrachten, zeigt es Ihnen, was gerade jetzt ist, anstatt was es war, als console.log(this.el) ausgewertet wurde.

+0

aber innerhalb der Initialisierungsfunktion wird "this.el" bereits so gerendert, dass sie Zeug enthält, das in der Renderfunktion erzeugt wird. Das macht keinen Sinn. –

+0

@ShawnChen Überprüfen Sie den zweiten Teil meiner Antwort, der erklärt, wie die Konsole versucht, zu helfen, indem Sie das geloggte Objekt später auswerten. Zuerst enthält 'this.el' nur das leere' div', das von 'tagName' erwähnt wird, aber wenn die Konsole das Element neu bewertet, zeigt es seinen letzten Zustand an. –

+0

Beachten Sie, dass 'HTMLElement' (was' this.el' ist) Objekte und keine Zeichenfolgen sind. –

Verwandte Themen