开发者问题收集

如何传递此和 addEventListener 以从列表中拾取项目并将其设置在输入字段上

2021-08-19
455

我正在开发一个自动完成功能,并填充一个列表,目前列表只显示结果,但我无法选择它们以将其添加到输入元素。 以下是代码示例:

var search_terms = ['a', 'b', 'c'];

function autocompleteMatch(input) {
  if (input == '') {
    return [];
  }
  var reg = new RegExp(input);
  return search_terms.filter(function(term) {
    if (term.match(reg)) {
      return term;
    }
  });
}

function showResults(val) {
  res = document.getElementById("result");
  res.innerHTML = '';
  let list = '';
  let terms = autocompleteMatch(val);
  for (i = 0; i < terms.length; i++) {
    list += '<li>' + terms[i] + '</li>';
  }
  res.innerHTML = '<ul>' + list + '</ul>';
}
<input type="text" class="form-control" placeholder="Explain in fewer words with the primary product key word (Eg: OneDrive sync issue, etc.)" name="post" required id="id_post" onKeyUp="showResults(this.value)">
<span class="fas fa-asterisk" style="font-size:12px;color:red;position:absolute; right:20px;top:12px;" id="asterix"></span>
<div id="result"></div>

任何建议将列表中的元素添加到输入。我搜索了类似的建议,但我无法将答案应用到我的代码中。

编辑:在我的情况下,这里发布的解决方案不起作用,因为脚本的调用

<script type="text/javascript"  src="app.js" charset="utf-8"></script>

在顶部。因此它失败了,出现 Uncaught TypeError:无法读取 null 的属性“addEventListener”。将 <script> 部分移动到 <body> 末尾后,建议的答案开始起作用。

3个回答

这是应该的工作方式吗?我向 res 添加了事件监听器,用于测试是否单击了 <li> 。如果是,则将 <li> 的 innerHTML 作为值插入到 <input> 中。使用 dispatchEvent() ,我更新列表,就像它是一个 keyup 事件一样。

var search_terms = ['abc', 'abcde', 'abde'];
var res = document.getElementById("result");
var id_post = document.getElementById("id_post");

function autocompleteMatch(input) {
  if (input == '') {
    return [];
  }
  var reg = new RegExp(input)
  return search_terms.filter(function(term) {
    if (term.match(reg)) {
      return term;
    }
  });
}

function showResults(val) {
  let terms = autocompleteMatch(val);
  list = terms.map(term => `<li>${term}</li>`).join('');
  res.innerHTML = '<ul>' + list + '</ul>';
}

res.addEventListener('click', e => {
  if(e.target.nodeName == "LI"){
    id_post.value = e.target.innerHTML;
    id_post.dispatchEvent(new Event('keyup'));
  }
});
<input type="text" class="form-control" placeholder="Explain in fewer words with the primary product key word (Eg: OneDrive sync issue, etc.)" name="post" required id="id_post" onKeyUp="showResults(this.value)">
<div id="result"></div>
chrwahl
2021-08-19

考虑到您的原始代码,缺少一些细节,例如 自动完成 功能和键盘事件(向上/向下/输入)。

1) HTML

// form (autocomplete off) disables autocomplete integration with external tools like 1password
<form autocomplete="off">
  <div class="autocomplete" id="autocomplete-container">
    <input id="autocomplete-input" type="text" placeholder="Type Something...">
  </div>
  <input type="submit">
</form>

2) 可能选项列表 要使其动态,请在将其绑定到自动完成方法之前加载列表

const data = ["Aaa", "Aab", "Aac", "Abc", "Bbc", "Bbd", "Xpto", "Item1", "Item2", "SomethingElse"];

3) 自动完成功能

