Need jQuery text() function to ignore hidden elements

一世执手 提交于 2019-12-11 01:15:35

问题


I have a div set up something like this:

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

EDIT: To clarify, this is the simplest example. The div could have any arbitrary number of n deep nested children.

$('#test').getText() returns 'Hello Goodbye'. Here's a one liner to test in Firebug: jQuery('<div id="test"> <p>Hello</p> <p style="display: none">Goodbye</p> </div>').text()

This seems to be because what jQuery uses internally, textContent (for non IE), returns hidden elements as part of the text. Hrmph.

Is there a way to return the text content ignoring display:none'd elements? Basically I am trying to mimic the text you would get from highlighting the div with your mouse and copying to system clipboard. That ignores hidden text.

Interestingly, if you create a selection range and get the text from it, that also returns text inside display:none elements.

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

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

So creating a document selection range doesn't appear to do the same thing as highlighting with the mouse in terms of display:none elements. How do I get around this dirty pickle conundrum?

Edit: using .filter(':visible').text has been suggested, but it won't work for this scenario. I need the returned text to be EXACTLY what would come from a selection with the mouse. So for example:

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

returns

"test2test3"

When the output I actually want is

test1 test2
 test3

linebreaks, whitespace and all, which come from the \r\n


回答1:


Filter the elements using .filter(":visible").

Or use this:

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

But the jQuery documentation advises us to use .filter() instead:

Because :visible is a jQuery extension and not part of the CSS specification, queries using :visible cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using :visible to select elements, first select the elements using a pure CSS selector, then use .filter(":visible").




回答2:


Use :visible in your selector as such:

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

A Function example:

-- Edit:

http://jsfiddle.net/8H5ka/ ( Works on Chrome it displays "Hello" in Result )

If the above doesn't work:

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




回答3:


If space isn't a major concern you could copy the markup, remove the hidden elements, and output that text.

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



回答4:


I had this problem and found this question, and it seems the actual solution is based on the provided answers but not actually written out. So here's a complete solution that worked for my situation, which is the same as the OP with the additional provision that elements may be invisible due to external styles based on DOM position. Example:

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

The solution is to:

  1. Make a clone of the entire object.
  2. Remove invisible objects in place; if we take #test out of the DOM before we remove invisible objects, jQuery might not know they're invisible because they will no longer match the CSS rules.
  3. Get the text of the object.
  4. Replace the original object with the clone we made.

The code:

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:


Here is how I did it with 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:


I search for that and found this question but without solution. Solution for me is just get out of jquery to use DOM:

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

or if more than on element in array of selector, you need a for loop and a merge but I guess that most of time it is the first version that you need.

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


来源:https://stackoverflow.com/questions/7382400/need-jquery-text-function-to-ignore-hidden-elements

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!