如何逐个字母地连续过滤列表中的选项?

How can I successively filter the choices in a list on a letter by letter basis?

如果此问题已在别处得到解答,我深表歉意;如果是这样,我将无法以返回所需结果的方式查询数据库。这是我的问题:

假设我有一个州名的无序列表。

等等, 路易斯安那州、缅因州、马萨诸塞州、密歇根州、密西西比州、密苏里州、蒙大拿州、新罕布什尔州等

我想显示一个搜索框,在输入连续的唯一字母时将列表过滤为单个选项。换句话说,只需输入“M”,就可以消除“Louisiana”和“New”汉普郡”从列表中。通过向“M”添加“o”,您可以消除除“Montana”之外的所有内容。但是在“M”之后输入“a”,列表仍然提供两个选择。为了将列表缩减为单个选项,您必须键入第三个字母。我找到了一个可以按大写字母过滤的脚本,仅此而已。如果输入第二个字母以进一步减少选项数量,列表将完全消失。

这里(来自 w3schools 有一些修改)是元素:

function myFunction() {
  var input, filter, ul, li, a, i, txtValue;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  ul = document.getElementById("myUL");
  li = ul.getElementsByTagName("li");
  for (i = 0; i < li.length; i++) {
    a = li[i].getElementsByTagName("a")[0];
    txtValue = a.textContent || a.innerText;
    if (txtValue.indexOf(filter) > -1) {
      li[i].style.display = "";
    } else {
      li[i].style.display = "none";
    }
  }
}
* {
  box-sizing: border-box;
}

#myInput {
  background-image: url('/css/searchicon.png');
  background-position: 10px 12px;
  background-repeat: no-repeat;
  width: 100%;
  font-size: 16px;
  padding: 12px 20px 12px 40px;
  border: 1px solid #ddd;
  margin-bottom: 12px;
}

#myUL {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

#myUL li a {
  border: 1px solid #ddd;
  margin-top: -1px;
  /* Prevent double borders */
  background-color: #f6f6f6;
  padding: 12px;
  text-decoration: none;
  font-size: 18px;
  color: black;
  display: block
}

#myUL li a:hover:not(.header) {
  background-color: #eee;
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">

<ul id="myUL">
  <li><a href="#">Louisiana</a></li>
  <li><a href="#">Maine</a></li>
  <li><a href="#">Massachusetts</a></li>
  <li><a href="#">Michigan</a></li>
  <li><a href="#">Mississippi</a></li>
  <li><a href="#">Missouri</a></li>
  <li><a href="#">Montana</a></li>
  <li><a href="#">New Hampshire</a></li>
</ul>

他们的脚本确实提供了按名称中的任何字母排序的选项,而不仅仅是大写(大概是第一个)字母。但是,这 returns 所有出现输入字母的名称。因此,键入“i”(在所有州名称的列表中)将显示名称中任何位置带有该字母的所有州。但是,随着输入更多的字母,这种方法最终确实将列表减少为单一选择。我希望这两种方法一起工作,即,我希望第一个输入的字母将列表过滤为只有第一个字母的状态,第二个输入的字母将其减少到只有前两个字母相同的州,等等。我希望这是有道理的。

在此先感谢您的帮助。

你好@ean 我在波纹管代码上添加了单行注释,它只是比较大写字符串,因为当你在文本框上输入时,你有一行 JavaScript 它转换为大写和 string.indexOf比较大小写字符

function myFunction() {
  var input, filter, ul, li, a, i, txtValue;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  ul = document.getElementById("myUL");
  li = ul.getElementsByTagName("li");
  for (i = 0; i < li.length; i++) {
      a = li[i].getElementsByTagName("a")[0];
      // txtValue = a.textContent || a.innerText;
      txtValue = a.innerText.toUpperCase();
      if (txtValue.indexOf(filter) > -1) {
        li[i].style.display = "";
      } else {
        li[i].style.display = "none";
      }
  }
}

是比 javascript 问题更多的算法问题,因此您可以为您的问题添加附加标签。我使用 foreach 循环来简化代码,你可以根据需要更改它。 Okej 您的代码检查 txtValue(字符串变量)是否包含第二个字符串 'filter' txtValue.indexOf(filter) > -1here u can read more about indexOf method。 您需要检查列表中哪个选项以 'filter' 开头。最简单的解决方案是:

function myFunction() {
    var value = document.getElementById("myInput").value.toUpperCase();
    var myUL = document.getElementById("myUL");
    for (var elem of myUL.getElementsByTagName("li")) {
        if (elem.innerText.toUpperCase().startsWith(value)) {
          elem.style.display = "";
        } else {
          elem.style.display = "none";
        }
    }
}

但我不认为它是一个好的搜索引擎。你可以搜索“模糊搜索算法”来实现更复杂的。

我不太明白你的问题,所以我添加了 2 个选项。一个检查状态的开始,一个检查以您输入的任何字母开头的每个状态

function myFunction() {
var input, filter, ul, li, a, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase().split('');
ul = document.getElementById("myUL");
li = ul.getElementsByTagName("li");
for (i = 0; i < li.length; i++) {
    if (filter.length === 0) {
    li[i].style.display = "";

  } else {
    a = li[i].getElementsByTagName("a")[0];
    txtValue = a.textContent.toUpperCase() || a.innerText.toUpperCase();
    // If you want to search from the first letter onwards
    /* if (txtValue.substr(0, filter.length) == filter)  {
     li[i].style.display = "";
    } else {
      li[i].style.display = "none";
    } */ 
    
    // If you want to search by the first letter no matter how many charachters you put in
    if (txtValue[0].split('').some((char) => filter.includes(char))) {
        li[i].style.display = "";
    } else {
        li[i].style.display = "none";
    }
  }
}

}

尝试研究JavaScript中内置的字符串和数组方法。

你可以这样做:

HTML

<h2>
Available names:
</h2>

<p>
'Tom', 'Linda', 'James', 'Allen', 'Matt'
</p>

<h3>
Try to search for one.
</h3>
<input type="text" />
<button type="button">
Search
</button>

<h3>
Names:
</h3>
<div id="output">
  No search yet
</div>   <!-- or even use an <output> tag! -->

JavaScript

const names = ["Tom", "Linda", "James", "Allen", "Matt", "Adam"];

const input = document.querySelector("input");
const button = document.querySelector("button");
const output = document.querySelector("#output");

const renderNamesToHTML = function(names) {
  output.innerHTML = '';
  output.innerHTML += names.map((n) => n.toString()).join(', ');
};

const filterNamesToStartWith = e => renderNamesToHTML(
  names.filter((name) => name.toLowerCase().startsWith(input.value.toLowerCase()))
)

const filterNamesToInclude = e => renderNamesToHTML(
  names.filter((name) => name.toLowerCase().indexOf(input.value.toLowerCase()) > -1)
)

button.addEventListener("click", filterNamesToInclude);

在 JSFiddle 中尝试运行!

编辑:我注意到我实际上让它没有完全工作,抱歉。应该自己试一下吧,反正现在应该可以用了,我也把代码缩短了一点。