jQuery.fn.init()构造函数能够构建jQuery对象,并把匹配的DOM元素存储在jQuery对象内部集合中。jQuery.fn.init()构造函数可以接收单个的DOM元素,也可以接收DOM集合。如果接收的是字符串型ID值,则直接在文档中查找对应的DOM元素,并把它传递给jQuery对象;如果接收的是字符串型HTML片段,则需要把这个字符串片段生成DOM元素。下面我们将重点分析jQuery是如何把HTML片段生成DOM元素的。
在2.3.3节中,我们可以看到jQuery.fn.init()构造器通过jQuery.clean([match[1]], context);语句实现把HTML片断生成DOM元素,jQuery.clean()是一个公共函数。源代码及其注释如下所示。
jQuery.clean()包含三个参数,其中elems和context可以支持多种形式的值。Elems参数可以为数组、类数组、对象结构的形式。数组元素和对象属性可以混合使用。
对于数字类型参数,则会被转换为字符串型,除了字符串型外,其他的都放入返回的数组中,当然对于集合形式只需要读取集合中每个元素即可。
对于字符串型参数,则把它转换成DOM元素,再存入返回的数组中。转换的方式是,把HTML字符串片段赋值给创建的div元素的innerHTML,这样就可以把HTML字符串片段挂到DOM文档树中,从而实现把字符串转换成DOM元素。
在转换过程中,应该考虑HTML语法约定,因为标签嵌套是有严格限制的,例如,<td>必须存在<tr>中。因此在执行转换前,还应该对HTML字符串进行预处理,即修正HTML标签不规范的用法,这也是jQuery.clean()函数的一个重要工作。
广州网站建设,网站建设,广州网页设计,广州网站设计
- //公共函数扩展
- jQuery.extend({
- //把HTML字符串片段转换成DOM元素
- //参数说明:
- //elems参数表示多个HTML字符串片段的数组
- // context参数表示上下文
- // fragment参数表示框架对象
- clean: function( elems, context, fragment ) {
- contextcontext = context || document; //默认的上下文是document
- //在IE中!context.createElement是错误用法,因为它返回的是对象类型,而不是逻辑值,故通过返回类型进行判断
- if ( typeof context.createElement === "undefined" )
- //支持context为jQuery对象,并获取第一个元素
- contextcontext = context.ownerDocument || context[0] && context[0].ownerDocument || document;
- //如果近匹配一个标签,且没有指定框架参数,则直接创建DOM元素,并跳过后面的解析
- if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
- var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
- if ( match )
- return [ context.createElement( match[1] ) ];
- }
- var ret = [], scripts = [], div = context.createElement("div");
- //匹配每一个HTML字符串片段,并为每一个片段执行回调函数
- jQuery.each(elems, function(i, elem){
- if ( typeof elem === "number" ) //把数值转换为字符串的高效方法
- elem += '';
- if ( !elem ) //如果不存在元素,则返回,或者为''、 undefined、false等时也返回
- return;
- //把HTML字符串转换为DOM节点
- if ( typeof elem === "string" ) {
- //统一转换为XHTML严谨型文档的标签形式,如<div/>的形式修改为<div></div>
- //但是对于(abbr|br|col|img|input|link|meta|param|hr|area|embed)不修改
- //front=(<(\w+)[^>]*?)
- elemelem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
- return tag.match(/^(abbr|br|col|img|inpu t|link|meta|param|hr|area|embed)$/i) ?
- all :
- front + "></" + tag + ">";
- });
- // 清除空格,否则indexof可能会出现不能正常工作
- var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();
- //有些标签必须是有一些约束的,如<option>必须在<select></select>中间
- //下面代码大部分是对<table>中的子元素进行修正。数组中第一个元素为深度
- var wrap =
- //约束<option>,<opt在开始位置上(index=0)就返回&&运算符后面的数组
- !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>" ] ||
- !tags.indexOf("<tr") &&
- [ 2, "<table><tbody>", "</tbody></table>" ] ||
- //<tr在<tbody>中间
- //td在tr中间
- //col在<colgroup>中间
- (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
- [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
- !tags.indexOf("<col") &&
- [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
- // IE can't serialize <link> and <script> tags normally
- !jQuery.support.htmlSerialize &&
- //IE中 link script不能串行化
- [ 1, "div<div>", "</div>" ] ||
- //默认不修正
- [ 0, "", "" ];
- // 包裹HTML之后,采用innerHTML转换成DOM
- div.innerHTML = wrap[1] + elem + wrap[2];
- // 转到正确的深度,对于[1, "<table>","</table>"],div=<table>
- while ( wrap[0]-- )
- divdiv = div.lastChild;
- // fragments去掉IE对<table>自动插入的<tbody>
- if ( !jQuery.support.tbody ) {
- //第一种情况:tags以<table>开头但没有<tbody>。在IE生成的元素中可能会自动加<tbody>
- // 第二种情况:thead|tbody|tfoot|colg|cap为tags,那wrap[1] == "<table>"
- var hasBody = /<tbody/i.test(elem),
- tbody = !tags.indexOf("<table") && !hasBody ?
- div.firstChild && div.firstChild.childNodes :
- // tbody不一定是tbody,也有可能是thead等
- wrap[1] == "<table>" && !hasBody ?
- 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 ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
- div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
- //elem从字符转换成了数组
- elem = jQuery.makeArray( div.childNodes );
- }
- //如果是DOM元素,则推入数组,否则就合并数组
- if ( elem.nodeType )
- ret.push( elem );
- else
- ret = jQuery.merge( ret, elem );
- });
- //如果指定了第3个参数,即框架对象,则附加到框架对象上
- //这段是新增加的,用来处理js代码,同时也取消了form的处理
- if ( fragment ) {
- for ( var i = 0; ret[i]; i++ ) {
- if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
- scripts.push( ret[i].parentNode ? ret[i].parentNode. removeChild( ret[i] ) : ret[i] );
- } else {
- if ( ret[i].nodeType === 1 )
- ret.splice.apply( ret, [i + 1, 0].concat (jQuery.makeArray(ret[i]. getElementsByTagName ("script"))) );
- fragment.appendChild( ret[i] );
- }
- }
- //返回脚本
- return scripts;
- }
- //返回DOM元素集合
- return ret;
- },
- //……
- }
上面这段代码实际上最后访问的是一个名为ret的数组,数组中的元素变为DOM元素的对象,而它的innerHTML正好就是刚才的HTML字符串。
广州网站建设,网站建设,广州网页设计,广州网站设计



