【问题标题】:Need jQuery text() function to ignore hidden elements需要 jQuery text() 函数来忽略隐藏元素
【发布时间】:2011-11-14 23:50:48
【问题描述】:

我有一个这样的 div 设置:

<div id="test"> <p>Hello</p> <p style="display: none">Goodbye</p> </div>

编辑:澄清一下,这是最简单的例子。 div 可以有任意数量的 n 个深度嵌套的子级。

$('#test').getText() 返回“你好,再见”。这是在 Firebug 中测试的一个衬里:jQuery('&lt;div id="test"&gt; &lt;p&gt;Hello&lt;/p&gt; &lt;p style="display: none"&gt;Goodbye&lt;/p&gt; &lt;/div&gt;').text()

这似乎是因为 jQuery 内部使用的 textContent(对于非 IE)返回隐藏元素作为文本的一部分。哼。

有没有办法返回忽略 display:none'd 元素的文本内容?基本上,我试图模仿用鼠标突出显示 div 并复制到系统剪贴板的文本。这会忽略隐藏的文本。

有趣的是,如果您创建一个选择范围并从中获取文本,那么它也会在 display:none 元素中返回文本。

var range = document.body.createTextRange();
range.moveToElementText($('#test')[0]);
range.select();

console.log(range.toString()); // Also logs Hello Goodbye!

因此,就 display:none 元素而言,创建文档选择范围似乎与用鼠标突出显示不同。我该如何解决这个肮脏的泡菜难题?

编辑:建议使用.filter(':visible').text,但它不适用于这种情况。我需要返回的文本与鼠标选择的内容完全相同。比如:

$('<div>test1 <p>test2</p>\r\n <b>test3</b> <span style="display:none">none</span></div>').appendTo(document.body).children().filter(':visible').text()

返回

"test2test3"

当我真正想要的输出是

test1 test2
 test3

换行符、空格和所有,来自\r\n

【问题讨论】:

    标签: javascript jquery innertext


    【解决方案1】:

    使用.filter(":visible")过滤元素。

    或者使用这个:

    $("#test :visible").text();
    

    jQuery documentation 建议我们改用.filter()

    因为:visible 是一个 jQuery 扩展,而不是 CSS 规范的一部分, 使用 :visible 的查询无法利用原生 DOM querySelectorAll() 方法提供的性能提升。为了在使用 :visible 选择元素时获得最佳性能,首先使用纯 CSS 选择器选择元素,然后使用 .filter(":visible")

    【讨论】:

    • 澄清问题,元素嵌套深度是可变的。
    • 然后改用这个$("#text :visible").text()
    • 不幸的是这还不够,我认为我的问题很模糊,更新了
    • 然后.remove()隐藏元素得到div的文字
    • 有趣。我实际上是要说你在.remove() 之前先使用.clone(),但我似乎无法让它在jsfiddle 上工作。但如果它现在有效,那么恭喜。
    【解决方案2】:

    在你的选择器中使用:visible

    $("#test > p:visible").text()
    

    一个函数示例:

    -- 编辑:

    http://jsfiddle.net/8H5ka/(在 Chrome 上工作它在结果中显示“Hello”)

    如果上述方法不起作用:

    http://jsfiddle.net/userdude/8H5ka/1/

    【讨论】:

    • 这需要适用于任何任意元素并返回与突出显示 div 完全相同的输出。 div 可以有任意数量的嵌套子级。
    • @Jared,已编辑。安迪:以上怎么不符合这个目的?
    • 编辑主要问题以澄清需求
    【解决方案3】:

    如果空间不是主要问题,您可以复制标记、删除隐藏元素并输出该文本。

    var x = $('#test').clone();
    x.filter(':not(:visible)').remove();
    return x.text();
    

    【讨论】:

    • 请注意,由于 x 仅包含 #test 而不是它的子级,所有这一切都会在 #test 不可见时将其删除。你需要做的是x.find('*').not(':visible').remove()
    • 请记住,如果您克隆了某些内容但没有将其附加到 DOM 并使其可见,那么x.find('*').not(':visible').remove() 将删除 'x' 中的所有内容(文本节点除外,因为 find() 不包括他们)。
    【解决方案4】:

    我遇到了这个问题,发现了这个问题,看来实际的解决方案是基于提供的答案,但实际上并没有写出来。所以这是一个适用于我的情况的完整解决方案,它与 OP 相同,但额外规定元素可能由于基于 DOM 位置的外部样式而不可见。示例:

    <style>.invisible-children span { display: none; }</style>
    <div class="invisible-children">
      <div id="test">Hello <span>Goodbye</span></div>
    </div>
    

    解决办法是:

    1. 克隆整个对象。
    2. 原地移除不可见物体;如果我们在移除不可见对象之前将 #test 从 DOM 中取出,jQuery 可能不知道它们是不可见的,因为它们将不再符合 CSS 规则。
    3. 获取对象的文本。
    4. 用我们制作的克隆替换原始对象。

    代码:

    var $test = $('#test');
    // 1:
    var $testclone = $test.clone();
    // 2: We assume that $test is :visible and only remove children that are not.
    $test.find('*').not(':visible').remove();
    // 3:
    var text = $test.text();
    // 4:
    $test.replaceWith($testclone);
    // Now return the text...
    return text;
    // ...or if you're going to keep going and using the $test variable, make sure
    // to replace it so whatever you do with it affects the object now in DOM and
    // not the original from which we got the text after removing stuff.
    $test = $testclone;
    $test.css('background', 'grey'); // For example.
    

    【讨论】:

      【解决方案5】:

      这是我使用 MooTools 的做法:

      $extend(Selectors.Pseudo, {
          invisible: function() {
              if(this.getStyle('visibility') == 'hidden' || this.getStyle('display') == 'none') {
                  return this;
              }
          }
      });
      
      Element.implement({
          getTextLikeTheBrowserWould = function() {
              var temp = this.clone();
              temp.getElements(':invisible').destroy();
              return temp.get('text').replace(/ |&amp;/g, ' ');
          }
      })
      

      【讨论】:

        【解决方案6】:

        我搜索并找到了这个问题,但没有解决方案。 对我来说,解决方案就是退出 jquery 来使用 DOM:

        var $test = $('#test').get(0).innerText
        

        或者如果选择器数组中的元素不止一个,您需要一个 for 循环和一个合并,但我想大多数时候它是您需要的第一个版本。

        var $test = $('#test').get().map(a => a.innerText).join(' ');
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-06-11
          • 1970-01-01
          • 2018-08-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多