2013-12-19 44 views
3

我正在用Backbone.js(使用Underscore模板),Express和Node.js構建一個應用程序。如何在呈現Backbone模板後調用jQuery代碼?

我做了這個非常簡單的例子來說明問題(請參閱下面的代碼),該應用程序包含從服務器檢索到的「標題」列表。

我使用下劃線模板來呈現HTML。在呈現HTML之後,我想執行一些jQuery代碼,例如在控制檯中打印每個「標題」的位置()。 問題是在模板插入DOM中的元素之前調用jQuery代碼,所以jQuery找不到元素。

我錯過了什麼? 在DOM中插入html後,是否有辦法獲取事件?

下面的代碼:

<div class="container"> 
     <div id="tracks"> 

     </div> 
    </div> 

    <!-- Template --> 
    <script id="trackTemplate" type="text/template"> 

     <ul id="<%= id2 %>" style="height:150px"> 
      <li><%= title %></li> 
     </ul>    

     <% 
     // So it looks like this code gets code before the template's HTML is in the DOM. 
      console.log($("#"+id2).position()); 
     %> 
    </script> 

    <script src="js/lib/jquery-1.10.2.min.js"></script> 
    <script src="js/lib/underscore-min.js"></script> 
    <script src="js/lib/backbone-min.js"></script> 
    <script> 
    var app = app || {}; 

    // Model 
    app.Track = Backbone.Model.extend({ 
     defaults: { 
      id2: '', 
      title: 'Track', 
     }, 
    }); 

    // Collection 
    app.Library = Backbone.Collection.extend({ 
     model: app.Track, 
     url: '/api/tracks' 
    }); 

    // Track view 
    app.TrackView = Backbone.View.extend({ 
     tagName: 'div', 
     className: 'trackContainer', 
     template: _.template($('#trackTemplate').html()), 
     initialize:function(){ 
      this.model.on('change', this.render, this); 
     }, 
     render: function() { 
      this.$el.html(this.template(this.model.toJSON())); 

      return this; 
     }, 

    }); 

    // Collection View 
    var numberOfTracks = 0; 
    app.LibraryView = Backbone.View.extend({ 
     el: '#tracks', 

     initialize: function(initialTracks) { 
      this.collection = new app.Library(initialTracks); 
      this.collection.fetch(); 
      this.listenTo(this.collection, 'add', this.renderTrack); 
     }, 

     // render library by rendering each track in its collection 
     render: function() { 
      this.collection.each(function(item) { 
       this.renderTrack(item); 
       numberOfTracks++; 
      }, this); 
     }, 

     // render a track by creating a trackView and appending the 
     // element it renders to the library's element 
     renderTrack: function(item) { 
      var trackView = new app.TrackView({ 
       model: item 
      }); 
      this.$el.append(trackView.render().el); 
     }, 
    }); 

    // Initialise app 
    var libraryView = new app.LibraryView(); 
    </script> 

感謝

回答

0
  • 的正確的地方爲你console.log電話會在你render方法結束或renderTrackappend之後。

  • Backbone還可以輕鬆創建自己的活動並通過Backbone.Events註冊。你可以在我前面提到的地方之一開火自己的活動。

  • 有一個用於跟蹤DOM中更改的已棄用事件系列,稱爲Mutation events - 但它們已被棄用且瀏覽器支持不太可靠。替換爲MutationObserver,在DOM4 spec中定義,瀏覽器支持尚未支持(IE僅支持11),但對於測試它可能會有用。

  • 另一種方法是將您的代碼放入setTimeout--這樣DOM節點肯定會在您的console.log運行時插入。

+0

我試圖把'console.log'放在'render'方法的末尾,但沒有解決問題。我可以像你說的那樣觸發一個事件,但是我遇到的問題是在模板呈現(可能觸發事件)和插入DOM元素中的HTML元素之間存在一段時間。我需要的是當HTML在DOM中時的事件和事件。感謝您的回答。 – andreugrimalt

+0

@andreugrimalt你在哪裏準確地把它放在哪裏?結果是什麼?元素應該在調用'append' /'html'後立即插入到DOM中。 – kapa

+0

結果如下所示:'Uncaught TypeError:Object [object Object] has no method'postion''。這意味着該元素不存在...實際上'$(「#」+ id2).length'返回0.我同意元素應該在調用append後立即插入到DOM中。不幸的是,情況並非如此...... – andreugrimalt

1

爲了覆蓋這裏的一些地方,一旦有東西插入到DOM中就不會觸發事件。我實際上不會主張通過將代碼放在模板中來解決這個問題。而是看看你的視圖呈現的方式。

如果你想拋出一些代碼到一個預先存在的佔位符,你可以看看做這樣的事情:

[view here].setElement(this.$([selector here])).render(); 

有這樣的一個很好的解釋:

http://ianstormtaylor.com/rendering-views-in-backbonejs-isnt-always-simple/

如果你不需要任何重量級的子視圖管理,這是排列子視圖的一種簡潔方式。在這之後,你應該能夠像使用jQuery那樣做事情,正如你通常所說的那樣。$ el和this。$。在視圖中提供元素的範圍是正確的。