Jquery源码分析---构建Jquery的Dom元素
2010-09-14 13:36:44 来源:WEB开发网在jQuery.fn.init函数中,最终的结果是把Dom元素放到jQuery对象的集合,我们可以传入单个Dom元素或Dom元素集合直接把其存到jQuery对象的集合。但是如果第一个参数是string类型的话,如#id就要把Dom文档树去查找。对于html的片断就得生成Dom元素。我们再进一步,传入的单个Dom元素或Dom元素集合参数又是从那里来的?我们可以通过Dom元素的直接或间接的查找元素的方式。
这一部分首先分析如何从html的片断就得生成Dom元素,然后分析jQuery是如何通过直接或间接的方式在在Dom树中找到dom元素,第三就是分析基于CSS1~CSS3的CSS selector。
3.1生成Dom元素
Init方法中通过jQuery.clean([match[1]], context);来实现把html片断转换成Dom元素,这是一个静态方法:
// 把html转换成Dom元素,elems多个html string 的数组
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 转换成string的最高效的方法
if (typeof elem == 'number')elem += '';
if (!elem) return;// 为'',undefined,false等时返回
if (typeof elem == "string") {// 转换html为Dom元素
// 修正 "XHTML"-style 标签,对于如<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");//在上下文中创建了一个元素<div>
// 有些标签必须是有一些约束的,比如<option>必须在<select></select>中间
// 下面的代码在大部分是对<table>中子元素进行修正。数组中第一个元素为深度 var wrap =
//<opt在开始的位置上(index=0)就返回&&后面的数组,这是对<option>的约束
!tags.indexOf("<opt")&& [1, "<select
multiple='multiple'>","</select>"]
//<leg 必须在<fieldset>内部
|| !tags.indexOf("<leg")&& [1, "<fieldset>", "</fieldset>"]
//thead|tbody|tfoot|colg|cap必须在<table>内部
|| 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转换成Dom
div.innerHTML = wrap[1] + elem + wrap[2];
while (wrap[0]--)
// 转到正确的深度,对于[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会去开头的空格节点的,加上去掉的空格节点
if (/^s/.test(elem)) div.insertBefore(context.createTextNode
(elem.match(/^s*/)[0]),div.firstChild);
}
elem = jQuery.makeArray(div.childNodes);//elem从字符转换成了数组
}
//采用===0,因为form,select都有length属性。这里主要是为了form,select进
//行下面的if else 处理。对于其它的length === 0的,也根本就不要加入到ret中。
if (elem.length === 0&& (!jQuery.nodeName(elem, "form")
&& !jQuery.nodeName(elem, "select")))
return;
//不是(类)数组的形式的元素,或是form元素或是select元素(这两个可以看作类数组)
if (elem[0] == undefined|| jQuery.nodeName(elem, "form")|| elem.options)
ret.push(elem);
else// 对于elems是array-like的集合
ret = jQuery.merge(ret, elem);
});
//上面的each中把有效的元素都加入到ret,现在只要返回就得到转换的Dom元素数组
return ret;
},
更多精彩
赞助商链接