【问题标题】:Why Does IE11 Handle Node.normalize() Incorrectly for the Minus Symbol?为什么 IE11 对减号的 Node.normalize() 处理不正确?
【发布时间】:2014-04-15 18:14:08
【问题描述】:

当我使用 Node.normalize() 函数连接相邻的文本节点时,我遇到了一个问题,即具有某些字符的 DOM 文本节点在 IE 中表现异常。

我创建了一个 Codepen 示例,它允许您重现 IE11 中的错误:http://codepen.io/anon/pen/BxoKH

IE11 中的输出:'- 示例'

Chrome 和早期版本 IE 中的输出:'Test - Example'

如您所见,这会截断减号之前的所有内容,减号显然被视为分隔符,显然是由于 Internet Explorer 11(但不是 IE10 或 IE8,甚至 IE6)。

谁能解释为什么会发生这种情况,有没有人知道导致此问题的其他字符序列?

编辑 - 我编写了一个代码笔,它将测试 Unicode 字符的各个部分以识别导致此行为的字符。它似乎影响的角色比我最初意识到的要多:

http://codepen.io/anon/pen/Bvgtb/ 这会测试 32-1000 的 Unicode 字符并打印那些未通过测试的字符(当节点标准化时截断数据)您可以对其进行修改以测试其他字符范围,但要小心在 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

【问题讨论】:

  • 什么版本的IE?我在 IE8 和 IE10 上都得到了预期的结果,不需要解决方法。
  • 抱歉,IE11,正在测试更多浏览器版本。
  • 事实上,它甚至可以在没有解决方法的情况下在 IE6 中工作:jsbin.com/xoxenara/1 究竟是什么错误?
  • 哇,但是在 IE11 中失败了。
  • 这实际上有一个错误...规范化在 IE 11 中被破坏 connect.microsoft.com/IE/feedback/details/809424/…

标签: javascript html internet-explorer dom


【解决方案1】:

我通过简单地重新实现 JS 中的 normalize 方法创建了一个解决方法,但是为此苦苦挣扎了好几个小时,所以我想我会做一个 SO 帖子来帮助其他人,并希望获得更多信息来帮助满足我的好奇心关于这个浪费了我大部分时间的错误,哈哈。

这是我的解决方法的代码笔,适用于所有浏览器: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;
      }
    });
  });
};

【讨论】:

  • 这实际上并没有正确地填充功能 - 您正在从 DOM 中删除节点,如果您引用了在其他地方删除的 DOM 节点,则它无法正常工作。 #normalize 也会合并你的 DOM 节点引用指针
【解决方案2】:

normalize 代码看起来有点复杂,下面简单一些。它遍历要规范化的节点的兄弟姐妹,收集文本节点,直到它碰到一个元素。然后它调用自己并收集该元素的文本节点,依此类推。

我认为将这两个函数分开可以使代码更简洁(而且更少)。

// 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;
  }
}

【讨论】:

  • 这实际上并没有正确地填充功能 - 您正在从 DOM 中删除节点,如果您引用了在其他地方删除的 DOM 节点,则它无法正常工作。 #normalize 也会合并你的 DOM 节点引用指针。
  • @Dan——请解释“如果你引用了某个被删除的 DOM 节点...#normalize 也会合并你的 DOM 节点引用指针”。我没有在 IE 中看到,对“#normalized”文本节点的引用仍然引用已删除的节点,而node.parentNodenull。或者你说的是XPointers
  • 当节点只有一个孩子时,规范化中的while部分不起作用。
【解决方案3】:

不是确切的答案,但对我的情况有所帮助。

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);
}

【讨论】:

    【解决方案4】:

    这里的其他答案有些冗长且不完整——它们没有遍历完整的 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);
    }
    

    【讨论】:

    • 更多代码,是的,但是所有答案都遍历了传递的节点下方的完整 DOM。
    • 我喜欢这个解决方案。我遇到了一个大问题:如果你的 DOM 很大,这会导致 递归过多 错误
    【解决方案5】:
    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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-05-21
      • 2015-05-17
      • 1970-01-01
      • 2022-12-05
      • 1970-01-01
      • 1970-01-01
      • 2016-08-22
      • 1970-01-01
      • 2021-05-10
      相关资源
      最近更新 更多