jquery.dataTable.js 使用詳解 二、sDom佈局原始碼解析

風靈使發表於2018-10-22

dataTable是怎麼利用aDom實現佈局的,提出了疑問。由於很久以前看的原始碼,當時也沒有跟他解釋的很清楚,於是又重新梳理了一下原始碼,在這裡做一下筆記。

首先看一下示例的實際效果:
在這裡插入圖片描述

原始碼中實現佈局的方法是_fnAddOptionsHtml(),形參是oSettings

下面看_fnAddOptionsHtml()原始碼:


    function _fnAddOptionsHtml ( oSettings )  
    {  
        /* 
         * Create a temporary, empty, div which we can later on replace with what we have generated 
         * we do it this way to rendering the 'options' html offline - speed :-) 
         * 作者說:這裡先建立一個臨時的空div,後面會被完整的內容替換掉 
         */  
        var nHolding = $('<div></div>')[0];  
        /* 
         * 把上面生成的臨時div插入到繫結dataTable外掛的元素前面 
         * 這裡的oSettings.nTable,追溯原始碼,發現是this,也就是繫結外掛的物件 
         * 例如:$("#mainTable").dataTable({....});   oSettings.nTable 就是 id為mainTable的 
         */  
        oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );  
        /*  
         * All DataTables are wrapped in a div 
         * 作者說:建立一個div作為根節點,將所有的元素都包裹進去,以<table>的id拼接'_wrapper' 
         */  
        oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0];  
        oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;  
      
        /* Track where we want to insert the option  
         * 將oSettings.nTableWrapper賦給變數nInsertNode,跟蹤我們想插入的元素 
         */  
        var nInsertNode = oSettings.nTableWrapper;  
          
        /* Loop over the user set positioning and place the elements as needed */  
        /* 
         * 前方高能,重頭戲開始了!!! 
         * 分割aDom,得到字元陣列 
         * 示例中我們的aDom屬性值為<lf>rt<lpi><"clear"> 
         */  
        var aDom = oSettings.sDom.split('');  
        var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;  
        /* 
         * 迭代字元陣列 
         */  
        for ( var i=0 ; i<aDom.length ; i++ )  
        {  
            iPushFeature = 0;  
            cOption = aDom[i];  
            /* 
             * 如果當前字元是'<'執行以下操作 
             */  
            if ( cOption == '<' )  
            {  
                /* New container div  
                 * 建立一個空div 
                 */  
                nNewNode = $('<div></div>')[0];  
                  
                /* Check to see if we should append an id and/or a class name to the container  
                 * 看看是否要給div新增id屬性或者class屬性 
                 * 如果<符號後面是'或"就要給div新增屬性 
                 */  
                cNext = aDom[i+1];  
                if ( cNext == "'" || cNext == '"' )  
                {  
                    sAttr = "";  
                    j = 2;  
                    while ( aDom[i+j] != cNext )  
                    {  
                        sAttr += aDom[i+j];  
                        j++;  
                    }  
                      
                    /* Replace jQuery UI constants */  
                    if ( sAttr == "H" )  
                    {  
                        sAttr = oSettings.oClasses.sJUIHeader;  
                    }  
                    else if ( sAttr == "F" )  
                    {  
                        sAttr = oSettings.oClasses.sJUIFooter;  
                    }  
                      
                    /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 
                     * breaks the string into parts and applies them as needed 
                     * 如果字串裡面有#號,就給div加上id屬性,如果字串裡面有.號,就給div加上class屬性 
                     */  
                    if ( sAttr.indexOf('.') != -1 )  
                    {  
                        var aSplit = sAttr.split('.');  
                        nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);  
                        nNewNode.className = aSplit[1];  
                    }  
                    else if ( sAttr.charAt(0) == "#" )  
                    {  
                        nNewNode.id = sAttr.substr(1, sAttr.length-1);  
                    }  
                    else  
                    {  
                        nNewNode.className = sAttr;  
                    }  
                      
                    i += j; /* Move along the position array */  
                }  
                /* 
                 * 將處理完成後的div放入根節點,並對根節點變數重新賦值為新建立的div 
                 */  
                nInsertNode.appendChild( nNewNode );  
                nInsertNode = nNewNode;  
            }  
            else if ( cOption == '>' )  
            {  
                /* End container div  
                 * 這裡標識一個div的閉合  
                 */  
                nInsertNode = nInsertNode.parentNode;  
            }  
            else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )  
            {  
                /* Length  
                 * 如果當前字元為l,則表示為dataTable增加可以操作每頁顯示行數的下來框 
                 * 前置條件為bLengthChange和bPaginate配置為true,即允許分頁並且允許使用者選擇每頁顯示行數 
                 * 將在_fnFeatureHtmlFilter函式中建立class="mainTable_length"的元素,並且放入上面建立的div中 
                 */  
                nTmp = _fnFeatureHtmlLength( oSettings );  
                iPushFeature = 1;  
            }  
            else if ( cOption == 'f' && oSettings.oFeatures.bFilter )  
            {  
                /* Filter  
                 * 如果當前字元為f,則表示為dataTable增加跨行搜尋框 
                 * 前置條件為bFilter配置為true,即啟用內建搜尋,可跨行搜尋 
                 * 將在_fnFeatureHtmlFilter函式中建立class="dataTables_filter"的元素,並且放入上面建立的div中 
                 */  
                nTmp = _fnFeatureHtmlFilter( oSettings );  
                iPushFeature = 1;  
            }  
            else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )  
            {  
                /* pRocessing  
                 * 如果當前字元為r,則表示為dataTable增加資料載入進度效果 
                 * 前置條件為bProcessing配置為true,即顯示載入時進度條 
                 * 將在_fnFeatureHtmlProcessing函式中建立class="dataTables_processing"的元素,並且放入上面建立的div中 
                 */  
                nTmp = _fnFeatureHtmlProcessing( oSettings );  
                iPushFeature = 1;  
            }  
            else if ( cOption == 't' )  
            {  
                /* Table  
                 * 這就是table實體了,將在_fnFeatureHtmlTable函式中建立table元素,table的屬性、樣式將沿用html程式碼中的定義 
                 */  
                nTmp = _fnFeatureHtmlTable( oSettings );  
                iPushFeature = 1;  
            }  
            else if ( cOption ==  'i' && oSettings.oFeatures.bInfo )  
            {  
                /* Info  
                 * 如果當前字元為i,則表示為dataTable增加表格相關資訊,例如翻頁資訊等。 
                 * 前置條件為bInfo配置為true,即顯示錶格相關資訊 
                 * 將在_fnFeatureHtmlInfo函式中建立class="dataTables_info"的元素,並且放入上面建立的div中 
                 * */  
                nTmp = _fnFeatureHtmlInfo( oSettings );  
                iPushFeature = 1;  
            }  
            else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )  
            {  
                /* Pagination  
                 * 如果當前字元為p,則表示為dataTable增加分頁功能。 
                 * 前置條件為bPaginate配置為true,即開啟分頁功能 
                 * 將在_fnFeatureHtmlPaginate函式中建立分頁所需的元素,並且放入上面建立的div中  
                 * */  
                nTmp = _fnFeatureHtmlPaginate( oSettings );  
                iPushFeature = 1;  
            }  
            else if ( DataTable.ext.aoFeatures.length !== 0 )  
            {  
                /* Plug-in features */  
                var aoFeatures = DataTable.ext.aoFeatures;  
                for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )  
                {  
                    if ( cOption == aoFeatures[k].cFeature )  
                    {  
                        nTmp = aoFeatures[k].fnInit( oSettings );  
                        if ( nTmp )  
                        {  
                            iPushFeature = 1;  
                        }  
                        break;  
                    }  
                }  
            }  
              
            /* Add to the 2D features array */  
            if ( iPushFeature == 1 && nTmp !== null )  
            {  
                if ( typeof oSettings.aanFeatures[cOption] !== 'object' )  
                {  
                    oSettings.aanFeatures[cOption] = [];  
                }  
                oSettings.aanFeatures[cOption].push( nTmp );  
                nInsertNode.appendChild( nTmp );  
            }  
        }  
          
        /* Built our DOM structure - replace the holding div with what we want  
         * 將上面的臨時div換成我們最後生成的div 
         */  
        nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );  
    }  

最後附上一張,aDom字元與介面元素的對應關係圖:
在這裡插入圖片描述

相關文章