Skip to content

Instantly share code, notes, and snippets.

@zealot128
Created May 6, 2021 08:49
Show Gist options
  • Select an option

  • Save zealot128/cf102ccfa03142fb2e5465ed8e443573 to your computer and use it in GitHub Desktop.

Select an option

Save zealot128/cf102ccfa03142fb2e5465ed8e443573 to your computer and use it in GitHub Desktop.
<template lang="pug">
form(@submit.prevent.stop="enterCurrentSelected")
.form-autocomplete(@blur.native='blur' @unfocus='blur')
.input-group.form-autocomplete-input
input.form-input.input-lg(
ref='input'
type="text" name="query" v-model.sync="query" placeholder="搜索查询" autocomplete="off" autofocus @blur='blur'
@keydown.right='selectCurrentContinue'
@keydown.up='selectPrevious'
@keydown.down='selectNext'
@keydown.enter='enterCurrentSelected'
)
button.btn.btn-primary.input-group-btn.btn-lg(@click="search")
i.mdi.mdi-magnify
transition(name='slide')
ul.menu.search-bar--autocomplete-menu(v-if='autocompleteVisible')
li.menu-item(v-for='(item, i) in autocompleteItems' :key='item')
a(@click='selectAndContinue(item)' class='float-right')
i.mdi.mdi-arrow-top-right
a(@click='selectItemAndSearch(item)' :class='{active: i == autocompleteFocusItem }')
|{{item}}
</template>
<script>
import _throttle from 'lodash/throttle'
export default {
props: {
url: { type: String, required: true }
},
data() {
return {
query: "",
searchOpen: false,
showAutocomplete: true,
autocompleteFocusItem: null,
autocompleteItems: []
};
},
computed: {
autocompleteVisible() {
return this.autocompleteItems.length > 0 && this.showAutocomplete;
}
},
watch: {
query() {
this.throttledAutocomplete();
}
},
mounted() {
this.throttledAutocomplete = _throttle(this.autocomplete.bind(this), 300);
},
methods: {
selectCurrentContinue(event) {
if (this.showAutocomplete && this.autocompleteFocusItem !== null) {
event.preventDefault();
this.autocompleteFocusItem = null
this.selectItem(this.autocompleteItems[this.autocompleteFocusItem]);
}
},
selectAndContinue(item) {
this.autocompleteFocusItem = null
this.selectItem(item);
},
enterCurrentSelected(event) {
event.preventDefault();
if (this.showAutocomplete && this.autocompleteFocusItem !== null) {
event.preventDefault();
this.selectItemAndSearch(this.autocompleteItems[this.autocompleteFocusItem]);
} else {
this.search()
}
},
selectPrevious(e) {
if (this.showAutocomplete) {
if (this.autocompleteFocusItem == null) {
this.autocompleteFocusItem = 0
}
this.autocompleteFocusItem =
(this.autocompleteFocusItem - 1) % this.autocompleteItems.length;
e.preventDefault();
}
},
selectNext(e) {
if (this.showAutocomplete) {
if (this.autocompleteFocusItem == null) {
this.autocompleteFocusItem = 0
} else {
this.autocompleteFocusItem =
(this.autocompleteFocusItem + 1) % this.autocompleteItems.length;
}
e.preventDefault();
}
},
blur(event) {
window.setTimeout(() => {
this.showAutocomplete = false;
}, 100)
},
search() {
this.showAutocomplete = false;
this.$emit("submit", this.query);
},
selectItem(item) {
this.query = item;
},
selectItemAndSearch(item) {
this.selectItem(item)
this.showAutocomplete = false;
this.search();
this.$nextTick(() => (this.showAutocomplete = false));
},
async autocomplete(ev) {
if (!this.showAutocomplete) {
this.autocompleteFocusItem = null;
this.showAutocomplete = true;
}
if (this.query.length === 0) {
this.showAutocomplete = false;
return;
}
const response = await this.$http.get(this.url, {
params: { q: this.query }
});
if (response.data.words.length === 1 && response.data.words.length[0].toLowerCase() === this.query.toLowerCase()) {
this.autocompleteItems = [];
this.autocompleteFocusItem = 0;
return;
}
this.autocompleteItems = response.data.words;
}
}
};
</script>
<style lang="sass" scoped>
.search-bar--autocomplete-menu {
position: absolute;
}
.slide-enter-active {
transition-duration: 0.1s;
transition-timing-function: ease-in-out;
}
.slide-leave-active {
transition-duration: 0.05s;
transition-timing-function: ease-out;
}
.slide-enter-to, .slide-leave {
max-height: 100px;
overflow: hidden;
opacity: 1.0;
}
.slide-enter, .slide-leave-to {
overflow: hidden;
opacity: 0;
max-height: 0;
}
.menu .menu-item > a:active, .menu .menu-item > a.active {
color: white;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment