讀Ext之十一(通過innerHTML創建元素)


innerHTML 這個由 IE 引入的屬性成了事實標准,各瀏覽器均支持。盡管html4中沒有承認它,但html5已經正式將其納入 。

我們知道任何一個庫都少不了DOM操作,因為用JS操作DOM(早期微軟稱DHTML)是日常開發中最基本的工作之一。

這篇主要講述Ext.DomHelper中的 createHtml 函數。首先Ext.DomHelper為一個單例對象。使用其時可沿用Ext庫的習慣使用別名dh

var dh = Ext.DomHelper; // 使用dh別名

 

dh有以下方法:
markup
applyStyles
insertHtml
insertBefore
insertAfter
insertFirst
append
overwrite
createHtml
 

dh的createHtml方法就是整個閉包中私有的createHtml。
dh的markup方法內部調用的就是整個閉包中私有的createHtml。
dh的overwrite方法內部也用到了createHtml。

此外私有的doInsert函數內部用用到了createHtml,而dh的insertBefore、insertAfter、insertFirst、append方法用到了doInsert。
因此可以看到私有的createHtml函數是dh中處在底層的,最重要的函數 。它們之間的關系如下圖

 

createHtml 的定義如下

function createHtml(o){
    var b = '',
        attr,
        val,
        key,
        keyVal,
        cn;

    if(Ext.isString(o)){
        b = o;
    } else if (Ext.isArray(o)) {
        for (var i=0; i < o.length; i++) {
            if(o[i]) {
                b += createHtml(o[i]);
            }
        };
    } else {
        b += '<' + (o.tag = o.tag || 'div');
        Ext.iterate(o, function(attr, val){
            if(!/tag|children|cn|html$/i.test(attr)){
                if (Ext.isObject(val)) {
                    b += ' ' + attr + '="';
                    Ext.iterate(val, function(key, keyVal){
                        b += key + ':' + keyVal + ';';
                    });
                    b += '"';
                }else{
                    b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
                }
            }
        });
        // Now either just close the tag or try to add children and close the tag.
        if (emptyTags.test(o.tag)) {
            b += '/>';
        } else {
            b += '>';
            if ((cn = o.children || o.cn)) {
                b += createHtml(cn);
            } else if(o.html){
                b += o.html;
            }
            b += '</' + o.tag + '>';
        }
    }
    return b;
}

雖然代碼較多,但接口卻很簡單:傳入了一個參數o,返回了一個字符串b。

createHtml 內部有三個分支

分支1 ,參數o為字符串時直接返回
分支2 ,參數o為數組時遞歸調用自身.Ext.isArray用來判斷所傳參數是否為一個數組類型,該方法在 讀Ext之二(實用方法) 中提到。
分支3 ,參數o為對象時(通常使用最多的情況)

分之一的情況很簡單

var str = createHtml('<div>test</div>');
alert(str); // "<div>test</div>"

 

分支二的情況

var str = createHtml(['<div>test</div>','<p>pp</p>']);
alert(str); // "<div>test</div><p>pp</p>"

 

分支三的情況

var obj = {
        tag:'ul',
        children:[{tag:'li',html:'li 1'},{tag:'li',html:'li 2'}]
    };
var str = createHtml(obj);
alert(str); // "<ul><li>li 1</li><li>li 2</li></ul>"

 

分支三的詳細情況如下

b += '<' + (o.tag = o.tag || 'div');

 

b為空字符串,該語句執行完為:"<tag",如果沒有所傳對象沒有tag屬性,默認創建div即"<div"

接下來是為根元素添加屬性,

Ext.iterate(o, function(attr, val){
    if(!/tag|children|cn|html$/i.test(attr)){
        if (Ext.isObject(val)) {
            b += ' ' + attr + '="';
            Ext.iterate(val, function(key, keyVal){
                b += key + ':' + keyVal + ';';
            });
            b += '"';
        }else{
            b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
        }
    }
});

 

Ext.iterate方法是一個通用迭代器,可以迭代數組,也可以是對象。在 讀Ext之二 提到。即所傳對象o的屬性不為tag、children、cn、html時給該元素添加html屬性

var obj = {
    tag: 'input',
    name: 'uname',
    cls: 'myClass',
    id: 'myId'
};
var str = createHtml(obj); // 創建input元素,添加name、class及id屬性
alert(str); // <input name="uname" class="myClass" id="myId"/>

 

對html元素的class,for屬性做了特殊處理,因為js中class是保留字,for是關鍵字。

此外有些屬性值是復合值組成,如style

var obj = {
    tag: 'p',
    style: {width:'100px',height:'100px',background:'red'}
};
var str = createHtml(obj);
alert(str); // <p style="width:100px;height:100px;background:red;"></p>

 

接下來

if (emptyTags.test(o.tag)) {
    b += '/>';
}

emptyTags 是一個正則,這句是對非閉合標簽的處理,非閉合標簽如br、input、img等。
所有的非閉合標簽,都會以"/>"結束,這里遵循xml的習慣。對於非閉合標簽不會有html內容。

接下來

else {
    b += '>';
    if ((cn = o.children || o.cn)) {
        b += createHtml(cn);
    } else if(o.html){
        b += o.html;
    }
    b += '</' + o.tag + '>';
}

對於閉合標簽,先完成首標簽閉合。拿div示例,由先"<div"變成了"<div>"。

 

接下來如果有children或cn屬性,則添加子元素,是一個遞歸調用,即子元素如果有屬性,子元素仍然會繼續遞歸添加。
最后是結束標簽"</div>"

 

這就是這個createHtml函數了。該函數實現的很緊湊,巧妙。

createHtml最終返回的是html片段,該片段會通過innerHTML添加到文檔中去。
上面的關系圖已經可以看到:

markup方法直接調用了createHTML

markup : function(o){
    return createHtml(o);
},

個人認為這個方法和markup方法重復了。


doInsert方法也直接調用了createHtml

function doInsert(el, o, returnElement, pos, sibling, append){
    var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o));
    return returnElement ? Ext.get(newNode, true) : newNode;
}

 

好了,下一篇會接着看DomHelper的其它方法。

 

 

DomHelper.js 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM