Функция поиска / клонирования, которая не должна учитывать регистр и иметь возможность расставлять приоритеты для клонированного - PullRequest
0 голосов
/ 23 апреля 2020

В настоящее время у меня есть настройка функции поиска, которая разбивает слова, которые вы искали, и затем проверяет, существуют ли эти слова в указанном c div. Если они это сделают, они клонируют эти div и перечисляют их внутри другого div под названием .search-results. В настоящее время это работает хорошо, однако я хотел бы настроить его следующим образом:

  1. Уметь сделать так, чтобы при поиске не учитывался регистр. Например, если я буду искать «яблоки» или «ЯБЛОКИ», он все равно узнает, нужно ли клонировать div со словом «Яблоки».

  2. Клонированные div, у которых большинство слов совпадают с для искомого предложения, которое нужно поместить в начало класса .search-results, это просто так, что эти элементы имеют приоритет над остальными, которые все еще содержат искомые слова, но, возможно, немного меньше.

Так, например, если бы я искал 'Lemon Pineapple Orange', я бы ожидал, что появятся только два результата:

<div class="box">Lemon Mango Orange</div>
<div class="box">Cherries Pineapple Strawberries Crabapple</div>

, и он будет в таком порядке, потому что 'Lemon' и 'Orange 'оба являются частью одного и того же div, содержащего два искомых слова, и, следовательно, идут вверху, так как div, содержащий слово Lemon, имеет только одно искомое слово, то есть go снизу. Я надеюсь, что это имеет смысл: -)

Я надеюсь, что все имеет смысл. Любая помощь будет отличной. Ниже приведен пример кода, который работает хорошо, но, как я уже сказал, я просто хочу его настроить. Большое спасибо.

$("#search-submit").on("click", function() {
  var search = $("#search-input").val();
  if (search !== "") {
    var searchArray = search.split(" ");
    searchArray.forEach(function(searchWord) {
      $(".box").each(function() {
        if ($(this).is(":contains(" + searchWord + ")")) {
          $(this).clone(true).appendTo(".search-results");
        }
      });
    });
  };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="search">
  <input id="search-input" type="text" />
  <input id="search-submit" type="submit" value="Submit" />
</div><br/>
<div class="search-results"></div><br/>
<div class="box">Apples Banana Blueberries</div>
<div class="box">Cherries Pineapple Strawberries</div>
<div class="box">Lemon Mango Orange</div>

Ответы [ 2 ]

1 голос
/ 23 апреля 2020

В первом блоке кода у вас есть пример того, как вы можете создать (или адаптировать существующий) селектор jQuery. В этом случае :containsInsensitiveWithCount, который будет действовать как, содержит в режиме нечувствительный к регистру и добавляет атрибут data-matches с количеством совпадений.

Затем вы можете сортировать на основе этого атрибута.

Примечание что при поиске нескольких терминов у вас могут возникнуть проблемы, вы заметите, что ваш код создает клон для каждого совпадения, поэтому он дублирует результат, если совпадает с разными терминами. Я не обращался к этому здесь.

РЕДАКТИРОВАТЬ: пока я писал, вы редактировали вопрос именно о примечании, которое я добавил. Вот возможное решение:

  • теперь пользовательский селектор может принимать несколько параметров, разделенных , (это означает, что вы не можете искать кому сейчас, если проблематично c, выберите другой разделитель)
  • селектор автоматически зацикливается на аргументах, поэтому теперь счетчик отражает общий поиск и избегает дубликатов
  • исправил сортировку (фактически с помощью @RoryMcCrossan я забыл .find(".box"))
  • вызов селектора упрощен, вам не нужно делать each на ".box", просто используйте $(".box:contains...").clone

//custom jQuery selector - has to be done only once, at the start of the scripts
$(document).ready(function() {
  $.expr[":"].containsInsensitiveWithCount = $.expr.createPseudo(function(arg) {
    return function( elem ) {
      var searchArray = arg.toUpperCase().split(",");
      var count = 0;
      searchArray.forEach(function(searchWord) {
        count += $(elem).text().toUpperCase().split(searchWord).length - 1;
      });
      $(elem).attr("data-matches", count);
      return count > 0;
    };
  });
});

$("#search-submit").on("click", function() {
  var search = $("#search-input").val(), result = $(".search-results");
  result.empty();
  if (search !== "") {
    $(".box:containsInsensitiveWithCount(" + search.replace(/ /g, ",") + ")").clone(true).appendTo(result);
    //the sorting
    result.find(".box").sort(function(a, b) {
      return $(b).data("matches") - $(a).data("matches");
    }).appendTo(result);
  };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="search">
  <input id="search-input" type="text" />
  <input id="search-submit" type="submit" value="Submit" />
</div><br/>
<div class="search-results"></div><br/>
<div class="box">Apples Banana Blueberries</div>
<div class="box">Cherries Pineapple Strawberries</div>
<div class="box">Lemon Mango Orange</div>
1 голос
/ 23 апреля 2020

Чтобы сделать поиск нечувствительным к регистру, вы можете использовать регулярное выражение, чтобы найти критерий поиска в тексте каждого .box.

Кроме того, это регулярное выражение можно использовать для подсчета количества совпадений в .box, а затем sort() по этому значению после завершения l oop.

Обратите внимание, что в приведенном ниже примере я добавил значение 'Crabapple' к одному из блоков, к которому у него есть два экземпляра 'apple' для поиска. Это всегда будет приводить к этому результату.

Наконец, обратите внимание, что я добавляю вызов к empty() результату каждый раз, когда выполняется новый поиск. Предыдущие результаты поиска не были удалены в исходном примере.

let $results = $('.search-results');

$("#search-submit").on("click", function() {
  let searchArray = $("#search-input").val().trim().split(' ');
  $results.empty();
  
  searchArray.forEach(function(word) {
    $(".box").each(function() {    
      let re = new RegExp(word, 'gi');
      let matches = ($(this).text().match(re) || []).length;      
      if (matches != 0) {
        $(this).clone(true).appendTo($results).data('matches', matches);
      }
    });
  });
  
  $results.find('.box').sort((a, b) => $(a).data('matches') < $(b).data('matches') ? 1 : -1).appendTo($results);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="search">
  <input id="search-input" type="text" value="apple" />
  <input id="search-submit" type="submit" value="Submit" />
</div><br/>
<div class="search-results"></div><br/>
<div class="box">Apples Banana Blueberries</div>
<div class="box">Cherries Pineapple Strawberries Crabapple</div>
<div class="box">Lemon Mango Orange</div>

Обновление

Учитывая изменение вопроса, вы можете изменить приведенную выше логику c, чтобы построить единый регулярное выражение, которое оценивает все слова, введенные одновременно:

let $results = $('.search-results');

$("#search-submit").on("click", function() {
  $results.empty();
  let exp = $("#search-input").val().trim().replace(/\s+/g, '|');
  let re = new RegExp(exp, 'gi');

  $(".box").each(function() {
    let matches = ($(this).text().match(re) || []).length;
    if (matches != 0) {
      $(this).clone(true).appendTo($results).data('matches', matches);
    }
  });

  $results.find('.box').sort((a, b) => $(a).data('matches') < $(b).data('matches') ? 1 : -1).appendTo($results);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="search">
  <input id="search-input" type="text" value="Lemon Pineapple Orange" />
  <input id="search-submit" type="submit" value="Submit" />
</div><br/>
<div class="search-results"></div><br/>
<div class="box">Apples Banana Blueberries</div>
<div class="box">Cherries Pineapple Strawberries</div>
<div class="box">Lemon Mango Orange</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...