jQuery的html()函数和原生innerHTML属性比较
不可否认jQuery是一个很犀利的工具,很容易让人对其产生依赖感。不过好的工具不一定是最适合的解决方案,就跟漂亮的女人并一定适合做你老婆的道理是一样的。本篇文章针对jQuery的html()函数和javascript原生innerHTML属性的优缺点做概要比较。
innerHTML属性的优点
- innerHTML是w3c制定的行业标准,几乎所有浏览器都做了支持;
- 作为原生支持,innerHTML在各主流浏览器下的执行效率是很高的;
innerHTML属性的缺点
虽然各个浏览器都实现了innerHTML,但是各个浏览器下innerHTML的行为却有着差异,较为另类的当属IE,IE不同版本表现得也不一样,这样导致innerHTML在IE下,用起来有很多不方便的地方,一个个的说来。
IE6-IE8处理html5标签和属性问题
IE6,IE7,IE8浏览器设置innerHTML属性时会忽略html5属性和标签。IE6-IE8不是不支持html5么?在这些版本IE里设置html5标签有什么意义呢?答案很简单,就算不支持html5的一些效果,至少要让网页的大体布局能够正常显示出来。
解决方案网上有很多资料,也有现成的脚本插件解决这个问题的,主体思路就是利用document.createElement方法创建出html5里的标签来,createElement接口是可以接纳任何标签的,本文不做重复描述了。
IE6-IE7处理标签href和src属性问题
标准模式下, IE6,IE7设置innerHTML属性时会把href,src属性自动转为绝对路径;在IE的怪异模式(Quirks)下,几乎所有IE版本都会不自觉地转换路劲为绝对路径,看借来的代码:
- <!DOCTYPE html>
- <html>
- <head>
- <title></title>
- </head>
- <body>
- <div id="test">
- <a href="#"> test </a>
- </div>
- <div id="result"></div>
- </body>
- </html>
- (function(){
- var test = document.getElementById('test');
- alert(test.innerHTML);// will be '<a href="#"> test </a>'
- var result = document.getElementById('result');
- result.innerHTML = test.innerHTML;
- alert(result.innerHTML)// will be '<a href="http://www.xxx.xxx/xxx.html#"> test </a>' in IE6,IE7 or all IE in Quirks model
- })();
如何解决这个问题呢?在 IE 下使用 getAttribute('href', 2 )方法。 Microsoft 给此方法扩展了第二个参数,可设置为 0、1、2,如果设置为 2 ,则返回属性原始值。
- (function(){
- var test = document.getElementById('test');
- alert(test.innerHTML);
- var result = document.getElementById('result');
- result.innerHTML = test.innerHTML;
- if(/*@cc_on!@*/0 ) { //if ie
- var links1 = test.getElementsByTagName('a');
- var links2 = result.getElementsByTagName('a');
- for(var i = 0, len = links1.length; i < len; ++i ) {
- //利用getAttribute('href', 2)得到的正确值,重新设置href属性
- links2[i].href = links1[i].getAttribute('href', 2);
- }
- }
- alert(result.innerHTML);
- })();
问题是可以这样折中的解决,但是也付出了代价,重新设置href的代价,要是html字符串特别复杂,势必也会影响到性能。代码和解决方法均取之于 怿飞博客的这篇文章,在他的这篇文章中还提到了另外一个跟本文无关的bug,有兴趣的可以去看看。
IE里有些元素的innerHTML是只读的
在IE6,IE7,IE8,IE9里面 col, colGroup, frameSet, html, head, style, table, tBody, tFoot, tHead, title, tr 这几个的innerHTML属性是只读的,不可以赋值,赋值的话就脚本报错。IE10这些标签的innerHTML改成可写的了。
既然在IE6-IE9里这些标签的innerHTML属性是只读的,那么我们尽量避免对这些标签的innerHTML属性赋值,比如说对table的innerHTML可以改为对table父元素(假设是div)的innerHTML属性赋值。
不过有时候我们没办法避免对这些只读属性进行赋值,那么该怎么办呢,网上的解决方案也是一搜一大堆,我们来看看其中一种解决方案:
- var oTable=document.getElementById("test");
- setTableInnerHTML(oTable,"<tr><td>innerHTML</td></tr>");
- function setTableInnerHTML(table, html) {
- if(navigator && navigator.userAgent.match(/msie/i)){
- var temp = table.ownerDocument.createElement('div');
- temp.innerHTML = '<table><tbody>' + html + '</tbody></table>';
- if(table.tBodies.length == 0){
- var tbody=document.createElement("tbody");
- table.appendChild(tbody);
- }
- table.replaceChild(temp.firstChild.firstChild, table.tBodies[0]);
- } else {
- table.innerHTML=html;
- }
- }
这段代码是处理table标签的innerHTML属性的,思路是通过创建临时的支持innerHTML的dom对象,先将html串写到临时dom对象的innerHTML属性中,然后再用replaceChild方法将临时DOM对象的对应子节点替换到table节点里面。其它标签思路类似。
不管怎样解决,都是造成相对来说比较冗余的的代码,所以说IE有时候真就是奇葩,不过其寄生在牛逼的windows系统上,没人能耐他何。
html()函数的优点
看看innerHTML属性的缺点,就知道jQuery中html()函数的优点了,它是兼容所有浏览的,不存在html5标签不支持的问题,不存在href,src属性被转换的问题,不存在某些标签设置不了html串的问题,总之就是一句话,用它基本就万事无忧了,至少功能的实现上是这样。
html()函数的缺点
看来jQuery的html()函数似乎完美无限了,其实不然,它的完美只表现它的功能上,它兼容了所有浏览器,包括IE。但偏偏也是IE,尽管兼容了,性能并不乐观,如果使用html()函数设置大数据量的html串的话,那将是场灾难。
在IE下,html()函数的性能到底低到什么程度?我电脑的配置为"i5 四核,8G内存,IE9",我测试了用html()函数设置2000行4列的table,其平均耗时达到27秒!具体什么原因导致html()在IE下这么慢,个人粗略看过源码,觉得使用try方式是主要原因之一,有兴趣的同学可以深入研究一下。