2011-08-25 109 views
0

我正在使用Backbone.js v0.5.5處理單頁應用程序,並且在應用程序的一個「頁面」上有一個Master View(audioOnDemand)和兩個輔助視圖(audioPlay和audioNav)。我希望輔助視圖是可路由的,以便用戶可以作爲示例轉到'#audio_ondemand','#audio_ondemand/id /:id'或'#audio_ondemand/page /:page',並且所有內容都會加載。爲了做到這一點,我最終不得不在我的控制器/路由器中放置一些jQuery代碼,這感覺很不方便。這就是爲什麼我在這裏,看看有沒有更好的方法。Refactor Me:Backbone.js子視圖渲染優化

這是我的控制器/路由器。

audio_ondemand: function(splat) { 
    this._audioondemandview = new AudioOnDemandView(); 
    this._audioondemandview.render(); 

    if (splat) { 
     var id_patt = /id\/(\d*)/i; 
     var id = id_patt.exec(splat); 
     id = (id) ? id[1] : null; 
     //console.log("id is: "+id); 

     var page_patt = /^page\/(\d*)/i; 
     var page = page_patt.exec(splat); 
    } 
    page = (page) ? page[1] : 1; 
    //console.log("page is: "+page); 

    if (id) { 
     setTimeout('app.play_audio("'+id+'");', 500); 
    } 

    setTimeout('app.audio_nav("'+page+'");', 500); 
}, 

audio_nav: function(page) { 
    var nav_holder = $('#pagination-nav'); 
    if (nav_holder.length == 0) { 
     app.audio_ondemand('page/'+page); 
    } else { 
     var audios = this._audios; 
     var nav = new AudioNavView({el: nav_holder, audios: audios, page: page}); 
     nav.render(); 
    } 
}, 

play_audio: function(id) { 
    var audio_holder = $('#audio-player'); 
    if (audio_holder.length == 0) { 
     app.audio_ondemand('id/'+id); 
    } else { 
     var audio = this._audios.getByUid(id); 
     this._audioview = new AudioView({el: $('#audio-player'), model: audio}); 
     this._audioview.render(); 
    } 
} 

的觀點並不做什麼特別突出的,但這裏是我的「主人」模板(使用jQuery模板):

<script id="audioOnDemandTmpl" type="text/x-jquery-tmpl"> 
    <div class="sub-header"> 
     <strong>Audio</strong> On Demand 
    </div> 
    <div id="currently-playing"> 
     <div id="currently-header">Currently Playing</div> 
     <div id="current-holder"></div> 
    </div> 
    <div id="audio-player"></div> 
    <div id="pagination-nav"></div> 
    <div id="audios-holder"></div> 
</script> 

我想現在你得到的困境承擔。主視圖必須在輔助視圖之前呈現,否則輔助視圖不具有要附加的適當DOM元素。但是,如果我希望次要視圖可路由,則必須執行'hacky'jQuery檢查以查看主視圖是否已呈現。

感謝您的任何想法或建議,並讓我知道如果您需要更多的細節!

UPDATE:因爲它可能有助於更好地給出這個想法,下面是導航視圖和模板。

<script id="audioNavTmpl" type="text/x-jquery-tmpl"> 
    {{if prev > 0}}<a href="#audio_ondemand/page/${prev}">Prev</a> | {{/if}}${current}{{if next}} | <a href="#audio_ondemand/page/${next}">Next</a>{{/if}} 
</script> 

<script id="audioTmpl" type="text/x-jquery-tmpl"> 
    <div class="audio-holder"> 
     <div class="title-author"> 
      <div class="title"><a href="#audio_ondemand/id/${attributes.uid}">${attributes.title}</a></div> 
      <div class="author">${attributes.author}</div> 
     </div> 
     <div class="topic-date"> 
      <div class="topic"><strong>${attributes.topic}</strong></div> 
      <div class="date">${attributes.date}</div> 
     </div> 
    </div> 
</script> 

var AudioNavView = Backbone.View.extend({ 
audioNavTemplate: $('#audioNavTmpl').template(), 
audioTemplate: $('#audioTmpl').template(), 

initialize: function(options) { 
    this.audios = options.audios.models; 

    var temp_page = parseInt(options.page); 
    this.page = [ 
     { 
      prev: temp_page - 1, 
      current: temp_page, 
      next: temp_page + 1 
     } 
    ]; 

    this.slice_start = (temp_page - 1) * 11; 
    this.slice_end = temp_page * 11; 

    this.audios = this.audios.slice(this.slice_start, this.slice_end); 

    if (this.audios.length <= 11) { 
     this.page[0]["next"] = false; 
    } 
}, 

render: function() { 
    //console.log(this.page); 
    this.el.empty(); 
    var sg = this; 
    $('#audios-holder').fadeOut('fast', function() { 
     $.tmpl(sg.audioNavTemplate, sg.page).appendTo(sg.el); 
     $(this).empty(); 
     $.tmpl(sg.audioTemplate, sg.audios).appendTo($(this)); 
     $(this).fadeIn('fast'); 
    }); 
    return this; 
} 

});

我應該如何更好地設置它,以便如果有人從'#home'直接跳到'#audio_ondemand/page/2',路由器會確保在audioNavView之前加載audioOnDemandView?

+0

「主」視圖和「次要」視圖之間的區別對我而言並不清楚。它們都看起來像可路由的意見。在我看來你的路由器應該有一個跟蹤當前呈現的所有視圖(路由本身是一個理想的關​​鍵),並路由顯示或構建和顯示視圖。 –

+0

爲導航視圖添加了更多代碼示例,以更好地瞭解發生了什麼。 – Andrew565

回答

1

據我所知,你的嵌套視圖只有1層深(即一個帶有子視圖的主視圖,但沒有任何子視圖),所以你可以通過渲染你的主視圖來解決你的問題在路由器的初始化方法中,然後渲染路由回調中的任何子視圖。這是一個非常簡單的例子。我使用了下劃線的模板引擎,但這個想法與jQuery的模板引擎一樣。

模板:

<script id="master-view" type="text/html"> 
    Hi, this is a master view. <a href="#subview">Render sub-view now.</a> 
    <div id="subview-container"></div> 
</script> 
<script id="sub-view" type="text/html"> 
    Hi, this is a sub view. 
</script> 

骨幹的意見和路由器

var MasterView = Backbone.View.extend({ 
    _template: _.template($('#master-view').html()), 
    render: function() { 
     $(this.el).html(this._template()); 
     return this; 
    } 
}); 

var SubView = Backbone.View.extend({ 
    _template: _.template($('#sub-view').html()), 
    render: function() { 
     $(this.el).html(this._template()); 
     return this; 
    } 
}); 

var MyRouter = Backbone.Router.extend({ 

    initialize: function() { 
     var view = new MasterView(); 
     $('body').append(view.render().el); 
    }, 

    routes: { 
     '': 'home', 
     'subview': 'subview' 
    }, 

    home: function() { 
     // probably don't have to do anything 
    }, 

    subview: function() { 
     // render subview here 
     var view = new SubView({ el: $('#subview-container')[0] }); 
     view.render(); 
    } 
}); 

new MyRouter(); 
Backbone.history.start(); 

當您將瀏覽器指向的頁面,你會首先看到的只是主視圖。點擊鏈接,你會看到#subview的URL哈希改變,子視圖將被渲染。然後,您可以重新加載頁面(URL散列仍然在#subview處),並且子視圖將在主視圖正確後呈現。