Поиск и отображение Javascript div с совпадающими ключевыми словами

Что я ищу:

Я работаю над созданием простого способа для пользователя выполнять поиск по списку людей и для мгновенного отображения результатов под полем поиска. Результаты ДОЛЖНЫ отображать "близкие" результаты, а не точные. Например: пользователь выполняет поиск по запросу «Мистер Смит» и отображается следующий существующий результат: «Джон Смит» (поскольку нет записи «Мистер Смит», отображается запись с ключевым словом «кузнец»)

Что у меня есть:

У меня есть рабочий код, который позволяет пользователю вводить некоторые символы, и отображаются все div, содержащие строку, соответствующую введенному (см. В jsfiddle: http://jsfiddle.net/891nvajb/5/ Код также ниже) К сожалению, здесь отображаются только ТОЧНО совпадающие результаты.

<body>
	<input type="text" id="edit_search" onkeyup="javascript: find_my_div();">
	<input type="button" onClick="javascript: find_my_div();" value="Find">
        
<script>

function gid(a_id) {
	return document.getElementById (a_id)	;
}

  function close_all(){
  
  	for (i=0;i<999; i++) {
  		var o = gid("user_"+i);
  		if (o) {
  			o.style.display = "none";
  		}
  	}
  
  }


  function find_my_div(){ 
  	close_all(); 
  	
	var o_edit = gid("edit_search");
	var str_needle = edit_search.value;
	str_needle = str_needle.toUpperCase();
  
	if (str_needle != "") {
		for (i=0;i<999; i++) {
	  	var o = gid("user_"+i);
	  	if (o) { 
	  		
	  		var str_haystack = o.innerHTML.toUpperCase();
	  		if (str_haystack.indexOf(str_needle) ==-1) {
	  			// not found, do nothing
	  		}
	  		else{
	  			o.style.display = "block";
		  		}	
  			}
  		}
  	}
  
  }
</script>
    
<div id="user_0" style="display:none">Andy Daulton<br/>Owner Nissan<br/><br/></div>
<div id="user_1" style="display:none">Doug Guy<br/>Bug Collector<br/><br/></div>
<div id="user_2" style="display:none">Sam Hilton<br/>Famous Celebrity in Hollywood<br/><br/></div>
<div id="user_3" style="display:none">Don Grey<br/>Old man<br/><br/></div>
<div id="user_4" style="display:none">Amy Hinterly<br/>Cook<br/><br/></div>
<div id="user_5" style="display:none">Gary Doll<br/>Racecar Driver<br/><br/></div>
<div id="user_6" style="display:none">Tod Akers<br/>Football Player<br/><br/></div>
<div id="user_7" style="display:none">Greg Barkley<br/>Interior designer<br/><br/></div>
<div id="user_8" style="display:none">Alen Simmons<br/>8th place winner<br/><br/></div>


person Steve    schedule 21.10.2014    source источник
comment
Я не могу воспроизвести поведение точного совпадения в вашем JSFIDDLE, которое, как вы утверждаете, работает ... не могли бы вы привести пример того, что вы искали, когда это сработало для вас ...   -  person Phani    schedule 21.10.2014
comment
Встроенный код вроде работает; Тонна возвращает и Долтона, и Хилтона ...?   -  person Malk    schedule 21.10.2014
comment
Вы просто хотите отдать приоритет нескольким совпадающим словам, а не меньшему количеству? Или мистеру Смоту следует также вернуть Джона Смита?   -  person juvian    schedule 21.10.2014
comment
@Phani Пример: dy da вызовет Andy Daulton, потому что эта строка символов включена в этот результат. Тогда как если вы наберете Энди Смит, ничего не появится, даже если Энди будет в результате. Таким образом, он не рассматривает ключевые слова по отдельности (что я и хочу), а просто точную строку, которая вводится.   -  person Steve    schedule 21.10.2014
comment
@juvian, если бы гладкость была ключевым словом в результате Джона Смита, он бы подошел, но в противном случае нет.   -  person Steve    schedule 21.10.2014


Ответы (2)


Разделите слова в строке поиска с помощью регулярного выражения, например

searchString.split(/\W/);

и выполните поиск по каждому слову в результирующем массиве по ИЛИ.

Обновленная скрипка.

var searchStrings = str_needle.split(/\W/);

for (var i = 0, len = searchStrings.length; i < len; i++) {
    var currentSearch = searchStrings[i].toUpperCase();
    if (currentSearch !== "") {
        nameDivs = document.getElementsByClassName("name");
        for (var j = 0, divsLen = nameDivs.length; j < divsLen; j++) {
            if (nameDivs[j].textContent.toUpperCase().indexOf(currentSearch) !== -1) {
                nameDivs[j].style.display = "block";
            }
        }
    }
}
person Matt R    schedule 21.10.2014
comment
Ах молодец! Такое простое решение, спасибо! Я мог бы даже избавиться от функции onKeyUp, чтобы улучшить взаимодействие с пользователем, чтобы все результаты больше не отображались с началом каждого нового слова ‹/justathought› Спасибо! - person Steve; 21.10.2014
comment
Я хотел проголосовать за, но не хотел испортить вашу репутацию 666: › - person SirDerpington; 14.11.2018

Еще один подход заключается в следующем:

function gid(a_id) {
  return document.getElementById(a_id);
}

function close_all() {

  // applies the Array.prototype.forEach() method to the array-like nodeList
  // returned by document.querySelectorAll() (the string passed to which finds all
  // elements with an id that starts with ('^=') the string 'user_':
  [].forEach.call(document.querySelectorAll('[id^=user_]'), function(div) {
    // 'div' is the array element (the node) itself:
    div.style.display = 'none';
  });

}


function find_my_div() {
  close_all();

  // getting the trimmed lower-cased string from the input element, split
  // on white-space characters to create an array:
  var keywords = gid('edit_search').value.trim().toLowerCase().split(/\s+/),
    // as above, selecting all elements whose id starts with the string 'user_':
    haystack = document.querySelectorAll('[id^="user_"]'),
    // working out whether text is accessed by node.textContent, or node.innerText:
    textProp = 'textContent' in document.body ? 'textContent' : 'innerText',
    // an initialised variable, for later:
    userWords,

    // filters the haystack (the divs whose id starts with 'user_'):
    found = [].filter.call(haystack, function(user) {
      // assigns the lower-cased string to the created-variable:
      userWords = user[textProp].toLowerCase();
      // returns those div elements whose text contains some of
      // the words returned, earlier, as the keywords:
      return keywords.some(function (word) {
        return userWords.indexOf(word) > -1;
      });
    });

  // iterates over the found elements, and shows them:
  [].forEach.call(found, function(user) {
    user.style.display = 'block';
  });

}

<body>
  <input type="text" id="edit_search" onkeyup="javascript: find_my_div();">
  <input type="button" onClick="javascript: find_my_div();" value="Find">

  <script>
    function gid(a_id) {
      return document.getElementById(a_id);
    }

    function close_all() {

      [].forEach.call(document.querySelectorAll('[id^=user_]'), function(div) {
        div.style.display = 'none';
      });

    }


    function find_my_div() {
      close_all();
      var keywords = gid('edit_search').value.trim().toLowerCase().split(/\s+/),
        haystack = document.querySelectorAll('[id^="user_"]'),
        textProp = 'textContent' in document.body ? 'textContent' : 'innerText',
        userWords,
        found = [].filter.call(haystack, function(user) {
          userWords = user[textProp].toLowerCase();
          return keywords.some(function (word) {
            return userWords.indexOf(word) > -1;
          });
        });
      console.log(found);
      [].forEach.call(found, function(user) {
        user.style.display = 'block';
      });

    }
  </script>

  <div id="user_0" style="display:none">Andy Daulton
    <br/>Owner Nissan
    <br/>
    <br/>
  </div>
  <div id="user_1" style="display:none">Doug Guy
    <br/>Bug Collector
    <br/>
    <br/>
  </div>
  <div id="user_2" style="display:none">Sam Hilton
    <br/>Famous Celebrity in Hollywood
    <br/>
    <br/>
  </div>
  <div id="user_3" style="display:none">Don Grey
    <br/>Old man
    <br/>
    <br/>
  </div>
  <div id="user_4" style="display:none">Amy Hinterly
    <br/>Cook
    <br/>
    <br/>
  </div>
  <div id="user_5" style="display:none">Gary Doll
    <br/>Racecar Driver
    <br/>
    <br/>
  </div>
  <div id="user_6" style="display:none">Tod Akers
    <br/>Football Player
    <br/>
    <br/>
  </div>
  <div id="user_7" style="display:none">Greg Barkley
    <br/>Interior designer
    <br/>
    <br/>
  </div>
  <div id="user_8" style="display:none">Alen Simmons
    <br/>8th place winner
    <br/>
    <br/>
  </div>

Использованная литература:

person David says reinstate Monica    schedule 21.10.2014
comment
Это не работает для данного варианта использования, т.е. мистер парень не возвращает никаких результатов. - person Matt R; 21.10.2014
comment
@Matt: да, да, это так ... (ну, сейчас в любом случае ...) Спасибо! :) - person David says reinstate Monica; 21.10.2014