自动完成 - 通过鼠标单击选择选项 - vuejs



前段时间我在 vue 中为我参与的一个项目创建了一个自动完成组件。

但是今天我发现了一个小错误。

当我通过单击鼠标选择所需的选项时,该选项不会被传输,如示例中的console.log ()所示。如果我再次单击另一个选项,console.log ()中显示的是之前选择的选项。

如果我放一个setTimeout( () => {}, 200)它已经检测到并发出该选项,但我认为这不是这种情况的最佳解决方案。

有什么建议吗?

const Autocomplete = {
name: "autocomplete",
template: "#autocomplete",
props: {
items: {
type: Array,
required: false,
default: () => Array(150).fill().map((_, i) => `Fruit ${i+1}`)
},
isAsync: {
type: Boolean,
required: false,
default: false
}
},
data() {
return {
isOpen: false,
results: [],
search: "",
isLoading: false,
arrowCounter: 0
};
},
methods: {
onChange() {
console.log( this.search)
// Let's warn the parent that a change was made
this.$emit("input", this.search);
},
setResult(result, i) {
this.arrowCounter = i;
this.search = result;
this.isOpen = false;
},
showAll() {
this.isOpen = !this.isOpen;
			(this.isOpen) ? this.results = this.items : this.results = [];
},
},
computed: {
filterResults() {
// first uncapitalize all the things
this.results = this.items.filter(item => {
return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
});


return this.results;
},
},
watch: {
items: function(val, oldValue) {
// actually compare them
if (val.length !== oldValue.length) {
this.results = val;
this.isLoading = false;
}
}
},
mounted() {
document.addEventListener("click", this.handleClickOutside);
},
destroyed() {
document.removeEventListener("click", this.handleClickOutside);
}
};
new Vue({
el: "#app",
name: "app",
components: {
autocomplete: Autocomplete
}
});
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.autocomplete {
position: relative;
width: 130px;
}
.autocomplete-results {
padding: 0;
margin: 0;
border: 1px solid #eeeeee;
height: 120px;
overflow: auto;
width: 100%;
}
.autocomplete-result {
list-style: none;
text-align: left;
padding: 4px 2px;
cursor: pointer;
}
.autocomplete-result.is-active,
.autocomplete-result:hover {
background-color: #4aae9b;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<autocomplete />
</div>
<script type="text/x-template" id="autocomplete">
<div class="autocomplete">
<input type="text" @blur="onChange" v-model="search"  @click="showAll" />
<ul id="autocomplete-results" v-show="isOpen" ref="scrollContainer" class="autocomplete-results">
<li class="loading" v-if="isLoading">
Loading results...
</li>
<li ref="options" v-else v-for="(result, i) in filterResults" :key="i" @click="setResult(result, i)" class="autocomplete-result" :class="{ 'is-active': i === arrowCounter }">
{{ result }}
</li>
</ul>
</div>
</script>

您使用的是 onblur 事件,但当您在外部和 onclick 的项目侦听器之前单击时,该事件会触发,因此该值未更新。

如果用户在输入中键入任何内容并在 setResult(( 中调用 onChange(( 方法,则使用 onchange 事件捕获数据。

const Autocomplete = {
name: "autocomplete",
template: "#autocomplete",
props: {
items: {
type: Array,
required: false,
default: () => Array(150).fill().map((_, i) => `Fruit ${i+1}`)
},
isAsync: {
type: Boolean,
required: false,
default: false
}
},
data() {
return {
isOpen: false,
results: [],
search: "",
isLoading: false,
arrowCounter: 0
};
},
methods: {
onChange() {
console.log( this.search)
// Let's warn the parent that a change was made
this.$emit("input", this.search);
},
setResult(result, i) {
this.arrowCounter = i;
this.search = result;
this.isOpen = false;
// Fire onChange, because it won't do it on blur
this.onChange();
},
showAll() {
this.isOpen = !this.isOpen;
			(this.isOpen) ? this.results = this.items : this.results = [];
},
},
computed: {
filterResults() {
// first uncapitalize all the things
this.results = this.items.filter(item => {
return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
});


return this.results;
},
},
watch: {
items: function(val, oldValue) {
// actually compare them
if (val.length !== oldValue.length) {
this.results = val;
this.isLoading = false;
}
}
},
mounted() {
document.addEventListener("click", this.handleClickOutside);
},
destroyed() {
document.removeEventListener("click", this.handleClickOutside);
}
};
new Vue({
el: "#app",
name: "app",
components: {
autocomplete: Autocomplete
}
});
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.autocomplete {
position: relative;
width: 130px;
}
.autocomplete-results {
padding: 0;
margin: 0;
border: 1px solid #eeeeee;
height: 120px;
overflow: auto;
width: 100%;
}
.autocomplete-result {
list-style: none;
text-align: left;
padding: 4px 2px;
cursor: pointer;
}
.autocomplete-result.is-active,
.autocomplete-result:hover {
background-color: #4aae9b;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<autocomplete />
</div>
<script type="text/x-template" id="autocomplete">
<div class="autocomplete">
<input type="text" @change="onChange" v-model="search"  @click="showAll" />
<ul id="autocomplete-results" v-show="isOpen" ref="scrollContainer" class="autocomplete-results">
<li class="loading" v-if="isLoading">
Loading results...
</li>
<li ref="options" v-else v-for="(result, i) in filterResults" :key="i" @click="setResult(result, i)" class="autocomplete-result" :class="{ 'is-active': i === arrowCounter }">
{{ result }}
</li>
</ul>
</div>
</script>

blur在这里使用是错误的事件,我认为你把它复杂化了。只需拨打您的emitsetResult

setResult(result, i) {
this.arrowCounter = i;
this.search = result;
this.isOpen = false;     
this.$emit("input", this.search);
},

最新更新