首页 / 脚本样式 / jQuery / Jquery源码分析---构建Jquery的Dom元素
Jquery源码分析---构建Jquery的Dom元素2010-12-15prk(彭仁夔)在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>&l t;/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;
},
在 上面的代码中,我们可以看出对于elems, context的参数的支持是多种形式的, elems可以为(类)数组的形式,还可以采用对象的形式。数组中的元素或对象 的属性可以是混合形的,如string,ojbect,甚至(类)数组的形式。对于数字类 型,会转换在string形,除string形之外的都放入返回的数组中,当然对于集合 的形式,那就会取集合中每个元素。对于string的形式就转换成Dom元素 的形式,之后存到返回的数组中。这是这个函数的主要任务。对于把html转换成 Dom元素,这里采用innerHTML把html挂到Dom文档树中。这样就转换成了Dom元素 。有些html标签片断是有约束的,比如<td>xx</td>,它必 须存在table的tr中,也就是说在要进行html的标签片断的修正。这也是上面的 代码处理的重点。