第十三课:js操作节点的创建
浏览器提供了多种方法创建节点。比如:document.createElement,innerHTML,insertAdjacentHTML,createContextualFragment。
document.createElement方法
传入一个标签名,返回此类型的元素节点,对于浏览器不支持的标签类型,它也能成功返回。
在IE6-IE8中,它允许用户连同属性一起生成,比如:document.createElement("<div id=aaa></div>"),此方法常用于生成带name属性的input和iframe,因为IE6-IE7下这两种元素的name属性是只读的,不能修改。因此你可以在IE6,7下,创建带有name属性的input和iframe,这样的name就是按照你的意愿设置的。其他标准浏览器不能传入带属性的元素标签,但是可以直接修改。
因此在创建带有name属性的元素时,你可以写一个兼容方法,首先用IE的形式来创建,如果创建出来的元素为null,就说明是其他标准浏览器,那么就使用标准方法创建,创建好了再改变它的name属性值。
innerHTML方法
innerHTML的创建效率比createElement快多倍,而且innerHTML一下子可以生成一大堆的节点。但是同样在IE下有一些兼容性问题要考虑:
IE6-IE8会对用户传入的字符串进行trimLeft操作,本意是智能的去掉没用的空格,但其他标准浏览器忠于用户输入,对应位置要生成文本节点,哪怕是空白文本。
举个例子:div.innerHTML = " <b>1</b><b>2</b> "; div.childNodes.length,IE6-IE8得到3,因为前面的空白文本没去掉了。而其他浏览器得到4,会为每个空白建立文本节点。当然后面的空白文本都会新建文本节点。
IE9以及以下版本下有些元素节点的innerHTML是只读的,不能重写。比如:table。
IE6-IE8下的innerHTML会忽略掉no-scope element。(注释,style,script,link,meta,noscript等功能性的标签称为no-scope element)。想要用innerHTML生成他们,需要在它们之前加上一些东西,比如:文字或其他标签。之后再移除这些文字或者标签。
另外一个众所周知的问题是innerHTML不会执行script标签里面的脚本,其实不完全正确,如果浏览器支持script标签中的defer属性,它就能执行脚本(只有 Internet Explorer 支持 defer 属性,defer 属性可以对脚本执行进行延迟,直到页面加载完成才执行)。
jQuery的处理方法是直接用正则把script标签里面的脚本内容取出来,然后eval执行。
还有一种方式是,动态生成一个script节点,然后把用innerHTML加进去的script节点中的所有属性赋给新节点。
最后一个问题:有的标签不能单独作为div的子元素,比如td,th元素(html的嵌套规则),需要外面包几层(tr,tbody,table),才能放到innerHTML中解释,否则浏览器会把这些当做普通的文本节点生成。
还有一个特点大家可以了解下:div.innerHTML = '<table><tbody><tr></tr>';浏览器会自动补全标签,因此不会出现错误。但是有些标签不会自动补全,所以大家在添加元素的时候,还是写全比较稳妥。
insertAdjacentHTML方法
这个方法使你可以到一个元素的内部的最前面,最后面,这个元素的前面或后面插入html标签字符串生成的节点,它们一一对应jQuery的prepend,append,before,after方法,非常好用,但是兼容性不好。如果浏览器不支持此方法,可以使用createContextualFragment来模拟。
createContextualFragment方法
此方法是Range对象的一个实例方法。它允许我们将字符串转换成文档碎片(不了解的先行百度),然后再由你决定插入到哪里。
除此之外,document.write()也可以创建内容,但是我们动态添加节点时发生在DOM树建完后,所以这个方法不适合。它会重写整个document内容。
这里我聊下jQuery和Zepto类库哪个好的问题。
jQuery中的操作都是使用链式操作,而链式操作,就意味着引用,大家都知道,引用的越多,就代表不能释放的东西也越多,因此内存占用的也越多。对于移动端,我个人还是推荐Zepto,至少现在的手机还没能达到PC的水平。PC端毫无疑问使用jQuery。