簡體   English   中英

在渲染主干視圖時獲得通知

[英]Get notified when a Backbone View has been rendered

我正在研究Backbone.View ,它應該將集合呈現為可滾動列表。

在初始渲染的一部分中,我需要訪問一些布局屬性(例如clientWidth ),這些屬性僅在渲染視圖之后才可用。

我的問題是, 如何知道何時將視圖添加到DOM?


使用Backbone.View通常有兩種將視圖附加到DOM的方法:

  1. 創建視圖>渲染>附加它:

     view = new MyList().render() $('#dummy').append(view.$el) 
  2. 創建視圖並就地渲染:

     new MyList({el: '#dummy'}).render() 

注意:我知道(1)和(2)並不完全等效,這不是重點。


讓我們考慮一下我的列表定義如下:

class MyList extends Backbone.View
    render: ->
        @$el->html( ... )
        @

    layout: ->
        max = $el.scrollWidth - $el.clientWidth
        # ... disable / enable scrolling arrows based on max ...

MyList附加到DOM后,如何確定layout()被調用?

我已經遇到了這個問題,有些模式可以提供幫助。 骨干網為您提供工具,但不會告訴您如何使用它們。 建立良好的模式在您使用它時非常重要。 我使用了兩種不同的模式來幫助實現這一目標。

1)根據您的應用程序的工作方式,確保始終在呈現視圖並將其附加到DOM之后始終調用attached()方法或在視圖上觸發attached事件可能很容易,也可能很難。 就我而言,這很容易,因為我創建了一種架構,可以在一個中央位置處理該架構。

2)如果您總是在渲染之后立即將元素附加到DOM-特別是在渲染之后的任何時間,而不是通過在異步回調中這樣做來延遲附加,那么在render()函數中,您可以將對layout()的調用或其他需要在連接后運行。 像這樣:

var MyList = Backbone.View.extend({
  render: function() {
    /* rendering logic goes here */

    // Notice that the timeout is 0 - you can actually not even pass this argument
    // but I wanted to emphasize that there is no delay given.
    setTimeout(this.layout, 0);

    return this;
  },

  layout: function() {
    // This code won't be run until after this.el is attached to the DOM
  }
});

var view = new MyList().render();
$('#dummy').append(view.$el);

Javascript始終是單線程的。 I / O可以異步完成,但是實際上需要JS引擎花費時間的任何事情都不能與其他JS代碼並行運行。 當您調用不帶最后一個參數或值為0 setTimeout()時,實際上它將使它排隊,以便在當前執行的代碼完成后盡快運行。

如果在調用render()之后立即遵循始終附加到DOM的模式,則可以利用這一事實-在當前執行的代碼完成運行並將控制權返回給JS引擎以運行接下來排隊的任何東西之前的任何時間。 在運行由setTimeout(func, 0)排隊的函數時,您便可以知道您的視圖已附加到DOM。 請注意,這與_.defer()作用相同,但是我想為您解釋一下。

再一次,建立模式非常重要。 如果您從未保持一致並且沒有在應用程序內建立模式,那么您將沒有任何保證,您將失去依靠這種機制的能力-否則您可能會建立其他機制。 希望這可以幫助!

這是一個看似困難的問題。 DOM突變事件 ,但是AFAIK並未跨瀏覽器實現,因此無論如何都已棄用。 突變觀察者似乎是做到這一點的新方法,但是同樣,我不確定兼容性。

確保安全的方法,但昂貴/混亂的方法是輪詢以查看屍體是否位於祖先鏈中。

whenInserted = function ($el, callback) {
  check = function () {
    if ($el.closest('body').length) { // assuming a jQuery object here
      callback();
    } else {
      setTimeout(check, 100);
    }
  };
  check();
};

我對其中一些答案的糟糕程度感到驚訝。 jQuery方法是同步的。

因此,在Backbone.View渲染功能中,您有幾個不錯的選擇:

//只調用一個函數

  render:function(){

          //first, use Backbone/jQuery to append to DOM here

           //second 

   this.callSomeFunctionToSignifyRenderIsDone();

      return this;
    }

//觸發一個事件

render:function(){

   //use Backbone/jQuery to append to DOM here


   Backbone.Events.trigger('viewX-rendered'.); //trigger an event when render is complete

  return this;
}

或者,如果您的render方法具有異步代碼,這種情況不太可能發生,您可以將可選的回調傳遞給render函數:

render: function(callback){

   //use Backbone/jQuery to append to DOM here

  if(typeof callback === 'function'){
     callback(null,'viewX-rendered'); //invoke the error-first callback
}
}

考慮到從渲染返回“ this”以便鏈接Backbone調用是首選模式,那么前兩個選擇可能是更好的選擇。

最后,如果您當前的渲染方法確實是異步的,也就是說,將內容附加到DOM的jQuery代碼正在異步發生,那么您可以使用jQuery這樣將偵聽器附加到DOM元素上

https://gist.github.com/azat-co/5898111

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM