【问题标题】:jQuery search and filter using keywords使用关键字的 jQuery 搜索和过滤
【发布时间】:2017-09-16 01:21:34
【问题描述】:

我正在尝试编写一个搜索/过滤函数,该函数根据用户输入的内容搜索具有 data-* 属性的无序列表项。

<input type="text" placeholder="Search..." id="myInput" onkeyup="myFunction()">        
<ul id="myUL">
    <li><a href="#" data-keywords="photography">Digital Media Design</a></li>
    <li><a href="#" data-keywords="computers">Information Technology</a></li>
    <li><a href="#" data-keywords="coding">Programming</a></li>
</ul>

这是我目前仅适用于一个数据关键字项的代码。我需要帮助才能根据多个关键字显示搜索结果。

<li><a href="#" data-keywords="photography photoshop illustrator premiere">Digital Media Design</a></li>

// Search functionality
function myFunction() {
    // Declare variables
    var input, filter, ul, li, a, i;
    input = document.getElementById('myInput');
    filter = input.value.toUpperCase();
    ul = document.getElementById("myUL");
    li = ul.getElementsByTagName('li');
    // Loop through all list items, and hide those who don't match the search query
    for (i = 0; i < li.length; i++) {
        a = li[i].getElementsByTagName("a")[0];
        if (a.innerHTML.toUpperCase().indexOf(filter) > -1 || $(a).data("keywords") === filter.toLocaleLowerCase()) {
            li[i].style.display = "";
        } else {
            li[i].style.display = "none";
        }
    }
}

如果有人对我如何改进代码有任何建议,那就太棒了!

【问题讨论】:

  • 允许用户在框中输入多少字,一个还是多个?如果是多个,它们都必须匹配吗?如果用户搜索photography media,是否应该与您在上面给出的示例节点匹配,其中一个搜索词匹配data-keywords,另一个搜索词匹配内容?
  • 另外,搜索hot应该匹配photography吗?

标签: javascript jquery web


【解决方案1】:

我做了一些假设:

  • 如果提供了多个搜索词,它们必须全部匹配。
  • 搜索词必须是字母,a-z。这可以很容易地更改为包含其他字符,例如数字,但最终我们需要某种方式来决定一个术语的结束位置和下一个术语的开始位置。
  • 匹配基于子串。

最需要解释的是 that 正则表达式。它使用标准技巧进行and 匹配:

Regular Expressions: Is there an AND operator?

因此,如果您搜索 digital photography,RegExp 将等同于:

/(?=.*digital)(?=.*photography)/i

如果您希望搜索为 or 而不是 and,您只需相应地调整 RegExp。如果你想做一个以匹配而不是子字符串开头的匹配,你可以在每个搜索词之前输入\b(适合在字符串中转义为\\b)。

我希望其余的内容是不言自明的,我尽量接近问题中的代码。

// Search functionality
function myFunction() {
    // Declare variables
    var input = document.getElementById('myInput'),
        filter = input.value,
        ul = document.getElementById('myUL'),
        lis = ul.getElementsByTagName('li'),
        searchTerms = filter.match(/[a-z]+/gi),
        re, index, li, a;
        
    if (searchTerms) {
        searchTerms = searchTerms.map(function(term) {
            return '(?=.*' + term + ')';
        });
        
        re = new RegExp(searchTerms.join(''), 'i');
    } else {
        re = /./;
    }

    // Loop through all list items, and hide those who don't match the search query
    for (index = 0; index < lis.length; index++) {
        li = lis[index];
        a = li.firstChild;

        if (re.test(a.innerHTML + ' ' + a.getAttribute('data-keywords'))) {
            li.style.display = '';
        } else {
            li.style.display = 'none';
        }
    }
}
<input type="text" placeholder="Search..." id="myInput" onkeyup="myFunction()">

<ul id="myUL">
  <li><a href="#" data-keywords="photography photoshop illustrator premiere">Digital Media Design</a></li>
  <li><a href="#" data-keywords="computers">Information Technology</a></li>
  <li><a href="#" data-keywords="coding">Programming</a></li>
</ul>

【讨论】:

    【解决方案2】:

    这对我有用:

    // Get all li's and create an array with each li's data attributes
    const lis = document.querySelector("#myUL").children;
    
    const keywordArray = [];
    
    [...lis].forEach((li, i) => {
      keywordArray.push(li.children[0].dataset.keywords);
    });
    
    function myFunction() {
      //Show any previous hidden li's
      [...lis].forEach(li => {
        li.style.display = 'block';
      });
    
      const inputArray = document.querySelector('#myInput').value.split(' ');
      const indexes = [];
      // For each word in the input field, search through our data attribute array
      inputArray.forEach(term => {
        keywordArray.forEach((keywords, i) => {
          keywords.split(' ').forEach(keyword => {
            // If we find a match, add the index of the data attribute array, which
            // will be the same as the index of the li element
            if (keyword === term) {
              indexes.push(i);
            }
          });
        });
      });
      // If we have a match, hide every non-matching li'
      if (indexes.length) {
        [...lis].forEach((li, i) => {
          if (!indexes.includes(i)) {
            li.style.display = 'none';
          }
        });
      }
    }
    

    为澄清起见,您是否需要额外的搜索词来使搜索更加具体或不那么具体?因为我的解决方案使搜索不那么具体,因为它会显示与任何搜索词匹配的任何 li。

    【讨论】:

      猜你喜欢
      • 2020-01-28
      • 2012-11-21
      • 1970-01-01
      • 2017-03-13
      • 2012-10-06
      • 2020-10-30
      • 2021-11-06
      • 2010-10-24
      • 1970-01-01
      相关资源
      最近更新 更多