如何使用 jQuery(或 Javascript)获取可见文本?
Posted
技术标签:
【中文标题】如何使用 jQuery(或 Javascript)获取可见文本?【英文标题】:How do I get just the visible text with jQuery (or Javascript)? 【发布时间】:2010-12-23 04:51:51 【问题描述】:我有网站可以转换Japanese Kanji into Romaji (roman letters):
输出显示和隐藏用户需要根据输入标准查看的内容。例如:
<div id="output"><span class="roman">watashi</span> <span class="english">I</span></div>
该界面允许用户根据他们想要看到的内容在watashi
或I
之间切换和输出。 CSS 使用 jQuery 和切换按钮隐藏其中之一。 (隐藏机制包括简单地向 body 添加一个类并让 CSS 完成它的工作)。
问题在于,当用户将文本复制/粘贴到 Word 中时,它会复制所有内容。所以我决定使用一个系统来复制粘贴文本,使用 javascript 和 jQuery,但问题再次出现:
$('#output').text()
输出watashi I
,即使I
在页面本身而不是watashi
上是不可见的。有什么方法可以只获取可见文本?
【问题讨论】:
【参考方案1】:使用:visible selector of jQuery
在你的情况下,我认为你想做:
$('#output').children(":visible").text()
【讨论】:
顺便说一句,根据 OP 问题,只有一个 #output 的孩子是隐藏的,这样可行吗?当我测试$('#output:visible').text()
时,它仍然显示“Watashi I”,但 OP 只想要“Watashi”,不是吗?
@s.mark:你一定是对的。我编辑了我的答案,我认为它应该可以工作。如果不尝试 *:visible 或类似的东西。你也可以测试 .css("display")!="none"
我认为这是错误的方法,因为它包括重新实现已经存在的浏览器功能(复制/粘贴)。
@smark:好!这显然不是最好的解决方案。最好的办法是只加载到所需语言的页面,但这会立即解决 OP 的问题
嘿,Marcgg,这似乎工作得几乎完美。它确实复制了可见文本,但如果我通过“旋转”按钮更改可见文本,那么复制操作仍然只能获取原始可见文本 - 而不是更新后的文本(如果您访问实际站点和单击旋转图标以可视化文本的变化方式)。所以我想如果可见文本发生变化,它会变得有点复杂。 (顺便说一句,我想“提高”你的建议,但我是新来的,它不允许我!)【参考方案2】:
不要隐藏 span,而是删除 span 元素并保留对它的引用。当用户单击切换按钮时,删除另一个并插入您保留引用的那个。用户将无法再选择不在 DOM 中的内容。
【讨论】:
嘿'风之声' :-) 我更愿意找到一个目前不涉及删除元素的解决方案,因为这需要对 coed 进行重大重写。 我想你将不得不使用一些捉迷藏魔法然后:) 我会在绑定到切换按钮的界面元素的函数中使用 JS 动态删除它们,但如果那也是很多工作我没有其他建议:(【参考方案3】:其他解决方案没有给我我需要的东西。
简答
我的答案是:
$('#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 包含原始内容旁边的克隆?)取决于你的场景。
【讨论】:
文本在叶节点中的假设似乎有问题 - 例如如果您有 文本或 文本,那么这些部分将位于叶节点中,而不是周围非粗体或非强调文本的其余部分。 但我展示了如何轻松绕过它。还有另一种方法.. 您可以克隆整个 HTML,然后简单地删除隐藏的部分,然后对所有内容执行“getText”。 @DaveHilditch 添加了一个也可以解决您的情况的示例。 我在您发布的最终 JS 函数中出现了一些奇怪的行为,您确定正确保存所有 DOM 元素上的所有 JS 事件吗? @Dave13s 不确定我是否遵循了这个问题。我发布了一个plunker。如果您遇到问题 - 您能在 plunker 上重现它吗?它会更容易解决。【参考方案4】:小伙答对了。
但是,我正在处理一个“this”对象,因此要让他的答案起作用,您需要使用以下语法...
$('*:not(:has(*)):visible', this).text()
【讨论】:
【参考方案5】:var lookup = function(element, text)
//DFS Recursive way of finding text on each level
//Visible only works on elements that take up space(i.e. not fixed position elements)
var results = element.children(':visible');
//Look at the text at each level with the children removed
var newText = '';
results.each(function(index, value)
newText += $(value).clone()
.children()
.remove()
.end()
.text();
);
var moreResultText = '';
results.each(function(index, value)
moreResultText += lookup($(value), text);
)
if (results.length > 0)
return text + newText + moreResultText;
else
return text;
;
lookup($('#output'), ''));
大多数其他功能在页面的大部分区域运行时都会崩溃,这应该是一种更准确的方法来确定实际向用户显示的内容,不会损坏页面,也不会返回不可见的文本用户。
当然要小心,这不会保留任何格式感,并且元素之间的输出间距可能不正确。此外,它可能没有正确排序返回的文本,在这些方面它的使用将受到限制。另一个考虑因素是可见的真正定义对nail down 来说有点困难,但对于这个例子,我接受 ":visible" 适用于大多数常见情况。
我用它来检查页面是否包含可见文本(只需在 body 元素上运行它),但它可能也适用于这个示例。
【讨论】:
我发现这段代码是一个有用的开始。但是你不想替换 moreResultText += lookup($(value), text); with moreResultText += lookup($(value), '');如果不是,您将重复原始文本值。 我很高兴你发现它很有用:),我觉得这个答案提供了一个更好/更完整的方法来完成所请求的功能,而不是其他更高投票的答案。至于代码,我没有观察到这种行为,它是 DFS,所以它应该将每个较低级别的文本添加到字符串中,最终将其传递给父调用者,直到你有一个包含所有文本的大字符串。您是否有一个不起作用的示例,可能是JSFiddle?【参考方案6】:在现代浏览器中试试这个(这里的“元素”是一个非 JQuery DOM 对象):
function getVisibleText(element)
window.getSelection().removeAllRanges();
let range = document.createRange();
range.selectNode(element);
window.getSelection().addRange(range);
let visibleText = window.getSelection().toString().trim();
window.getSelection().removeAllRanges();
return visibleText;
然后:
getVisibleText(document.getElementById('output'));
【讨论】:
$('#output *:not(:has(*)):visible').text()
jQuery 答案由于某种原因错过了一些文本。这个拾取了所有可见的内容(除了 ::before 伪元素中生成的内容,我不太担心)。
验证您的输入!如果您查询输入元素,它可能是 null ? 很好的答案。以上是关于如何使用 jQuery(或 Javascript)获取可见文本?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 JavaScript 或 jQuery 更改数组内对象的值?
如何使用 jquery 或 javascript 删除索引处的行? [复制]
如何使用 jQuery 或 JavaScript 设置底边距
如何使用 PHP 或 JavaScript/jQuery 禁用地址栏?