128 lines
3.2 KiB
Vue
128 lines
3.2 KiB
Vue
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
search: '',
|
|
results: [],
|
|
isOpen: false,
|
|
arrowCounter: 0,
|
|
}
|
|
},
|
|
props: {
|
|
items: {
|
|
type: Array,
|
|
required: false,
|
|
default: () => [],
|
|
},
|
|
isAsync: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
}
|
|
},
|
|
watch: {
|
|
items: function (value, oldValue) {
|
|
if (this.isAsync) {
|
|
this.results = value;
|
|
this.isOpen = true;
|
|
this.isLoading = false;
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
onchange() {
|
|
this.$emit('input', this.search)
|
|
|
|
if (this.isAsync) {
|
|
this.isLoading = true;
|
|
} else if(this.search.length > 0) {
|
|
this.filter();
|
|
this.isOpen = true;
|
|
} else {
|
|
this.isOpen = false;
|
|
}
|
|
this.arrowCounter = 0;
|
|
},
|
|
filter() {
|
|
this.results = this.items.filter(item => item.toLowerCase().indexOf(this.search.toLowerCase()) > -1);
|
|
},
|
|
setResult(result) {
|
|
this.search = result;
|
|
this.isOpen = false;
|
|
},
|
|
handleClickOutside(event) {
|
|
if (!this.$el.contains(event.target)) {
|
|
this.isOpen = false;
|
|
this.arrowCounter = 0;
|
|
}
|
|
},
|
|
bumpUp() {
|
|
console.log("bumpup")
|
|
console.log(this.arrowCounter, " ", this.results.length)
|
|
|
|
if (this.arrowCounter > 0) {
|
|
this.arrowCounter -= 1;
|
|
}
|
|
},
|
|
bumpDown() {
|
|
console.log("bumpdown")
|
|
console.log(this.arrowCounter, " ", this.results.length)
|
|
|
|
if (this.arrowCounter < this.results.length - 1) {
|
|
this.arrowCounter += 1;
|
|
}
|
|
},
|
|
select() {
|
|
this.search = this.results[this.arrowCounter];
|
|
this.arrowCounter = 0;
|
|
this.isOpen = false;
|
|
},
|
|
},
|
|
mounted() {
|
|
document.addEventListener('click', this.handleClickOutside)
|
|
},
|
|
unmounted() {
|
|
document.removeEventListener('click', this.handleClickOutside)
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="relative">
|
|
<input type="text" v-model="search" @input="onchange" @keydown.down="bumpDown" @keydown.up="bumpUp"
|
|
@keydown.enter="select" @keydown.tab="select" :class="{}"
|
|
class="bg-gray-light rounded-md text-white focus:outline-none p-1 px-2"/>
|
|
<ul id="results" v-show="isOpen">
|
|
<li class="result" v-for="(result, i) in results" :key="i" @click="setResult(result)"
|
|
:class="{ 'is-active': i === arrowCounter }">
|
|
{{ result }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
#results {
|
|
position: absolute;
|
|
padding: 0;
|
|
margin: 0;
|
|
border: 1px solid #eeeeee;
|
|
height: max-content;
|
|
/* min-height: 1em;
|
|
max-height: 6em; */
|
|
overflow: auto;
|
|
}
|
|
|
|
.result {
|
|
list-style: none;
|
|
text-align: left;
|
|
padding: 4px 2px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.result.is-active,
|
|
.result:hover {
|
|
background-color: #01bde7;
|
|
color: white;
|
|
}
|
|
</style> |