const AutoCompleteComponent = {
data() {
return {
open: false,
current: 0,
/** @type {string[]} **/
suggestions: ["first", "ble", "hello"],
fieldWidth: 0,
}
},
mounted() {
this.fieldWidth = this.$refs.inputField.clientWidth;
},
methods: {
focus() {
console.log("Focus activated");
this.open = true;
},
blur() {
console.log("Focus deactivated")
// when I do this, the suggestions dissappear the frame before they are
// clicked, causing the suggestionClick to not be called
this.open = false;
},
//For highlighting element
isActive(index) {
return index === this.current;
},
//When the user changes input
change() {
this.loadSuggestions();
//console.log("change()");
if (this.open == false) {
this.open = true;
this.current = 0;
}
},
//When one of the suggestion is clicked
suggestionClick(index) {
this.currentText = this.matches[index];
console.log("Clicked suggestion: ", index, this.matches[index]);
this.open = false;
},
},
computed: {
/**
* Filtering the suggestion based on the input
* @this {ReturnType<AutoCompleteComponent["data"]>}
*/
matches() {
console.log("computed.matches() str=", this.currentText, " suggestions=", this.suggestions);
return this.suggestions.filter((str) => {
const withoutAccents = str.toLowerCase();
return withoutAccents.indexOf(this.currentText.toLowerCase()) >= 0;
});
},
//The flag
openSuggestion() {
return this.currentText !== "" &&
this.matches.length != 0 &&
this.open === true;
},
copiedWidth() {
return this.fieldWidth + "px";
}
},
template: "#vue-auto-complete-template"
};
这是HTML模板:
<template id="vue-auto-complete-template">
<div v-bind:class="{'open':openSuggestion}" class="auto-complete-field">
<div class="field-wrapper">
<input class="form-control" type="text" v-model="currentText" @keydown.enter='enter' @keydown.down='down'
@keydown.up='up' @input='change' @focus="focus" @blur="blur" ref="inputField" />
</div>
<div class="suggestions-wrapper">
<ul class="field-suggestions" :style="{ width: copiedWidth }" >
<li v-for="(suggestion, suggestion_index) in matches" v-bind:class="{'active': isActive(suggestion_index)}"
@click="suggestionClick(suggestion_index)">
{{ suggestion }}
</li>
</ul>
</div>
</div>
</template>
所以我这样创建它:
<AutoCompleteComponent class="some class names"></AutoCompleteComponent>
为了使其出现在现场下,应用了以下CSS:
.auto-complete-field {
display:inline-block;
}
.auto-complete-field .suggestions-wrapper {
display:block;
position: relative;
}
.auto-complete-field.open ul {
display:initial;
}
.auto-complete-field ul {
list-style:none;
padding:0;
margin:0;
display: none;
position: absolute;
top:0px;
left: 0px;
border-bottom: 1px solid black;
}
.auto-complete-field ul li {
background-color: white;
border: 1px solid black;
border-bottom: none;
}
现在问题是,如果您查看blur()
函数,它将设置为false,而false又可以使用
open
类名称隐藏建议。由于处理事件的顺序,
ul.field-suggestions
在创建点击事件之前,该场上的事件隐藏了active
,从而使其在其下面的任何内容上被调用。
Quick和肮脏的补救措施将是blur
。我认为这样可以使用,至少必须是两个渲染帧。它没有用作微型审判也不起来。我不想使用超时,尤其是大型超时,因为它可能会通过快速点击引起gui闪烁。 我正在为此寻求更坚实的解决方案。我希望Vue为此有所作为。普通的JS解决方案通常是通过在窗口上的多个事件中聆听并检查其发生的位置来重新实现模糊事件。我宁愿避免这种情况。您应该尝试
.auto-complete-field.open ul
而不是
setTimeout(()=>{this.open=false}, 100)
??i我在我的VUE3项目上重现了您的代码,他的工作(直到单击建议的项目完成后完成完成后才召集)
@mousedown