您现在的位置: 365建站网 > 365学习 > Jquery源码分析之二:生成Dom元素

Jquery源码分析之二:生成Dom元素

文章来源:365jz.com     点击数:268    更新时间:2009-09-14 10:31   参与评论

3、构建jQueryDom元素

jQuery.fn.init函数中,最终的结果是把Dom元素放到jQuery对象的集合,我们可以传入单个Dom元素或Dom元素集合直接把其存到jQuery对象的集合。但是如果第一个参数是string类型的话,如#id就要把Dom文档树去查找。对于HTML的片断就得生成Dom元素。我们再进一步,传入的单个Dom元素或Dom元素集合参数又是从那里来的?我们可以通过Dom元素的直接或间接的查找元素的方式。

这一部分首先分析如何从html的片断就得生成Dom元素,然后分析jQuery是如何通过直接或间接的方式在在Dom树中找到dom元素,第三就是分析基于CSS1~CSS3CSS 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')

           //这里支持contextjQuery对象,取第一个元素。

       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") {// 转换htmlDom元素

       // 修正 "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>"]

     //tdtr中间

     (!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|captags

// 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// 对于elemsarray-like的集合

    ret = jQuery.merge(ret, elem);

});

   //上面的each中把有效的元素都加入到ret,现在只要返回就得到转换的Dom元素数组

return ret;

},

在上面的代码中,我们可以看出对于elems, context的参数的支持是多种形式的,elems可以为(类)数组的形式,还可以采用对象的形式。数组中的元素或对象的属性可以是混合形的,如string,ojbect,甚至(类)数组的形式。对于数字类型,会转换在string形,除string形之外的都放入返回的数组中,当然对于集合的形式,那就会取集合中每个元素。

对于string的形式就转换成Dom元素的形式,之后存到返回的数组中。这是这个函数的主要任务。对于把html转换成Dom元素,这里采用innerHTMLhtml挂到Dom文档树中。这样就转换成了Dom元素。

有些html标签片断是有约束的,比如<td>xx</td>,它必须存在tabletr中,也就是说在要进行html的标签片断的修正。这也是上面的代码处理的重点。

文章来自:精灵部落

作者:prk(彭仁夔)   QQ546711211   email:sjkjs155@126.com   水平有限,难免有错误,请多多请教

 

 

Tag标签: Jquery

如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛


发表评论 (268人查看0条评论)
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
用户名: 验证码: 点击我更换图片
最新评论
------分隔线----------------------------