以下类监听输入元素上的“keyup”事件。然后通过
get_matches()
,它从其列表search_terms
中找到与输入的术语匹配的所有术语。然后通过show_matches()
,显示autocomplete_container
中的所有匹配项。
我的问题是
search_terms
列表需要从我的服务器检索,我只想发送一个请求来这样做,而且我只想在搜索栏被使用时发送它。为了解决这个问题,我创建了一个方法get_search_terms()
,它只在第一个“keyup”事件上触发。但这会导致一些不理想的行为,这就是我要问如何解决这个问题:
如果我的第一个输入是“a”然后我等待
get_search_terms()
完成,我会在方法完成后弹出自动完成列表,并显示“alice”。但是,相反,在我现在的代码中,get_matches()
方法只是在 search_terms
列表仍然为 null 时运行,导致什么也没有发生。
我想过使用 async / await 来解决这个问题,但是,另一个问题是如果用户输入“a”,然后删除它,然后输入“b”,所有这些都是在
search_terms
列表被检索之前。在这种情况下,一旦列表被检索到,它将显示“alice”而不是“bob”,因为它在初始“a”输入发生后等待。
class Searchbar {
constructor() {
this.elm_form = document.querySelector(".form_search");
this.elm_input = document.querySelector(".inp_search");
this.elm_autocomplete_container = document.querySelector(".autocomplete_container");
this.search_terms = null;
this.search_terms_requested = false;
this.elm_input.addEventListener("keyup", () => {
if (!this.search_terms && !this.search_terms_requested) {
this.search_terms_requested = true;
this.get_search_terms();
}
this.show_matches(this.get_matches(this.elm_input.value));
});
}
get_search_terms() {
setTimeout(() => {
this.search_terms = ["alice", "bob", "charlie", "dylan", "eric", "finn", "greg", "harry", "ian", "jenny", "ken", "liam", "mike", "nick", "oscar", "patrick", "quinn", "rick", "sara", "tom", "una", "victor", "wally", "xaro", "yila", "zara"];
console.log("search terms retrieved");
}, 2000);
}
get_matches(input_term) {
if (input_term === "") return [];
let reg = new RegExp(`^${input_term}`, "i");
return this.search_terms?.filter((search_term) => {
return reg.test(search_term);
});
}
show_matches(matches) {
if (!matches || matches.length === 0) {
this.elm_autocomplete_container.classList.remove("shown");
} else {
this.elm_autocomplete_container.innerHTML = ``;
matches.forEach(match => {
this.elm_autocomplete_container.innerHTML += `<li>${match}</li>`;
});
this.elm_autocomplete_container.classList.add("shown");
}
}
}
const my_searchbar = new Searchbar();
.form_search {
position: relative;
width: 20rem;
}
.inp_search {
width: 100%;
}
.autocomplete_container {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
background-color: #eee;
}
.autocomplete_container.shown {
display: block;
}
<form class="form_search">
<input class="inp_search" type="text">
<ul class="autocomplete_container"></ul>
</form>