jQuery EasyUI響應式佈局的實現過程

easyui.info發表於2014-10-30

EasyUI的fluid佈局

首先解釋一下本篇文章標題中提到的“jQuery EasyUI響應式(fluid)佈局”,這裡是指頁面內的元件例項能夠隨著瀏覽器視窗大小的不同或者大小的變化自動調整元件例項自身的大小,比如自動100%填充,百分比寬度。

EasyUI 1.4版本之前,只有一個fit屬性(佈局類和表格類元件),用以實現元件寬度和高度同時按照100%比例自適應父容器大小。

到了1.4版本,新增了一個寬度百分比(佈局類、表格類以及表單類元件),用以實現元件寬度按照任意百分比自適應父容器。

儘管使用上分為fit和百分比,但是他們的實現其實是統一的,都是一個逐級呼叫子元件相關方法的過程。

什麼時候需要重計算和重繪

響應式佈局其實就是元件對自身元素大小位置的重新計算,然後重繪自我以及子元件(需要計算和重繪的)。有兩種情況會觸發這種計算和重繪:

  • 一是瀏覽器視窗大小調整會觸發計算和重繪,具體是通過window物件的resize事件實現的。
  • 二是元件本身大小調整,或者顯示隱藏狀態的切換都會觸發計算和重繪,比如layout元件region大小的調整,tabs元件標籤頁的切換等,具體是通過元件內部程式碼實現的。

巢狀元件fluid的實現機制

僅僅對某個元件例項自身計算和重繪是很簡單的,但是某元件例項自身的改變,勢必對其子元件造成影響,“EasyUI是如何在重繪元件自身後完成重繪所有需要重繪的子元件的?”,這是一個很有必要弄清楚的問題。

首先,對子元件的重繪一定是按照級數層次逐級來的,不可能先重繪孫子輩的元件再重繪兒子輩的元件。

再者,是一些我分析原始碼後得到的結論(基於1.4版本,之前的版本實現思想類似,但是包裝不同):

  • 所有佈局類元件和表格類元件的自適應計算和重繪全部使用的是panel的相關介面(表單類元件除外);
  • panel例項的DOM繫結一個自定義的”_resize”事件,事件處理器內部呼叫panel元件的”resize”介面;
  • panel元件的reszie介面內部會呼叫panel元件的doLayout介面;
  • doLayout介面會尋找下一級需要重繪(包含表單類元件)的子元件;

現在來說明具體的實現機制。我們假設有以下DOM結構,class為panel的DOM代表佈局類或者表單類元件的例項,不帶class的DOM是普通的DIV。

<div id="a-0" class="panel">
    <div id="a-1">
        <div id="a-1-1" class="panel">
            <div id="a-1-1-1" class="panel">...</div>
        </div>
        <div id="a-1-2" class="panel">
            <div id="a-1-2-1"></div>
        </div>
    </div>
</div>
  • 第一步:“a-0”被觸發計算和重繪,具體通過其例項的resize介面實現,resize介面最後呼叫doLayout介面;
  • 第二步:“a-0”的doLayout介面搜尋到“a-1-1”和“a-1-2”兩個元件例項需要重繪,呼叫他們的resize方法;
  • 第三步:“a-1-1”和“a-1-2”各自呼叫自身的resize介面重繪自我後,在各自呼叫自身的doLayout介面;
  • 第四步:“a-1-1”的doLayout介面搜尋到:“a-1-1-1”需要重繪,“a-1-2”的doLayout沒找到需要重繪的元件,搜尋結束;
  • 第五步:“a-1-1-1”呼叫自己的resize介面重繪自我後,在呼叫自身的doLayout介面;
  • 第六步:“a-1-1-1”的doLayout介面搜尋不到需要重繪的元件,到此全部結束。

通過這個例子,我想這個過程應該就很清楚了,儘管我描述成這個樣子,大家可能覺得很簡單,但是其內部元件的依賴繼承關係還是比較複雜的。抓住中心的實現思想,一切問題才有解決的思路。

效能問題

doLayout對“下一級響應式佈局元件”的搜尋程式碼是有很大優化空間的,當頁面DOM結構很複雜的時候,特別是有大資料量表格的時候,在IE下的doLayout的搜尋效率慘不忍睹,可以使用“children方法+遞迴呼叫+對普通表格不搜尋”的方案優化。

相關文章