简体   繁体   English

如何使用 jQuery(或 Javascript)仅获取可见文本?

[英]How do I get just the visible text with jQuery (or Javascript)?

I have website that converts Japanese Kanji into Romaji (roman letters) :我有将日语汉字转换为罗马字(罗马字母)的网站

and the output shows and hides with CSS what the user needs to see depending on their input criteria.并且输出使用 CSS 显示和隐藏用户需要根据他们的输入条件查看的内容。 For example:例如:

<div id="output"><span class="roman">watashi</span> <span class="english">I</span></div>

The interface allows the user to flip between and output of watashi or I depending on what they want to see.该界面允许用户根据他们想要看到的内容在watashiI输出和输出之间watashi The CSS hides one or the other using jQuery and a toggle button. CSS 使用 jQuery 和切换按钮隐藏其中一个。 (the hiding mechanism involves simple adding a class to the body and letting CSS do its thing). (隐藏机制包括简单地向主体添加一个类并让 CSS 完成它的工作)。

The problem is that when users copy/paste the text into Word it copies everything.问题是当用户将文本复制/粘贴到 Word 时,它会复制所有内容。 So I decided to use a system to copy paste the text using JavaScript and jQuery, but the problem repeats itself:所以我决定使用一个系统来复制粘贴使用 JavaScript 和 jQuery 的文本,但问题又重复了:

$('#output').text() outputs watashi I even if I is invisible on the page itself rather than watashi . $('#output').text()输出watashi I即使I在页面本身而不是watashi上不可见。 Is there any way to get just the visible text?有没有办法只获取可见文本?

the other solutions did not give me what I needed.其他解决方案没有给我我需要的。

Short Answer简答

my answer is :我的回答是:

$('#output *:not(:has(*)):visible').text()

plunkr普朗克

TL;DR TL; 博士

The problem with marcgg's solution marcgg 解决方案的问题

You should not ask the text of all element under some root element..您不应该询问某个根元素下所有元素的文本。

why?为什么? - it will repeat output and ignore hidden flag - 它会重复输出并忽略隐藏标志

lets look at a simple example让我们看一个简单的例子

<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>

now if I do $('#output').children(":visible").text()现在如果我做$('#output').children(":visible").text()

I will get .some-div and .second .. when in fact .some-div is of no concern to me..我会得到.some-div.second .. 实际上.some-div对我来说.some-div ..

when I ask for text() on those elements, .some-div will return the hidden text as well..当我在这些元素上请求text()时, .some-div也会返回隐藏的文本..

so technically marcgg's solution is wrong IMHO...所以从技术上讲,marcgg 的解决方案是错误的,恕我直言......

The reason for my answer我回答的原因

Now, in order to properly answer the question, we have to make an assumption.现在,为了正确回答这个问题,我们必须做一个假设。 One that, for me, seems reasonable enough.一个,对我来说,似乎足够合理。

The assumption is that text only appears in leaf elements..假设文本仅出现在叶元素中。

So we won't see something like this:所以我们不会看到这样的事情:

<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>

Why does this assumption seem reasonable to me?为什么这个假设在我看来是合理的? two reasons:两个原因:

  • Because it is hard to maintain a page that is constructed this way - and with time people with experience learn that and avoid it.因为很难维护以这种方式构建的页面 - 随着时间的推移,有经验的人会了解并避免它。
  • It is easy to convert your html to such a structure.很容易将您的 html 转换为这样的结构。 just wrap parents' text with spans.只需用跨度包裹父母的文字。 So even if this assumption does not exist right now, it is easy to get there.所以即使这个假设现在不存在,也很容易实现。

With that assumption, what you want to do is request all leaf elements (elements without children) , filter out the visible, and ask for their text..有了这个假设,您想要做的是请求所有叶元素(没有子元素的元素),过滤掉可见元素,并请求它们的文本。

$('#output *:not(:has(*)):visible').text()

This should generate the correct result.这应该会产生正确的结果。

Gotta have text outside leaf element?必须在叶子元素外有文字吗?

the comments suggest sometimes you just got to have text outside leaf element评论建议有时你只需要在叶子元素之外添加文本

<div> This is some <strong style="display:none"> text </strong>  </div>

As you can see, you have <strong> as a leaf and it is common to have text outside it like in this example.正如您所看到的,您将<strong>作为叶子,并且像本例中一样在它外面有文本是很常见的。

You could go around it with the workaround I suggest above.. but what if you can't?你可以用我上面建议的解决方法来解决它……但是如果你不能呢?

