:contains for multiple words

2019-02-18 01:16发布

问题:

I am using the following jQuery

var etag = 'kate'
if (etag.length > 0) {
    $('div').each(function () {
        $(this).find('ul:not(:contains(' + etag + '))').hide();
        $(this).find('ul:contains(' + etag + ')').show();
    });
}​

towards the following HTML

<div id="2">
<ul>
  <li>john</li>
  <li>jack</li>
</ul>
<ul>
  <li>kate</li>
  <li>clair</li>
</ul>
<ul>
  <li>hugo</li>
  <li>desmond</li>
</ul>  
<ul>
  <li>said</li>
  <li>jacob</li>
</ul>
  </div>

    <div id="3">
<ul>
  <li>jacob</li>
  <li>me</li>
</ul>
<ul>
  <li>desmond</li>
  <li>george</li>
</ul>
<ul>
  <li>allen</li>
  <li>kate</li>
</ul>  
<ul>
  <li>salkldf</li>
  <li>3kl44</li>
</ul>
</div>

basically, as long as etag has one word, the code works perfectly and hides those elements who do not contain etag. My problem is, when etag is multiple words (and I don't have control over it. Its coming from a database and could be combination of multiple words separated with space char) then the code does not work..

is there any way to achieve this?

回答1:

This filter checks if any of the words in the given string match the text of the element.

jQuery.expr[':'].containsAny = function(element, index, match) {
    var words = match[3].split(/\s+/);
    var text = $(element).text();
    var results = $.map(words, function(word) {
        return text === word;
    });
    return $.inArray(true, results) !== -1;
};

Show and hide as:

$('ul').hide();
$('li:containsAny(john kate)').parents('ul').show();

See an example here.



回答2:

You could turn this into a function that takes any number of words separated by a character, like this:

function filter(words) {
    var uls = $('div ul').hide();
    $.each(words.split(' '), function(i, v) {
        uls = uls.filter(':contains(' + v + ')');
    });
    uls.show();
}

//sample call
var etag='kate clair'
filter(etag);

You can see a working demo here

This finds <ul> elements that contain all the words in the given string.



回答3:

Another approach:

var etag='Some text from server';

if (etag.length > 0) {
    $('div ul').each(function () {
        var el = $(this); // Local reference
        (el.html() === etag) ? el.show() : el.hide(); 
    });
}​


回答4:

A slightly different approach - try this:

    var etag='kate test blah';

    var tags = etag.split(' ');
    $('div ul').each(function () {
      var list = $(this);
      list.hide();
      list.children('li').each(function() {
        var item = $(this);
        if ($.inArray(item.html(), tags) >= 0) list.show();
      });
    });

Written in the browser, so sorry if there are any bugs!

-- edit --

Actually, I reread the question, and that code won't work. You need to define the behaviour more first - does the list have to contain all of the tags, or just one of the tags to be shown?

-- edit 2 --

Code updated. Kind of inefficient, but it should do the job.