为什么IE11对Node.normalize()的负号处理不正确?
Why Does IE11 Handle Node.normalize() Incorrectly for the Minus Symbol?
我一直遇到一个问题,当使用Node.normalize()函数连接相邻的文本节点时,具有某些字符的DOM文本节点在IE中表现奇怪。
我已经创建了一个Codepen示例,允许您在IE11中重现错误:http://codepen.io/anon/pen/BxoKH
IE11输出:'-示例'
Chrome和早期版本IE的输出:'Test - Example'
正如你所看到的,这截断了减号之前的所有内容,减号显然被视为分隔字符,显然是由于Internet Explorer 11(但不是IE10,或IE8,甚至IE6)中normalize()的本机实现中的错误。
有没有人能解释为什么会发生这种情况,有没有人知道导致这个问题的其他字符序列?
Edit -我写了一个代码依赖程序,它将测试Unicode字符的部分,以识别导致这种行为的字符。它影响的字符似乎比我最初意识到的要多得多:
http://codepen.io/anon/pen/Bvgtb/这将测试32-1000之间的Unicode字符,并打印那些未通过测试的字符(当节点被规范化时截断数据)。您可以修改它来测试其他范围的字符,但要注意在IE中增加太多的范围,否则它会冻结。
我已经创建了一个IE错误报告和微软报告,能够根据我提供的代码样本重现它。如果你也遇到了这个问题,请投票:https://connect.microsoft.com/IE/feedback/details/832750/ie11-node-normalize-dom-implementation-truncates-data-when-adjacent-text-nodes-contain-a-minus-sign
这里的其他答案有些冗长和不完整—它们没有遍历整个DOM子树。这里有一个更全面的解决方案:
function normalize (node) {
if (!node) { return; }
if (node.nodeType == 3) {
while (node.nextSibling && node.nextSibling.nodeType == 3) {
node.nodeValue += node.nextSibling.nodeValue;
node.parentNode.removeChild(node.nextSibling);
}
} else {
normalize(node.firstChild);
}
normalize(node.nextSibling);
}
我通过简单地在JS中重新实现normalize方法创建了一个解决方案,但为此挣扎了许多小时,所以我想我应该做一个so帖子来帮助其他人,并希望得到更多的信息来帮助满足我对这个浪费了我大部分时间的bug的好奇心,哈哈。
下面是我的解决方案的代码依赖,适用于所有浏览器:http://codepen.io/anon/pen/ouFJa
我的解决方法是基于我在这里找到的一些有用的规范化代码:https://stackoverflow.com/a/20440845/1504529,但已经针对这个特定的IE11错误进行了定制,而不是那个帖子讨论的那个:
这是我测试过的所有浏览器的解决方案,包括IE11
function isNormalizeBuggy(){
var testDiv = document.createElement('div');
testDiv.appendChild(document.createTextNode('0-'));
testDiv.appendChild(document.createTextNode('2'));
testDiv.normalize();
return testDiv.firstChild.length == 2;
}
function safeNormalize(DOMNode) {
// If the normalize function doesn't have the bug relating to minuses,
// we use the native normalize function. Otherwise we use our custom one.
if(!isNormalizeBuggy()){
el.normalize();
return;
}
function getNextNode(node, ancestor, isOpenTag) {
if (typeof isOpenTag === 'undefined') {
isOpenTag = true;
}
var next;
if (isOpenTag) {
next = node.firstChild;
}
next = next || node.nextSibling;
if (!next && node.parentNode && node.parentNode !== ancestor) {
return getNextNode(node.parentNode, ancestor, false);
}
return next;
}
var adjTextNodes = [], nodes, node = el;
while ((node = getNextNode(node, el))) {
if (node.nodeType === 3 && node.previousSibling && node.previousSibling.nodeType === 3) {
if (!nodes) {
nodes = [node.previousSibling];
}
nodes.push(node);
} else if (nodes) {
adjTextNodes.push(nodes);
nodes = null;
}
}
adjTextNodes.forEach(function (nodes) {
var first;
nodes.forEach(function (node, i) {
if (i > 0) {
first.nodeValue += node.nodeValue;
node.parentNode.removeChild(node);
} else {
first = node;
}
});
});
};
不是确切的答案,但对我的情况有帮助。
function safeNormalize(el) {
function recursiveNormalize(elem)
{
for (var i = 0; i < elem.childNodes.length; i++) {
if (elem.childNodes[i].nodeType != 3) {
recursiveNormalize(elem.childNodes[i]);
}
else {
if (elem.childNodes[i].nextSibling != null && elem.childNodes[i].nextSibling.nodeType == 3) {
elem.childNodes[i].nodeValue = elem.childNodes[i].nodeValue + elem.childNodes[i].nextSibling.nodeValue;
elem.removeChild(elem.childNodes[i].nextSibling);
i--;
}
}
}
}
recursiveNormalize(el);
}
规范化代码看起来有点复杂,下面的代码更简单一些。它遍历要规范化的节点的兄弟节点,收集文本节点,直到遇到一个元素。然后它调用自身并收集该元素的文本节点,依此类推。
我认为将这两个函数分开会使代码更简洁(和更少)。
// textNode is a DOM text node
function collectTextNodes(textNode) {
// while there are text siblings, concatenate them into the first
while (textNode.nextSibling) {
var next = textNode.nextSibling;
if (next.nodeType == 3) {
textNode.nodeValue += next.nodeValue;
textNode.parentNode.removeChild(next);
// Stop if not a text node
} else {
return;
}
}
}
// element is a DOM element
function normalise(element) {
var node = element.firstChild;
// Traverse siblings, call normalise for elements and
// collectTextNodes for text nodes
while (node) {
if (node.nodeType == 1) {
normalise(node);
} else if (node.nodeType == 3) {
collectTextNodes(node);
}
node = node.nextSibling;
}
}
function mergeTextNode(elem) {
var node = elem.firstChild, text
while (node) {
var aaa = node.nextSibling
if (node.nodeType === 3) {
if (text) {
text.nodeValue += node.nodeValue
elem.removeChild(node)
} else {
text = node
}
} else {
text = null
}
node = aaa
}
}
- Jquery菜单操作不稳定,定位不正确,存在一般错误
- Amazon S3 REST API大小不正确
- Javascript Reg Exp不正确匹配
- DIV并排,位置不正确
- 仅在IE中,javascript中的时区名称不正确
- 注意:wp_enqueue_script调用不正确.在 Wordpress 调试模式下
- 你能解释一下为什么这个javascript不正确吗
- react路由器使用简单的javascript路由器配置来处理不匹配的路径
- 从int值来看,Javascript日期不正确
- jQuery-迭代不正确?(太长,无法执行)
- 处理“不正确的字符串值”
- 在我的 javascript 项目中获取不正确的值时,将函数作为事件处理程序的回调传递
- Json jQuery 和 php 处理的值不正确
- json对象内部的json处理不正确
- 表单数据中的对象处理不正确
- 在iOS8 Safari中,只读输入处理不正确
- 处理“不正确”从服务格式化JSON
- 角度处理不正确的缓存数据
- 事件类型字段的打字稿事件处理程序函数 - 上下文不正确
- 为什么IE11对Node.normalize()的负号处理不正确?