Почему IE11 обрабатывает узел.normalize () неправильно для символа минус?
У меня возникла проблема, когда текстовые узлы DOM с определенными символами ведут себя странно в IE при использовании узла.функция normalize () для объединения соседних текстовых узлов.
Я создал пример Codepen, который позволяет воспроизводить ошибку в IE11:http://codepen.io/anon/pen/BxoKH
вывод в IE11: '- Example'
вывод в Chrome и более ранних версиях IE:'Test - Example'
Как вы можете видеть, это усекает все до символа минус, который, по-видимому, рассматривается как разделяющий символ, по-видимому, из-за ошибки в собственной реализации normalize() в Internet Explorer 11 (но не IE10, или IE8, или даже IE6).
может ли кто-нибудь объяснить, почему это происходит, и кто-нибудь знает о других последовательностях символов, которые вызывают эту проблему?
изменить - я написал codepen, который будет тестировать разделы символов Юникода для определите символы, вызывающие такое поведение. Кажется, это влияет на гораздо больше символов, чем я изначально понял:
http://codepen.io/anon/pen/Bvgtb/ Это проверяет символы Юникода из 32-1000 и печатает те, которые не проходят тест (усекают данные при нормализации узлов) вы можете изменить его, чтобы проверить другие диапазоны символов, но будьте осторожны, чтобы увеличить диапазон слишком много в IE или он замерзнет.
Я создал отчет об ошибке IE и Microsoft отчеты, способные воспроизвести его на основе образца кода, который я предоставил. Проголосуйте за это, если вы также испытываете эту проблему: https://connect.microsoft.com/IE/feedback/details/832750/ie11-node-normalize-dom-implementation-truncates-data-when-adjacent-text-nodes-contain-a-minus-sign
5 ответов
другие ответы здесь несколько многословны и неполны - они не ходят по полному под-дереву 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);
}
Я создал обходной путь, просто переопределив метод normalize в JS, но боролся с этим в течение многих часов, поэтому я решил сделать так, чтобы помочь другим людям, и, надеюсь, получить больше информации, чтобы помочь удовлетворить мое любопытство об этой ошибке, которая потратила большую часть моего дня, ха-ха.
вот codepen с моим обходным путем, который работает во всех браузерах: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);
}
код нормализации выглядит немного запутанным, следующее немного проще. Он пересекает братьев и сестер узла, который необходимо нормализовать, собирая текстовые узлы, пока не попадет в элемент. Затем он вызывает себя и собирает текстовые узлы этого элемента и так далее.
Я думаю, что seprating двух функций делает для более чистого (и намного меньше) кода.
// 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
}
}