实现更强大的HTML表单自动完成功能:模糊匹配、光标悬停显示全部选项以及输入验证

霞舞
发布: 2025-10-15 09:45:01
原创
418人浏览过

实现更强大的html表单自动完成功能:模糊匹配、光标悬停显示全部选项以及输入验证

本文将指导你如何增强HTML表单的自动完成功能,使其具备以下特性:在光标悬停时显示所有选项,支持在字符串的任何位置进行模糊匹配,并强制用户输入的内容必须是自动完成列表中的有效值。我们将通过修改现有的JavaScript代码,并添加必要的验证逻辑来实现这些功能。

1. 光标悬停时显示所有选项

要实现光标悬停时显示所有选项,我们需要修改 fruitautocomplete 函数中的事件监听器。当输入框获得焦点时,如果输入框为空,则显示完整的 fruitlist。

inp.addEventListener("focus", function(e) {
  if (!this.value) {
    showAllOptions(this, fruitlist);
  }
});

function showAllOptions(inp, arr) {
  var a, b, i, val = ""; // val设为空,显示所有项
  closeAllLists();
  currentFocus = -1;
  a = document.createElement("DIV");
  a.setAttribute("id", inp.id + "autocomplete-list");
  a.setAttribute("class", "autocomplete-items");
  inp.parentNode.appendChild(a);
  for (i = 0; i < arr.length; i++) {
      b = document.createElement("DIV");
      b.innerHTML = arr[i];
      b.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
      b.addEventListener("click", function(e) {
          inp.value = this.getElementsByTagName("input")[0].value;
          closeAllLists();
      });
      a.appendChild(b);
  }
}
登录后复制

这段代码添加了一个 focus 事件监听器,当输入框获得焦点且内容为空时,调用 showAllOptions 函数。 showAllOptions 函数与原有的自动完成逻辑类似,但它会显示 fruitlist 中的所有选项,而不管输入框中的内容是什么。

2. 支持在字符串的任何位置进行模糊匹配

为了支持模糊匹配,我们需要修改自动完成逻辑中的字符串比较部分。不再使用 substr 和 toUpperCase 来检查字符串是否以输入框中的内容开头,而是使用 indexOf 来检查字符串是否包含输入框中的内容。

立即学习前端免费学习笔记(深入)”;

表单大师AI
表单大师AI

一款基于自然语言处理技术的智能在线表单创建工具,可以帮助用户快速、高效地生成各类专业表单。

表单大师AI 74
查看详情 表单大师AI
if (arr[i].toUpperCase().indexOf(val.toUpperCase()) > -1) {
  /*create a DIV element for each matching element:*/
  b = document.createElement("DIV");
  /*make the matching letters bold:*/
  let index = arr[i].toUpperCase().indexOf(val.toUpperCase());
  b.innerHTML = arr[i].substr(0, index);
  b.innerHTML += "<strong>" + arr[i].substr(index, val.length) + "</strong>";
  b.innerHTML += arr[i].substr(index + val.length);
  /*insert a input field that will hold the current array item's value:*/
  b.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
  /*execute a function when someone clicks on the item value (DIV element):*/
  b.addEventListener("click", function(e) {
    /*insert the value for the autocomplete text field:*/
    inp.value = this.getElementsByTagName("input")[0].value;
    /*close the list of autocompleted values,
    (or any other open lists of autocompleted values:*/
    closeAllLists();
  });
  a.appendChild(b);
}
登录后复制

这段代码使用 indexOf 函数来查找 arr[i] 中是否包含 val。如果 indexOf 返回值大于 -1,则表示 arr[i] 包含 val,我们就创建一个包含匹配项的 DIV 元素。

3. 强制用户输入的内容必须是自动完成列表中的有效值

要强制用户输入的内容必须是自动完成列表中的有效值,我们需要添加输入验证逻辑。可以在表单提交时进行验证,或者在输入框失去焦点时进行验证。这里我们选择在输入框失去焦点时进行验证。