You can clone the dom and then remove all hidden elements.您可以克隆 dom,然后删除所有隐藏元素。 The problem here is that in order for :visible selector or :hidden selectors to work, I must have the dom element on the document (which means actually visible to the user).这里的问题是,为了使:visible选择器或:hidden选择器工作,我必须在文档上有 dom 元素(这意味着实际上对用户可见)。 And so, this method comes with some side effects, so be careful.所以,这种方法有一些副作用,所以要小心。

Here is an example这是一个例子

for this html对于这个 html

 <div id="output" class="my-root">
     <span>
         some text <strong style="display:none">here.. </strong>
     </span>
</div>

This javascript works这个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. 
})

see plunker here在这里看到plunker

as mentioned - side effects may appear like a momentary flicker, or some initialization script that should run.. some may be avoided with some original thinking (div with size 1px/1px to contain the clone alongside original content?) depending on your scenario.如前所述 - 副作用可能看起来像瞬间闪烁,或者一些应该运行的初始化脚本..一些可能会通过一些原始想法来避免(大小为 1px/1px 的 div 包含克隆和原始内容?)取决于您的场景。

Use the :visible selector of jQuery使用:visible jQuery 选择器

In your case I think you want to do:在你的情况下,我认为你想做:

$('#output').children(":visible").text() 

Try this in modern browsers (here 'element' is a non-JQuery DOM object):在现代浏览器中试试这个(这里的“元素”是一个非 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;
}

then:然后:

getVisibleText(document.getElementById('output'));

Guy has the correct answer.盖伊给出了正确答案。

However, I was dealing with a "this" object, so to get his answer to work you need to use the following syntax...但是,我正在处理一个“this”对象,因此要获得他的工作答案,您需要使用以下语法...

$('*:not(:has(*)):visible', this).text()
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'), ''));

Most of the other functions fall apart when run on large sections of a page, this should be a more accurate way to determine what is actually displayed to the user, without corrupting the page, and without returning text that is not visible to the user.大多数其他功能在页面的大部分区域运行时都会崩溃,这应该是一种更准确的方法来确定实际向用户显示的内容,而不会损坏页面,并且不会返回用户不可见的文本。

Be careful of course, this does not preserve any sense of formatting, and the spacing of the output may not be correct between elements.当然要小心,这不会保留任何格式感,并且元素之间的输出间距可能不正确。 Also, it probably does not correctly order the returned text, in these aspects its usages will be limited.此外,它可能没有正确排序返回的文本,在这些方面它的用法将受到限制。 Another consideration is the real definition of visible is a little hard to nail down , but for this example I accept that ":visible" works for most common cases.另一个考虑是可见的真正定义是有点难以明确,但在这个例子中我接受“:可见”为最常见的情况下工作。

I use it to check if a page contains visible text(just run it on the body element), but it would probably work for this example too.我用它来检查页面是否包含可见文本(只需在 body 元素上运行它),但它也可能适用于本示例。

Instead of hiding a span, remove the span element and keep a reference to it.不要隐藏跨度,而是删除跨度元素并保留对它的引用。 When the user clicks on the toggle button, remove the other one and insert the one you kept a reference to.当用户单击切换按钮时,删除另一个并插入您保留引用的那个。 The user won't be able to select something that isn't in the DOM anymore.用户将无法再选择不在 DOM 中的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何获取包含Javascript / Jquery中单击文本的元素? - How do I get the element containing clicked text in Javascript/Jquery? 如何使用 Javascript 或 jQuery 获得突出显示的文本? - How do I use Javascript or jQuery get highlighted text? jQuery获取当前显示的文本(即不仅可见) - jquery get text currently shown (ie.not just visible) 如何获得范围的可见文本? (createRange) - How do I get the visible text of a range? (createRange) 如何用jQuery / javascript分页文本? - how do I paginate text with jQuery / javascript? 如何使JavaScript与Jquery交互? - How do I get JavaScript to interact with Jquery? 在Livecycle中,如何隐藏SSN中的前五个数字,并使用JS,jQuery或Livecyle使后四个数字可见? - In Livecycle, How do I hide the first five numbers in a SSN and make the last 4 visible using JS, jquery, or just Livecyle? 如何使用 Javascript 延迟文本框的可见性,然后在第一个框可见后隐藏另一个框 - How do I use Javascript to delay visibility of a text box and then hide another box after the first becomes visible 如何仅使用Javascript旋转图像? - How do i just rotate a image in Javascript? 如何使用 JQuery/Javascript 翻译表格中的文本? - How do i translate text in a table Using JQuery/Javascript?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM