在jQuery.fn.init函數(shù)中,最終的結(jié)果是把Dom元素放到jQuery對象的集合,我們可以傳入單個Dom元素或Dom元素集合直接把其存到jQuery對象的集合。但是如果第一個參數(shù)是string類型的話,如#id就要把Dom文檔樹去查找。對于html的片斷就得生成Dom元素。我們再進一步,傳入的單個Dom元素或Dom元素集合參數(shù)又是從那里來的?我們可以通過Dom元素的直接或間接的查找元素的方式。
這一部分首先分析如何從html的片斷就得生成Dom元素,然后分析jQuery是如何通過直接或間接的方式在在Dom樹中找到dom元素,第三就是分析基于CSS1~CSS3的CSS selector。
Init方法中通過jQuery.clean([match[1]], context);來實現(xiàn)把html片斷轉(zhuǎn)換成Dom元素,這是一個靜態(tài)方法:
// 把html轉(zhuǎn)換成Dom元素,elems多個html string 的數(shù)組
clean : function(elems, context) {
var ret = [];
context = context || document;//默認的上下文是document
//在IE中!context.createElement行不通,因為它返回對象類型
if (typeof context.createElement == 'undefined')
//這里支持context為jQuery對象,取第一個元素。
context = context.ownerDocument || context[0]
&& context[0].ownerDocument || document;
jQuery.each(elems, function(i, elem) {
// 把int 轉(zhuǎn)換成string的最高效的方法
if (typeof elem == 'number')elem += '';
if (!elem) return;// 為'',undefined,false等時返回
if (typeof elem == "string") {// 轉(zhuǎn)換html為Dom元素
// 修正 "XHTML"-style 標(biāo)簽,對于如<div/>的形式修改為<div></div>
//但是對于(abbr|br|col|img|input|link|meta|param|hr|area|embed)
//不修改 。front=(<(\w+)[^>]*?)
elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag) { return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)? all: front + "></" + tag+ ">";} );
// 去空格,否則indexof可能會出不能正常工作
var tags = jQuery.trim(elem).toLowerCase(),
div = context.createElement("div");//在上下文中創(chuàng)建了一個元素<div>
// 有些標(biāo)簽必須是有一些約束的,比如<option>必須在<select></select>中間
// 下面的代碼在大部分是對<table>中子元素進行修正。數(shù)組中第一個元素為深度 var wrap =
//<opt在開始的位置上(index=0)就返回&&后面的數(shù)組,這是對<option>的約束
!tags.indexOf("<opt")&& [1, "<select
multiple='multiple'>","</select>"]
//<leg 必須在<fieldset>內(nèi)部
|| !tags.indexOf("<leg")&& [1, "<fieldset>", "</fieldset>"]
//thead|tbody|tfoot|colg|cap必須在<table>內(nèi)部
|| tags.match(/^<(thead|tbody|tfoot|colg|cap)/)
&& [1, "<table>", "</table>"]
//<tr在<tbody>中間
|| !tags.indexOf("<tr")&& [2, "<table><tbody>", "</tbody></table>"]
//td在tr中間
(!tags.indexOf("<td") || !tags.indexOf("<th"))&& [3,
"<table><tbody><tr>","</tr></tbody></table>"]
//col在<colgroup>中間
|| !tags.indexOf("<col")&& [2,
"<table><tbody></tbody><colgroup>","</colgroup></table>"]
//IE中 link script不能串行化 ?
|| jQuery.browser.msie&& [1, "div<div>", "</div>"]
//默認不修正
|| [0, "", ""];
// 包裹html之后,采用innerHTML轉(zhuǎn)換成Dom
div.innerHTML = wrap[1] + elem + wrap[2];
while (wrap[0]--)
// 轉(zhuǎn)到正確的深度,對于[1, "<table>","</table>"],div=<table>
div = div.lastChild;
// fragments去掉IE對<table>自動插入的<tbody>
if (jQuery.browser.msie) {
// 第一種情況:tags以<table>開頭但沒有<tbody>。在IE中生成的元素中可能會自動
// 加的<tbody> 第二種情況:thead|tbody|tfoot|colg|cap為tags,
// 那wrap[1] == "<table>" .tbody不一定是tbody,也有可能是thead等等
var tbody = !tags.indexOf("<table")&& tags.indexOf("<tbody") < 0
? div.firstChild&& div.firstChild.childNodes
: wrap[1] == "<table>"&& tags.indexOf("<tbody") < 0
? div.childNodes: [];
// 除去<tbody>
for (var j = tbody.length - 1;j >= 0; --j)
if (jQuery.nodeName(tbody[j],
"tbody")&&!tbody[j].childNodes.length) tbody[j].parentNode.removeChild(tbody[j]);
//使用innerHTML,IE會去開頭的空格節(jié)點的,加上去掉的空格節(jié)點
if (/^\s/.test(elem)) div.insertBefore(context.createTextNode
(elem.match(/^\s*/)[0]),div.firstChild);
}
elem = jQuery.makeArray(div.childNodes);//elem從字符轉(zhuǎn)換成了數(shù)組
}
//采用===0,因為form,select都有length屬性。這里主要是為了form,select進
//行下面的if else 處理。對于其它的length === 0的,也根本就不要加入到ret中。
if (elem.length === 0&& (!jQuery.nodeName(elem, "form")
&& !jQuery.nodeName(elem, "select")))
return;
//不是(類)數(shù)組的形式的元素,或是form元素或是select元素(這兩個可以看作類數(shù)組)
if (elem[0] == undefined|| jQuery.nodeName(elem, "form")|| elem.options)
ret.push(elem);
else// 對于elems是array-like的集合
ret = jQuery.merge(ret, elem);
});
//上面的each中把有效的元素都加入到ret,現(xiàn)在只要返回就得到轉(zhuǎn)換的Dom元素數(shù)組
return ret;
},
在上面的代碼中,我們可以看出對于elems, context的參數(shù)的支持是多種形式的,elems可以為(類)數(shù)組的形式,還可以采用對象的形式。數(shù)組中的元素或?qū)ο蟮膶傩钥梢允腔旌闲蔚?,?/span>string,ojbect,甚至(類)數(shù)組的形式。對于數(shù)字類型,會轉(zhuǎn)換在string形,除string形之外的都放入返回的數(shù)組中,當(dāng)然對于集合的形式,那就會取集合中每個元素。
對于string的形式就轉(zhuǎn)換成Dom元素的形式,之后存到返回的數(shù)組中。這是這個函數(shù)的主要任務(wù)。對于把html轉(zhuǎn)換成Dom元素,這里采用innerHTML把html掛到Dom文檔樹中。這樣就轉(zhuǎn)換成了Dom元素。
有些html標(biāo)簽片斷是有約束的,比如<td>xx</td>,它必須存在table的tr中,也就是說在要進行html的標(biāo)簽片斷的修正。這也是上面的代碼處理的重點。
文章來自:精靈部落
作者:prk(彭仁夔) QQ:546711211 email:sjkjs155@126.com 水平有限,難免有錯誤,請多多請教
如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會為你解答??! 點擊進入論壇