inp.addEventListener("blur", function(e) {
  let valid = false;
  for (let i = 0; i < fruitlist.length; i++) {
    if (fruitlist[i] === this.value) {
      valid = true;
      break;
    }
  }
  if (!valid) {
    this.value = ""; // Clear the input if it's invalid
    alert("Please select a valid fruit from the list.");
  }
});
登录后复制

这段代码添加了一个 blur 事件监听器,当输入框失去焦点时,它会检查输入框中的值是否在 fruitlist 中。如果不在,则清空输入框并显示警告信息。

完整代码示例

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
  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;
}


/* Mark input boxes that gets an error on validation: */

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


/* Hide all steps by default: */

.tab {
  display: 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;
}


/* Make circles that indicate the steps of the form: */

.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;
}


/* Mark the steps that are finished and valid: */

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

.autocomplete {
  position: relative;
  display: inline-block;
}

.autocomplete-items {
  position: absolute;
  border: 1px solid #d4d4d4;
  border-bottom: none;
  border-top: none;
  z-index: 99;
  /*position the autocomplete items to be the same width as the container:*/
  top: 100%;
  left: 0;
  right: 0;
}

.autocomplete-items div {
  padding: 10px;
  cursor: pointer;
  background-color: #fff;
  border-bottom: 1px solid #d4d4d4;
}

.autocomplete-items div:hover {
  /*when hovering an item:*/
  background-color: #e9e9e9;
}

.autocomplete-active {
  /*when navigating through the items using the arrow keys:*/
  background-color: DodgerBlue !important;
  color: #ffffff;
}
</style>
<body>

<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>
  </div>
</form>

