IE 在创建 DOM 树时会忽略某些空白字符
来源: 阅读:1037 次 日期:2015-04-22 11:03:05
温馨提示: 小编为您整理了“IE 在创建 DOM 树时会忽略某些空白字符”,方便广大网友查阅!

标准参考

Node(节点)不仅包括元素节点,也包含文本节点、注释节点、属性节点等等,节点的类型可以使用 nodeType 来区分。

在 HTML 源代码中,位于标签之内以及标签之间的文本(包括空白字符)将被创建为文本节点。

关于 Node 的更多信息,请参考 DOM-1 Core Interface Node 及 DOM-2 Core Interface Node 中的内容。

关于 Text 的更多信息,请参考 DOM-2 Core Interface Text 中的内容。

问题描述

IE 在创建 DOM 树时,会忽略某些空白字符,因此会比其他浏览器少创建一些文本节点。反过来说,同样的一篇文档,其他浏览器将比 IE 多创建一些文本节点。

造成的影响

用户针对 IE 设计的脚本如果使用节点对象的 nodeList、firstChild、lastChild、previousSibling 或 nextSibling 方法,可能会因为此问题而无法在其他浏览器中达到相同的目的,如脚本执行出错,或对错误的目标对象进行了操作。

受影响的浏览器

IE6 IE7 IE8

问题分析

分析以下代码:

...

<!--测试元素-->

<div id="a"> <div>div</div> <span id="b">span</span> <span>span</span> </div>

<!--脚本输出-->

<pre>

<script>

//获取父元素。

var $a=document.getElementById("a");

//测试 childNodes。

var nodeList=$a.childNodes;

var string="";

for(var i=0;i<nodeList.length;i++)string+=nodeList[i].nodeType;

document.writeln("nodeList: "+string);

//测试 firstChild。

document.writeln("firstChild: "+$a.firstChild.nodeType);

//测试 lastChild。

document.writeln("lastChild: "+$a.lastChild.nodeType);

//获取子元素。

var $b=document.getElementById("b");

//测试 previousSibling。

document.writeln("previousSibling: "+$b.previousSibling.nodeType);

//测试 nextSibling。

document.writeln("nextSibling: "+$b.nextSibling.nodeType);

//显示 innerHTML。

alert("|"+$a.innerHTML+"|");

</script>

</pre>

...

注意以上代码,外层 DIV 标签内的各标签间有空格符。空格符被标记为红色。

根据规范中的描述,脚本的预计输出情况如下:

第一行输出应该是“nodeList: 3131313”,因为该元素内的节点共有 7 个:3 个元素节点穿插在 4 个文本节点之间。

第二行输出应该是“firstChild: 3”,第一个节点是文本节点。

第三行输出应该是“lastChild: 3”,最后一个节点也是文本节点。

第四行输出应该是“previousSibling: 3”。本次的目标元素(SPAN[id=b])的前一个节点是文本节点。

第五行输出应该是“nextSibling: 3”,原因同上。

这段代码在不同的浏览器环境中的表现:

IE其他浏览器

nodeList:113133131313

firstChild:13

lastChild:33

previousSibling:13

nextSibling:33

最后弹出 DIV[id=a] 元素的 innerHTML 为:

IE

|<DIV>div</DIV><SPAN id=b>span</SPAN> <SPAN>span</SPAN> |

其他浏览器:

| <div>div</div> <span id="b">span</span> <span>span</span> |

对原代码中的“测试元素部分”进行改动后(将其中第二个 SPAN 更换为 DIV 元素):

...

<!--测试元素-->

<div id="a"> <div>div</div> <span id="b">span</span> <div>div</div> </div>

...

再次测试,各浏览器表现如下:

IE6 IE7 IE8Firefox Chrome Safari Opera

nodeList:11313131313

firstChild:13

lastChild:13

previousSibling:13

nextSibling:33

最后弹出 DIV[id=a] 元素的 innerHTML 为:

IE

|<DIV>div</DIV><SPAN id=b>span</SPAN>

<DIV>div</DIV>|

其他浏览器:

| <div>div</div> <span id="b">span</span> <div>div</div> |

可见:IE 在生成 DOM 树时,忽略了一些空白字符,从而比其他浏览器少创建了一些文本节点。这导致在使用 nodeList、firstChild、lastChild、previousSibling 或 nextSibling 方法时,在 IE 和其他浏览器中得到的结果不一致。

解决方案

1. 没有必要时尽量去掉各标签之间的空白字符。

因为页面脚本多是对“元素节点”进行操作,因此只要保证各元素之间没有文本节点(即源代码中的标签之间没有空白字符——包括空格符、换行符、制表符),就能使上述各属性在各浏览器中的行为一致。如:

<div id="a"><div>div</div><span id="b">span</span><span>span</span></div>

另外,使用脚本创建并顺次添加的元素,他们本身就是紧密相联的,各元素之间并没有文本节点,因此这种情况也不必担心上述兼容性问题,如:

...

var $a=document.createElement("div");

...

var $b=document.createElement("div");

...

document.body.appendChild($a);

document.body.appendChild($b);

...

$a.nextSibling.className="foo";

...

上述代码中,'$a.nextSibling' 在所有浏览器中都将是 $b。

2. 在获取节点时做类型判断。

无法保证各元素之间没有文本节点时,则需要在针对节点的操作上添加类型判断,如:

function getPreviousElementSibling ($target) {

var $previousNode = $target.previousSibling;

while ($previousNode && $previousNode.nodeType!=1) {

$previousNode = $previousNode.previousSibling;

}

return $previousNode;

}

另外,在非IE中,还可以使用 Element Traversal Specification 草案中提到的 previousElementSibling 和 nextElementSibling 获取元素节点,例如:以 Element.nextElementSibling 取得与元素 Element 的相邻的下一个元素节点。

更多信息请查看IT技术专栏

更多信息请查看脚本栏目
由于各方面情况的不断调整与变化, 提供的所有考试信息和咨询回复仅供参考,敬请考生以权威部门公布的正式信息和咨询为准!
关于我们 | 联系我们 | 人才招聘 | 网站声明 | 网站帮助 | 非正式的简要咨询 | 简要咨询须知 | 加入群交流 | 手机站点 | 投诉建议
工业和信息化部备案号:滇ICP备2023014141号-1 云南省教育厅备案号:云教ICP备0901021 滇公网安备53010202001879号 人力资源服务许可证:(云)人服证字(2023)第0102001523号
云南网警备案专用图标
联系电话:0871-65317125(9:00—18:00) 获取招聘考试信息及咨询关注公众号:
咨询QQ:526150442(9:00—18:00)版权所有:
云南网警报警专用图标
Baidu
map