【问题标题】:Finding length of text nodes in nested HTML up to a point查找嵌套 HTML 中文本节点的长度直到某一点
【发布时间】:2013-05-25 16:09:31
【问题描述】:

使用这样的 HTML:

<div id="container">                                                                                 
  <p>Lorem ipsum lorem ipsum
    <p>This is the second!
      <span data-attribute="my-span">Hello World</span>
    </p>
  </p>
</div> 

我想找到从容器到我的跨度的文本长度。因此,通过计算后代的指数,我得到了 42 个正确答案。

但如果我有这样的 HTML:

  <div id="container">                                                                                 
      <p>Lorem ipsum lorem ipsum
        <p>This is the second!
          <span data-attribute="my-span">Hello World</span>
        </p>
        Some preceding HTML that I dont want!
      </p>
    </div> 

我不希望字符计数继续我的跨度。我只希望字符数达到我的跨度,所以正确答案仍然是 42。但是通过计算子文本长度,它还会添加到前面的文本和跨度的文本中(这很容易通过减去它来消除从总数中)。

我已经探索了列出 html 并将子字符串设置为我想要的 span 属性,拆分结尾并解析出 html,只留下我想要计算的文本字符。但这似乎过于复杂。

我也在考虑使用 wicked good xpath 之类的东西来查找直到我要查找的节点的所有节点,然后总结文本。

我还查看了仅列出直到某个点的所有文本节点并将它们求和,但它在我的跨度文本之前列出了孩子的前面文本,因此它的求和顺序不正确。

此外,嵌套可能有 n 层深,所以不要假设只有一层。

对实现这一目标的最佳方式有何建议?

【问题讨论】:

  • 我认为最简单的方法是从底部开始,然后在 while 循环中逐步恢复。选择span,并继续计算父母直到你到达容器div
  • @shaun5 父母将包含该文本 - 以及跨度文本,因此需要更复杂的节点计数方法,例如 Jans 解决方案。

标签: javascript jquery dom


【解决方案1】:

一个始终可用的选项是手动遍历 DOM 树。 jQuery 并不擅长处理非元素节点(当我们执行.find('*').contents() 时,似乎所有子节点的后代都列在每个节点的所有子节点之后,而contents 是看到这些节点的唯一方法),但我们可以仍然使用本机 API。另请注意,此处处理空白很棘手(我假设您希望折叠空白以模仿渲染器行为)像这样:

function countCharsUntil(parent, selector, inclusive){
  var done = false;
  return listChars(parent).replace(/\s+/g," ").trim().length;

  function listChars(elem){
    var cn = elem.childNodes;
    var chars = "";
    if(!inclusive && $(elem).is(selector)){
      done = true;
      return ""
    }
    for(var i=0; i<cn.length && !done; i++){
      var child = cn[i];
      switch(child.nodeType){
        case Node.ELEMENT_NODE:
          chars += listChars(child);
          break;
        case Node.TEXT_NODE:
          chars += child.nodeValue;
          break;
      }
    }
    if(inclusive && $(elem).is(selector)){
      done = true;
      return chars;
    }
    return chars;
  }
}

测试:http://jsfiddle.net/8hxb6/1/

请注意,该测试返回 43 个字符以进行独占搜索。这可能是因为您忽略了div&gt;p 中的“ipsum”和div&gt;p&gt;p 中的“This”之间的空格

【讨论】:

    【解决方案2】:

    这个工人

    $(document).ready(function(){
      var tx = $('#container').text().split($('#container span').text())[0].replace(/[\s]{2,}/g,'');
      console.log(tx.length); //42
    });
    

    DEMO

    【讨论】:

    • 不错的技巧,但是如果跨度文本也出现在跨度之外的某个地方怎么办?然后它会破裂!
    • @JanDvorak 他可以更改拆分索引并加入其中的一些,但这是一个基础:P
    • 如果您不知道文本出现了多少次怎么办?我不认为这可以工作。
    • @JanDvorak 你可以看到分割长度以了解它
    • @JanDvorak 是正确的,文本比较方法很脆弱。如果我在我的原件之前包含一个“Hello World”,那么它会找到那个的索引。但我确实喜欢这种方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-08
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-26
    • 1970-01-01
    相关资源
    最近更新 更多