<script>
function fruitautocomplete(inp, arr) {
  /*the autocomplete function takes two arguments,
  the text field element and an array of possible autocompleted values:*/
  var currentFocus;
  /*execute a function when someone writes in the text field:*/
  inp.addEventListener("input", function(e) {
    var a, b, i, val = this.value;
    /*close any already open lists of autocompleted values*/
    closeAllLists();
    if (!val) {
      return false;
    }
    currentFocus = -1;
    /*create a DIV element that will contain the items (values):*/
    a = document.createElement("DIV");
    a.setAttribute("id", this.id + "autocomplete-list");
    a.setAttribute("class", "autocomplete-items");
    /*append the DIV element as a child of the autocomplete container:*/
    this.parentNode.appendChild(a);
    /*for each item in the array...*/
    for (i = 0; i < arr.length; i++) {
      /*check if the item starts with the same letters as the text field value:*/
      if (arr[i].toUpperCase().indexOf(val.toUpperCase()) > -1) {
        /*create a DIV element for each matching element:*/
        b = document.createElement("DIV");
        /*make the matching letters bold:*/
        let index = arr[i].toUpperCase().indexOf(val.toUpperCase());
        b.innerHTML = arr[i].substr(0, index);
        b.innerHTML += "<strong>" + arr[i].substr(index, val.length) + "</strong>";
        b.innerHTML += arr[i].substr(index + val.length);
        /*insert a input field that will hold the current array item's value:*/
        b.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
        /*execute a function when someone clicks on the item value (DIV element):*/
        b.addEventListener("click", function(e) {
          /*insert the value for the autocomplete text field:*/
          inp.value = this.getElementsByTagName("input")[0].value;
          /*close the list of autocompleted values,
          (or any other open lists of autocompleted values:*/
          closeAllLists();
        });
        a.appendChild(b);
      }
    }
  });
  /*execute a function presses a key on the keyboard:*/
  inp.addEventListener("keydown", function(e) {
    var x = document.getElementById(this.id + "autocomplete-list");
    if (x) x = x.getElementsByTagName("div");
    if (e.keyCode == 40) {
      /*If the arrow DOWN key is pressed,
      increase the currentFocus variable:*/
      currentFocus++;
      /*and and make the current item more visible:*/
      addActive(x);
    } else if (e.keyCode == 38) { //up
      /*If the arrow UP key is pressed,
      decrease the currentFocus variable:*/
      currentFocus--;
      /*and and make the current item more visible:*/
      addActive(x);
    } else if (e.keyCode == 13) {
      /*If the ENTER key is pressed, prevent the form from being submitted,*/
      e.preventDefault();
      if (currentFocus > -1) {
        /*and simulate a click on the "active" item:*/
        if (x) x[currentFocus].click();
      }
    }
  });

    inp.addEventListener("focus", function(e) {
        if (!this.value) {
            showAllOptions(this, fruitlist);
        }
    });

    inp.addEventListener("blur", function(e) {
        let valid = false;
        for (let i = 0; i < fruitlist.length; i++) {
            if (fruitlist[i] === this.value) {
                valid = true;
                break;
            }
        }
        if (!valid) {
            this.value = ""; // Clear the input if it's invalid
            alert("Please select a valid fruit from the list.");
        }
    });

  function addActive(x) {
    /*a function to classify an item as "active":*/
    if (!x) return false;
    /*start by removing the "active" class on all items:*/
    removeActive(x);
    if (currentFocus >= x.length) currentFocus = 0;
    if (currentFocus < 0) currentFocus = (x.length - 1);
    /*add class "autocomplete-active":*/
    x[currentFocus].classList.add("autocomplete-active");
  }

  function removeActive(x) {
    /*a function to remove the "active" class from all autocomplete items:*/
    for (var i = 0; i < x.length; i++) {
      x[i].classList.remove("autocomplete-active");
    }
  }

  function closeAllLists(elmnt) {
    /*close all autocomplete lists in the document,
    except the one passed as an argument:*/
    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]);
      }
    }
  }

    function showAllOptions(inp, arr) {
        var a, b, i, val = ""; // val设为空,显示所有项
        closeAllLists();
        currentFocus = -1;
        a = document.createElement("DIV");
        a.setAttribute("id", inp.id + "autocomplete-list");
        a.setAttribute("class", "autocomplete-items");
        inp.parentNode.appendChild(a);
        for (i = 0; i < arr.length; i++) {
            b = document.createElement("DIV");
            b.innerHTML = arr[i];
            b.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
            b.addEventListener("click", function(e) {
                inp.value = this.getElementsByTagName("input")[0].value;
                closeAllLists();
            });
            a.appendChild(b);
        }
    }

  /*execute a function when someone clicks in the document:*/
  document.addEventListener("click", function(e) {
    closeAllLists(e.target);
  });
}

/*An array containing all the country names in the world:*/
var fruitlist = [
  "Apple",
  "Mango",
  "Pear",
  "Banana",
  "Berry"
];

/*initiate the autocomplete function on the "myFruitList" element, and pass along the fruit array as possible autocomplete values:*/
fruitautocomplete(document.getElementById("myFruitList"), fruitlist);
</script>

</body>
</html>
登录后复制

注意事项

  • 性能: 对于大型数据集,模糊匹配可能会影响性能。可以考虑使用更高效的搜索算法或限制显示的选项数量。
  • 用户体验: 确保自动完成列表的样式与你的网站风格一致。
  • 可访问性: 确保自动完成功能对使用屏幕阅读器等辅助技术的用户是可访问的。

总结

通过修改 JavaScript 代码,我们成功地增强了 HTML 表单的自动完成功能,使其具备了光标悬停时显示所有选项、支持模糊匹配和强制输入验证的能力。这些改进可以显著提升用户体验,并确保用户输入的数据是有效的。 请记住,根据你的具体需求,你可能需要进一步调整代码。 例如,你可能需要添加错误处理、自定义样式或与其他 JavaScript 库集成。

以上就是实现更强大的HTML表单自动完成功能:模糊匹配、光标悬停显示全部选项以及输入验证的详细内容,更多请关注php中文网其它相关文章!

HTML速学教程(入门课程)
HTML速学教程(入门课程)

HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号