关于innerHTML 赋值问题最近发现各大类库都能利用div.innerHTMLHTML片断来生成节点元素,再把它们插入到目
关于innerHTML 赋值问题
最近发现各大类库都能利用div.innerHTML=HTML片断来生成节点元素,再把它们插入到目标元素的各个位置上。这东西实际上就是insertAdjacentHTML,但是IE可恶的innerHTML把这优势变成劣势。首先innerHTML会把里面的某些位置的空白去掉,见下面运行框的结果:(复制运行)
// Move to the right depth
while ( wrap[0]-- )
div = div.lastChild;
//处理IE自动插入tbody,如我们使用$('<thead></thead>')创建HTML片断,它应该返回
//'<thead></thead>',而IE会返回'<thead></thead><tbody></tbody>'
if ( !jQuery.support.tbody ) {
// String was a <table>, *may* have spurious <tbody>
var hasBody = /<tbody/i.test(elem),
tbody = !tags.indexOf("<table") && !hasBody ?
div.firstChild && div.firstChild.childNodes :
// String was a bare <thead> or <tfoot>
wrap[1] == "<table>" && !hasBody ?
div.childNodes :
[];
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 ] );
}
// IE completely kills leading whitespace when innerHTML is used
if ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
//把所有节点做成纯数组
elem = jQuery.makeArray( div.childNodes );
}
if ( elem.nodeType )
ret.push( elem );
else
//全并两个数组,merge方法会处理IE下object元素下消失了的param元素
ret = jQuery.merge( ret, elem );
});
if ( fragment ) {
for ( var i = 0; ret[i]; i++ ) {
//如果第一层的childNodes就有script元素节点,就用scripts把它们收集起来,供后面用globalEval动态执行
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 {
//遍历各层节点,收集script元素节点
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;//由于动态插入是传入三个参数,因此这里就返回了
}
return ret;
},
真是复杂的让人掉眼泪!不过jQuery的实现并不太高明,它把插入的东西统统用clean转换为节点集合,再把它们放到一个文档碎片中,然后用appendChild与insertBefore插入它们。在除了火狐外,其他浏览器都支持insertAdjactentXXX家族的今日,应该好好利用这些原生API。下面是Ext利用insertAdjactentHTML等方法实现的DomHelper方法,官网给出的数据:
Insertion MethodIE7 beta 2IE6FF 1.5Opera 9DOM.7301.35.420.280HTML Fragments.360.380.400.260Template.320.335
.385.220Compiled Template.295.300.350.210
数据来源:《Tutorial:使用DomHelper 创建元素的DOM、HTML片断和模版》
这数据有点老了,而且最新3.03早就解决了在IE table插入内容的诟病(table,tbody,tr等的innerHTML都是只读,insertAdjactentHTML,pasteHTML等方法都无法修改其内容,要用又慢又标准的DOM方法才行,Ext的早期版本就在这里遭遇滑铁卢了)。可以看出,结合insertAdjactentHTML与文档碎片后,IE6插入节点的速度也得到难以置信的提升,直逼火狐。基于它,Ext开发了四个分支方法insertBefore、insertAfter、insertFirst、append,分别对应jQuery的before、after、prepend与append。不过,jQuery还把这几个方法巧妙地调换了调用者与传入参数,衍生出insertBefore、insertAfter、prependTo与appendTo这几个方法。但不管怎么说,jQuery这样一刀切的做法实现令人不敢苛同。下面是在火狐中实现insertAdjactentXXX家族的一个版本:
dom.each({
appendTo: 'append',
prependTo: 'prepend',
insertBefore: 'before',
insertAfter: 'after'
},function(method,name){
dom.prototype[name] = function(stuff){
return dom(stuff)[method](this);
};
});
大致的代码都给出,大家可以各取所需