【问题标题】:HTML/jQuery - Preventing empty text nodesHTML/jQuery - 防止空文本节点
【发布时间】:2013-09-12 08:35:12
【问题描述】:

我试图防止在添加时创建空文本节点

  • 换行符,
  • 空格(包括不间断空格)
  • 标签

到我的 HTML 结构。

例如。

<div><div>    <!-- Node not created -->
<div>
                <!-- Node created -->
<div>

例如1。

<div><div>    <!-- Node not created -->
<div> <div>     <!-- Node created -->

例如2。

<div><div>    <!-- Node not created -->
<div>            <!-- Node created -->
    <div>
                 <!-- Node created -->
    </div>    
<div>            <!-- Node created -->

在这里,为了更好的不朽: 看看第一个 &lt;DIV&gt;s 会发生什么 - jsFiddle

【问题讨论】:

  • 这样做有什么特殊原因
  • 为什么?就因为你担心浏览器内存中有一些空的文本节点?
  • 它有助于内联块元素
  • 嗯,最终目标是用其他内容替换非空文本节点......所以我正在寻找所有文本节点的 DOM,但我的函数替换了所有文本节点。包括空的。
  • 您将如何创建这些节点?它们会在 jQuery 中使用某种形式的输入来创建吗?

标签: jquery html textnode


【解决方案1】:

每次操作 DOM 时,向父节点调用 node.normalize(),它就会完成这项工作。

Node.normalize查看更多信息

更新

根据您提供的小提琴,我深入研究了这个问题,我根据您的 html 结构在 Chrome 29 中运行以下代码。

var i = 0;
function traverse(node){
    if (node.firstChild) {
        traverse(node.firstChild);
    }

    if (node.nodeType === 3) {
        console.log("text node " + ++i + ": " + node.nodeValue);
        if (node.nodeValue !== '') {
            console.log("text node " + i + " is not null");
        }
        if (node.nodeValue.match(/(\r\n|\r|\n)+/g)) {
            console.log("nonsense node");
        }
    }

    if (node.nextSibling) {
        traverse(node.nextSibling);
    }
}
document.addEventListener("DOMContentLoaded", doTraverse);

function doTraverse(){
    traverse(document.getElementsByClassName("selector")[0]);
}

并得到这些结果:

text node 1: 

text node 1 is not null
nonsense node
text node 2: 

text node 2 is not null 
nonsense node 
text node 3: 

text node 3 is not null 
nonsense node 
text node 4: 

text node 4 is not null 
nonsense node 
text node 5: 
            text

text node 5 is not null 
text node 6: a paragraph 
text node 6 is not null
text node 7: 

text node 7 is not null 
nonsense node 
text node 8: a paragraph 
text node 8 is not null 
text node 9: a paragraph 
text node 9 is not null 
text node 10: 
             more text

text node 10 is not null 
text node 11: 


text node 11 is not null 
nonsense node 

令我们惊讶的是,empty 文本节点比我们预期的要多得多。但是,如果我们在 Chrome 的检查器中检查这些元素,一切似乎都正常。我猜 Chrome 在渲染引擎中优化了这个问题,但在 DOM 中没有。

我们清楚地知道,那些empty 文本节点实际上包含linebreaks,这使您的代码无法按预期工作。所以如果你确实想删除那些文本节点,你可以遍历 DOM ,找到它们并删除它们(这将非常低效,我很欣赏更好的解决方案)。

顺便说一句,在这种情况下,node.normalize() 对您不起作用,因为它只会删除真正的空文本节点。

【讨论】:

  • 所以在我的例子中我应该在哪里添加这个命令?? jsFiddle
  • 我没有在你的小提琴中看到任何空的text node
  • 在第一个 div 之间有那些奇怪的节点!!
  • 如何删除无意义的文本节点?规范化不会删除它们。
【解决方案2】:

如果您认为有必要,请添加 cmets

<ul>
  <li>one</li><!--
  --><li>two</li><!--
  --><li>three</li>
</ul>

这将使空白被注释掉并且不插入文本节点

来自http://css-tricks.com/fighting-the-space-between-inline-block-elements/

例如 1

<div><div><!-- 
--><div><!--

--><div>

例如2

<div><div><!--
--><div><!-- --><div>

例如 3

<div><div><!--
--><div><!--
    --><div><!--

    --></div><!--    
--><div>  

使您的标记相当难看,但会删除文本节点

【讨论】:

  • 我看不到添加这些标记以具有注释节点而不是空文本节点的一种情况。
  • 当您需要将两个 display: inline-block; 元素并排放置并且不希望在不是由填充或边距生成的元素之间存在间隙时。
【解决方案3】:

你可以在你的 DOM 上运行一个简单的清理函数:

function cleanNode(node) {
 var child;
 for (var i = node.childNodes.length; i--;) {
  child = node.childNodes[i];
  // If commentt/textNode and has no non-whitespace character in it, delete it.
  if (child.nodeType === 3 || child.nodeType === 8 && !/\S/.test(child.nodeValue)) {
   node.removeChild(child);
   n--;
  }
  else {
   cleanNode(child);
  } 
 }
}

【讨论】: