其他解决方案没有给我我需要的东西。
简答
我的答案是:
$('#output *:not(:has(*)):visible').text()
plunkr
TL;DR
marcgg解决方案的问题
你不应该询问某个根元素下所有元素的文本..
为什么? - 它将重复输出并忽略隐藏标志
让我们看一个简单的例子
<div id="output" class="my-root">
<div class="some-div">
<span class="first" style="display:none"> hidden text </span>
<span class="second" > visible text </span>
</div>
<div>
现在如果我这样做$('#output').children(":visible").text()
我会得到.some-div 和.second..
事实上.some-div 对我来说并不重要..
当我在这些元素上请求 text() 时,.some-div 也会返回隐藏文本..
所以从技术上讲,marcgg 的解决方案是错误的恕我直言......
我回答的原因
现在,为了正确回答这个问题,我们必须做出一个假设。对我来说,这似乎足够合理。
假设是文本只出现在叶元素中..
所以我们不会看到这样的:
<div id="output" class="my-root">
<div class="some-div">
<span class="first" style="display:none"> hidden text </span>
<span class="second" > visible text </span>
</div>
some text here..
<div>
为什么这个假设对我来说似乎是合理的?两个原因:
- 因为很难维护以这种方式构建的页面 - 并且随着时间的推移,有经验的人会学习并避免它。
- 很容易将您的 html 转换为这样的结构。只需用跨度包装父母的文字。所以即使这个假设现在不存在,也很容易实现。
有了这个假设,你要做的是请求所有的叶子元素(没有子元素的元素),过滤掉可见的元素,然后请求它们的文本..
$('#output *:not(:has(*)):visible').text()
这应该会产生正确的结果。
必须在叶子元素之外有文字吗?
cmets 建议有时您只需要在叶子元素之外添加文本
<div> This is some <strong style="display:none"> text </strong> </div>
如您所见,您有<strong> 作为叶子,并且在此示例中通常在其外部放置文本。
您可以使用我上面建议的解决方法来解决它。但是如果您不能呢?
您可以克隆 dom,然后删除所有隐藏的元素。
这里的问题是,为了让:visible 选择器或:hidden 选择器工作,我必须在文档上有 dom 元素(这意味着用户实际上可以看到)。
所以,这种方法有一些副作用,所以要小心。
这是一个例子
对于这个 html
<div id="output" class="my-root">
<span>
some text <strong style="display:none">here.. </strong>
</span>
</div>
这个javascript有效
$(function(){
var outputClone = $('#output').clone();
$('#output :hidden').remove();
console.log($('#output').text()); // only visible text
$('#output').replaceWith(outputClone);
console.log($('#output').text()); // show original state achieved.
})
见plunker here
如前所述 - 副作用可能看起来像瞬间闪烁,或一些应该运行的初始化脚本。有些可能会通过一些原始想法来避免(大小为 1px/1px 的 div 包含原始内容旁边的克隆?)取决于你的场景。