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
相关产品推荐
相关产品推荐