const autocomplete = (container, inputElement, list) => {
  var currentFocus = -1;

  inputElement.addEventListener('input', () => {
    var autocompleteText = inputElement.value;

    hideList();

    if (!autocompleteText) {
      return false;
    }

    const autocompleteList = document.createElement('div');
    autocompleteList.setAttribute('id', 'autocomplete-list');
    autocompleteList.setAttribute('class', 'autocomplete-items');

    container.appendChild(autocompleteList);

    list.forEach((item, index) => {
      if (
        item.substr(0, autocompleteText.length).toUpperCase() ===
        autocompleteText.toUpperCase()
      ) {
        const tempId = `hiddenInput_${index}`;
        const text = item.substr(0, autocompleteText.length);
        const autocompleteMatch = document.createElement('div');

        autocompleteMatch.innerHTML = `<strong>${text}</strong>`;
        autocompleteMatch.innerHTML += item.substr(autocompleteText.length);
        autocompleteMatch.innerHTML += `<input type='hidden' id='${tempId}' value='${item}'>`;

        autocompleteMatch.addEventListener('click', (event) => {
          const clickedElement = event.target.getElementsByTagName('input')[0];

          inputElement.value = clickedElement.value;
          hideList();
        });

        autocompleteList.appendChild(autocompleteMatch);
      }
    });
  });

  inputElement.addEventListener('keydown', function (e) {
    const autoCompleteList = document.getElementById('autocomplete-list');
    var autoCompleteDiv;

    if (autoCompleteList) {
      autoCompleteDiv = autoCompleteList.getElementsByTagName('div');
    }

    if (e.keyCode === 40) {
      // KEY DOWN
      currentFocus++;
      addActive(autoCompleteDiv);
    } else if (e.keyCode === 38) {
      // KEY UP
      currentFocus--;
      addActive(autoCompleteDiv);
    } else if (e.keyCode === 13) {
      // ENTER
      e.preventDefault();

      if (currentFocus > -1 && autoCompleteDiv) {
        autoCompleteDiv[currentFocus].click();
      }
    }
  });

  const addActive = (item) => {
    if (!item) {
      return false;
    }

    removeActive(item);

    if (currentFocus >= item.length) {
      currentFocus = 0;
    }

    if (currentFocus < 0) {
      currentFocus = item.length - 1;
    }

    item[currentFocus].classList.add('autocomplete-active');
  };

  const removeActive = (autoCompleteItems) => {
    Array.from(autoCompleteItems).forEach((item) => {
      item.classList.remove('autocomplete-active');
    });
  };

  const hideList = (element) => {
    var autoCompleteItems =
      document.getElementsByClassName('autocomplete-items');

    if (autoCompleteItems && autoCompleteItems.length > 0) {
      Array.from(autoCompleteItems).forEach((item) => {
        if (element !== item && element !== inputElement) {
          item.parentNode.removeChild(item);
        }
      });
    }
  };

  document.addEventListener('click', (event) => hideList(event.target));
};

// this part binds the autocomplete with the HTML
window.addEventListener('load', function () {
  const container = document.getElementById('autocomplete-container');
  const inputElement = document.getElementById('autocomplete-input');

  autocomplete(container, inputElement, data);
});
  1. CSS
* { box-sizing: border-box; }

body {
  font: 16px Arial;
}

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

input {
  border: 1px solid transparent;
  background-color: #f1f1f1;
  padding: 10px;
  font-size: 16px;
}

input[type=text] {
  background-color: #f1f1f1;
  width: 100%;
}

input[type=submit] {
  background-color: DodgerBlue;
  color: #fff;
}

.autocomplete-items {
  position: absolute;
  border: 1px solid #d4d4d4;
  border-bottom: none;
  border-top: none;
  z-index: 99;
  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 {
  background-color: #e9e9e9;
}

.autocomplete-active {
  background-color: DodgerBlue !important;
  color: #ffffff;
}

基于 W3School - 操作方法 - 自动完成

实时版本 - Codesandbox

示例

Daniel Santana
2021-08-19

尝试此代码

var searchTerms = ["OneDrive sync issue", "Abcde", "123456"];
var result = document.getElementById("result");
rul = document.createElement("ul");
result.appendChild(rul);
rul.classList.add("datalist");
for(var x = 0; x < searchTerms.length; x++ ){
  rli = document.createElement("li");
  rul.appendChild(rli);
  rli.innerHTML = searchTerms[x];
  rli.classList.add("d-none");
  rli.addEventListener("click", function(){
    document.getElementById("id_post").value = this.innerHTML;
    this.classList.add("d-none");
  });
}
function showResults(v){
  var ListItems = rul.querySelectorAll("li");
  for(var i = 0; i < ListItems.length; i++){
      var c = ListItems[i].innerHTML.toLowerCase();
      v = v.toLowerCase();
      if(c.indexOf(v) > -1 && v !== ""){
        ListItems[i].classList.remove("d-none");
      }
      else{
        ListItems[i].classList.add("d-none");
      }
  }
}
.d-none{ display:none; }
.datalist li{ cursor:pointer; }
<input 
  type="text" 
  class="form-control" 
  placeholder="Explain in fewer words with the primary product key word (Eg: OneDrive sync issue, etc.)" 
  name="post" 
  required 
  id="id_post" 
  onKeyUp="showResults(this.value)">
<span 
  class="fas fa-asterisk" 
  style="font-size:12px;color:red;position:absolute; right:20px;top:12px;" 
  id="asterix"></span>
<div id="result"></div>
nxt
2021-08-19