2014-06-20 25 views
0

我正試圖傾聽兩個JavaScript事件。兩者都需要發生,但我不知道它們將以何種順序發生。在這兩種情況都發生之前,我不想運行我的代碼。我可以與jQuery的事件處理程序附加函數一起使用延遲事件嗎?如何偵聽兩個異步的附加事件處理程序?

具體而言,我想等到具有遠程加載內容的引導模式已完成顯示和加載。

單擊此超鏈接顯示模式,使用jquery的load方法在超鏈接中加載頁面,並將加載的頁面內容插入到模式中。

<a href="http://www.example.com" data-toggle="modal" data-target="#mymodal">Click Here</a> 

目標模式:

<div class="modal fade" id="mymodal> 
    <div class="modal-dialog"> 
     <div class="modal-content"></div> 
    </div> 
</div> 

我的失敗嘗試連接該事件偵聽器和使用承諾,知道什麼時候這兩個事件都被解僱。我認爲這裏的問題在於,承諾告訴我,聽衆是依附的,而不是事件已經解僱。

var loaded = $(".modal").on('loaded.bs.modal', function(evt) { 
    console.log("content loaded"); 
}).promise(); 
var shown = $(".modal").on('shown.bs.modal', function(evt) { 
    console.log("modal visible"); 
}).promise(); 

$.when(loaded, shown).done(function(load, show) { 
    console.log("content loaded and modal visible"); 
}); 

Demo上bootply

+1

嘗試http://www.bootply。com/YWcJsaXbpq – PSL

+0

@PSL使用'resolve()'完美地工作。感謝您的幫助! –

+0

@ Mr.Dave,據我所知,看起來''shown'事件總是會在'loaded'事件之後觸發。如果沒有要顯示的內容,沒有理由完成顯示模式。我想你只需要聽着'shown'事件就安全了。 – zzzzBov

回答

1

.promise()返回該fx隊列延期承諾。由於您實際上並未等待fx隊列,因此沒有理由在此使用該特定方法。

諮詢的bootstrap documentation

show.bs.modal - 馬上此事件在該show實例方法被調用。如果由點擊引起,點擊的元素可用作事件的relatedTarget屬性。

shown.bs.modal - 當模式已經被用戶看到(將等待CSS轉換完成)​​時,該事件被觸發。如果由點擊引起,點擊的元素可用作事件的relatedTarget屬性。

loaded.bs.modal - 當模式使用遠程選項加載內容時觸發此事件。

承諾是一次性使用。一旦他們解決了,你需要產生一個新的承諾。

如果您知道事件將按特定順序發生,依靠該順序通常就足夠了。例如,如果訂單總是:

  1. 顯示
  2. 顯示

然後一個事件處理程序連接到shown事件

  • 裝載足夠的,因爲它會在loaded後總是會發生事件。


    我的文檔的解釋是,shown事件總會被loaded事件後(爲什麼顯示的東西,這不是到了嗎?)解僱了,這意味着你可以只監聽shown事件,完全忽略loaded


    由於我不是100%肯定的實際的行爲,我將承擔爲這篇文章的緣故,訂單也可能是:

    1. 顯示
    2. 所示
    3. 加載

    我已經包括show在列表中,因爲它是一個一致的起點。您將不會獲得shownloaded事件,直到之後show事件發起。這很有用,因爲您可以使用它來生成新的延期。

    $('.modal').on('show.bs.modal', function() { 
        var $this, 
         data; 
        $this = $(this); 
        data = $this.data(); 
        if (data.shownDeferred) { 
         //if this modal had been opened before, but never finished 
         //showing it should be cancelled 
         data.shownDeferred.reject(); 
        } 
        data.shownDeferred = $.Deferred(); 
        if (data.loadedDeferred) { 
         //if this modal had been opened before, but never loaded 
         //it should be cancelled 
         data.loadedDeferred.reject(); 
        } 
        data.loadedDeferred = $.Deferred(); 
    
        $.when(data.shownDeferred, data.loadedDeferred).then(function() { 
         $this.trigger('yourcustomeventname'); 
        }); 
    }).on('loaded.bs.modal', function() { 
        var dfd; 
        dfd = $(this).data('loadedDeferred'); 
        if (dfd) { 
         dfd.resolve(); 
        } 
    }).on('shown.bs.modal', function() { 
        var dfd; 
        dfd = $(this).data('shownDeferred'); 
        if (dfd) { 
         dfd.resolve(); 
        } 
    }); 
    

    通過以上設置,你的一套模式當兩個loadedshown事件已經完成射擊觸發自己的自定義事件。


    警告我沒有測試此代碼的任何,所以它可以是手推車

  • +0

    包括演出是一個聰明的想法。我通常會在'顯示'之前看到「加載」,但我不相信有引導程序對模型的動畫和jQuery的加載進行排序的任何原因。我現在正在測試這種方法,我會讓你知道它是怎麼回事。 –

    +0

    這很好。正如你所提到的那樣,生成新的延期而不是承諾允許它重複觸發新的事件。 –

    0

    對於這個問題,Deferreds /承諾是大錘破解的螺母。即使事件的順序不知道,整個事情可以用布爾人解決,而不是承諾。

    但是,事件的順序已知。運行一個test,你可以看到一個初始的「show」與後面的「shows」有不同的表現。的事件中,爲了,如下:

    • 上第一展 - '顯示', '加載', '示出' 在隨後的節目
    • - '節目', '' 所示

    換句話說,loaded是一次性事件,並且shown是可靠的最後一次。

    因此,您可以簡單地收聽shown

    $('.modal').on('shown.bs.modal', function() { 
        //Do awesome stuff here 
    }); 
    

    如果要抑制進一步的「表演」的模式已經顯示出之前,那麼它稍微有點複雜,但不是太糟糕了 - 這樣也許事情:

    $('.modal').on('show.bs.modal', function() { 
        var $this = $(this), 
         data = $this.data('modal'); 
        if (!data) { 
         data = $this.data('modal') = {}; 
        } 
        if(!data.pending) { 
         data.pending = true; 
         $this.one('shown.bs.modal', function() { 
          data.pending = false; 
          //Do awesome stuff here 
         }); 
        } 
    }); 
    

    有了更多的想法,這可能會簡化。