You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HTML表单autocomplete组件优化:全列表展示、任意匹配与值校验

自动完成组件优化方案

修改说明

针对提出的三项需求,核心修改点如下:

  • 空输入聚焦展示全量列表:新增输入框聚焦事件监听,移除空值拦截逻辑,空状态下直接渲染全部候选选项
  • 任意位置字符串匹配:替换前缀匹配逻辑为全串包含匹配,同步调整匹配字符高亮规则
  • 候选值合法性校验:新增失焦校验和表单提交校验,非列表内值会自动清空并给出错误提示

完整可运行代码

JavaScript 代码

function fruitautocomplete(inp, arr) {
  var currentFocus;
  
  // 抽离公共渲染逻辑
  function renderCandidateList() {
    var a, b, i, val = inp.value;
    closeAllLists();
    currentFocus = -1;
    a = document.createElement("DIV");
    a.setAttribute("id", inp.id + "autocomplete-list");
    a.setAttribute("class", "autocomplete-items");
    inp.parentNode.appendChild(a);
    
    const valUpper = val.toUpperCase();
    for (i = 0; i < arr.length; i++) {
      // 改为任意位置匹配
      if (arr[i].toUpperCase().includes(valUpper)) {
        b = document.createElement("DIV");
        // 调整高亮逻辑,仅高亮匹配到的子串
        const matchIdx = arr[i].toUpperCase().indexOf(valUpper);
        b.innerHTML = arr[i].substr(0, matchIdx);
        b.innerHTML += "<strong>" + arr[i].substr(matchIdx, val.length) + "</strong>";
        b.innerHTML += arr[i].substr(matchIdx + val.length);
        b.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
        b.addEventListener("click", function(e) {
          inp.value = this.getElementsByTagName("input")[0].value;
          closeAllLists();
        });
        a.appendChild(b);
      }
    }
  }

  // 输入事件
  inp.addEventListener("input", renderCandidateList);
  // 新增聚焦事件,触发列表渲染
  inp.addEventListener("focus", renderCandidateList);
  
  // 新增失焦校验
  inp.addEventListener("blur", function(e) {
    const inputVal = this.value.trim();
    if (inputVal && !arr.some(item => item.toLowerCase() === inputVal.toLowerCase())) {
      this.value = '';
      this.classList.add('invalid');
      setTimeout(() => this.classList.remove('invalid'), 2000);
    }
  });

  /*键盘事件逻辑不变*/
  inp.addEventListener("keydown", function(e) {
    var x = document.getElementById(this.id + "autocomplete-list");
    if (x) x = x.getElementsByTagName("div");
    if (e.keyCode == 40) {
      currentFocus++;
      addActive(x);
    } else if (e.keyCode == 38) {
      currentFocus--;
      addActive(x);
    } else if (e.keyCode == 13) {
      e.preventDefault();
      if (currentFocus > -1) {
        if (x) x[currentFocus].click();
      }
    }
  });

  function addActive(x) {
    if (!x) return false;
    removeActive(x);
    if (currentFocus >= x.length) currentFocus = 0;
    if (currentFocus < 0) currentFocus = (x.length - 1);
    x[currentFocus].classList.add("autocomplete-active");
  }

  function removeActive(x) {
    for (var i = 0; i < x.length; i++) {
      x[i].classList.remove("autocomplete-active");
    }
  }

  function closeAllLists(elmnt) {
    var x = document.getElementsByClassName("autocomplete-items");
    for (var i = 0; i < x.length; i++) {
      if (elmnt != x[i] && elmnt != inp) {
        x[i].parentNode.removeChild(x[i]);
      }
    }
  }
  document.addEventListener("click", function(e) {
    closeAllLists(e.target);
  });
}

var fruitlist = [
  "Apple",
  "Mango",
  "Pear",
  "Banana",
  "Berry"
];

// 修正原代码函数名调用不一致的问题
fruitautocomplete(document.getElementById("myFruitList"), fruitlist);

// 新增表单提交校验
document.getElementById('regForm').addEventListener('submit', function(e) {
  const fruitInput = document.getElementById('myFruitList');
  const inputVal = fruitInput.value.trim();
  if (!inputVal || !fruitlist.some(item => item.toLowerCase() === inputVal.toLowerCase())) {
    e.preventDefault();
    fruitInput.classList.add('invalid');
    setTimeout(() => fruitInput.classList.remove('invalid'), 2000);
    alert('请选择列表内的有效水果');
  }
});

CSS 代码(新增下拉相关样式)

* {
  box-sizing: border-box;
}

body {
  background-color: #f1f1f1;
}

#regForm {
  background-color: #ffffff;
  margin: 10px auto;
  font-family: Raleway;
  padding: 10px;
  width: 90%;
  min-width: 300px;
}

h1 {
  text-align: center;
}

input {
  padding: 10px;
  width: 100%;
  font-size: 17px;
  font-family: Raleway;
  border: 1px solid #aaaaaa;
}

input.invalid {
  background-color: #ffdddd;
}

.tab {
  display: block; /* 原代码是none会隐藏表单,这里调整为可见方便测试 */
}

button {
  background-color: #04AA6D;
  color: #ffffff;
  border: none;
  padding: 10px 20px;
  font-size: 17px;
  font-family: Raleway;
  cursor: pointer;
}

button:hover {
  opacity: 0.8;
}

#prevBtn {
  background-color: #bbbbbb;
}

.step {
  height: 15px;
  width: 15px;
  margin: 0 2px;
  background-color: #bbbbbb;
  border: none;
  border-radius: 50%;
  display: inline-block;
  opacity: 0.5;
}

.step.active {
  opacity: 1;
}

.step.finish {
  background-color: #04AA6D;
}

/* 新增自动完成下拉相关样式 */
.autocomplete {
  position: relative;
}
.autocomplete-items {
  position: absolute;
  border: 1px solid #d4d4d4;
  z-index: 99;
  top: 100%;
  left: 0;
  right: 0;
  max-height: 200px;
  overflow-y: auto;
}
.autocomplete-items div {
  padding: 10px;
  cursor: pointer;
  background-color: #fff;
  border-bottom: 1px solid #d4d4d4;
}
.autocomplete-items div:hover {
  background-color: #e9e9e9;
}
.autocomplete-active {
  background-color: #04AA6D !important;
  color: #ffffff;
}

HTML 代码

<form id="regForm" action="/submit_page.php">
  <h1>Your Nutrition Needs:</h1>
  <div class="tab">Your Fruit:
    <p class="autocomplete">
      <input id="myFruitList" type="text" name="fruit" placeholder="Start typing your fruit name">
    </p>
    <button type="submit">提交</button>
  </div>
</form>

内容的提问来源于stack exchange,提问作者Aquaholic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 20:36:03