方案
我已经构建了自动填充的自定义自动完成选择组件,但此外,如果找不到结果,我们可以添加新值。(我发现在vue-select模块中无法实现)。
问题
我尝试使用@blur,但如果点击该项目,菜单将会关闭。 我将自定义div作为选项的列表,如果焦点在文本字段上,则选择哪个项目。如果我删除模糊它完美但它不会关闭它我点击文本字段之外。 我已经复制了处理keyup,keydown,keyenter,scrolling,处理指针以选择vue-select的函数
CODE
<template>
<div class="vselect">
<div class="form-group">
<label>{{label}}</label>
<p class="control has-icon has-icon-right">
<input ref="selected" @keyup="filterSelect($event)" @focus="onFocus" v-model="mutableValue" type="text" class="form-control"
@keydown.up.prevent="onKeyUp" @keydown.down.prevent="onKeyDown" @keydown.enter.prevent="onKeyEnter" @blur="onBlur">
</p>
</div>
<div ref="dropdown" class="my-dropdown" v-show="toggled" v-if="options">
<div v-for="(item,index) in filterList" :class="{'my-dropdwon--item':true,active:index === pointer}" @click="handleItemClick(item)"
@mouseover="pointer = index">{{item}}</div>
</div>
</div>
</template>
<script>
export default {
name: 'VSelect',
props: {
'options': Array,
'label': String,
'value': String,
},
data() {
return {
selected: null,
toggled: false,
filterList: [],
mutableValue: null,
mutableOptions: [],
pointer: 0
}
},
methods: {
filterSelect: function (key) {
if (!this.toggled) this.toggled = !this.toggled;
let oldArr = this.options;
if (this.mutableValue && this.mutableValue.length <= 0)
this.filterList = this.mutableOptions;
else if (key.key.length == 1 || key.key == 'Backspace') {
oldArr = oldArr.filter(item => {
if (item.toLowerCase().includes(this.mutableValue.toLowerCase()))
return true;
})
this.filterList = oldArr;
//console.log('type', this.filterList)
}
// if (key.key == 'Enter')
// this.toggled = !this.toggled;
this.$emit('input', this.mutableValue);
},
handleItemClick: function (item) {
this.mutableValue = item;
this.$emit('input', item);
this.toggled = !this.toggled;
},
onFocus: function () {
this.$refs.dropdown.scrollTop = 0;
this.toggled = !this.toggled;
},
onBlur: function () {
this.handleItemClick(this.mutableValue)
this.$refs.selected.blur();
},
onKeyUp: function () {
if (this.pointer > 0) this.pointer--;
if (this.maybeAdjustScroll) {
this.maybeAdjustScroll()
}
},
onKeyDown: function () {
if (this.pointer < this.options.length && this.filterList.length) this.pointer++;
if (this.pointer == this.options.length) this.pointer = 0;
if (this.maybeAdjustScroll) {
this.maybeAdjustScroll()
}
},
onKeyEnter: function () {
//console.log(this.filterList.length> 0);
if(this.filterList.length > 0)
this.handleItemClick(this.filterList[this.pointer])
this.$refs.selected.blur();
this.$emit('input', this.mutableValue);
this.toggled = false;
},
maybeAdjustScroll() {
let pixelsToPointerTop = this.pixelsToPointerTop()
let pixelsToPointerBottom = this.pixelsToPointerBottom()
//console.log(pixelsToPointerTop,pixelsToPointerBottom);
if (pixelsToPointerTop <= this.viewport().top) {
return this.scrollTo(pixelsToPointerTop)
} else if (pixelsToPointerBottom >= this.viewport().bottom) {
return this.scrollTo(this.viewport().top + this.pointerHeight())
}
},
pixelsToPointerTop() {
let pixelsToPointerTop = 0
if (this.$refs.dropdown && this.$refs.dropdown.children) {
for (let i = 0; i < this.pointer; i++) {
pixelsToPointerTop += this.$refs.dropdown.children[i].offsetHeight
}
}
return pixelsToPointerTop
},
pixelsToPointerBottom() {
return this.pixelsToPointerTop() + this.pointerHeight()
},
pointerHeight() {
let element = this.$refs.dropdown ? this.$refs.dropdown.children[this.pointer] : false
return element ? element.offsetHeight : 0
},
viewport() {
return {
top: this.$refs.dropdown ? this.$refs.dropdown.scrollTop : 0,
bottom: this.$refs.dropdown ? this.$refs.dropdown.offsetHeight + this.$refs.dropdown.scrollTop : 0
}
},
scrollTo(position) {
//console.log(position);
return this.$refs.dropdown ? this.$refs.dropdown.scrollTop = position : null
},
},
mounted() {
this.filterList = this.options;
},
watch: {
value(val) {
this.mutableValue = val
},
options(val) {
this.mutableOptions = val
},
pointer() {
this.maybeAdjustScroll()
}
}
}
</script>
<style scoped>
.vselect {
display: block;
position: relative;
}
.my-dropdown {
width: 100%;
background: #f7f7f7;
margin-top: 0.1rem;
border: 1px solid #ced4da;
border-radius: 3px;
transition: all 0.5s;
position: absolute;
z-index: 1;
max-height: 10rem;
overflow: auto
}
.my-dropdwon--item {
padding: 0.5rem;
width: 100%;
transition: all 0.5s;
}
.active {
cursor: pointer;
background-color: rgb(223, 221, 221);
}
/* .my-dropdwon--item:hover {
cursor: pointer;
background-color: rgb(223, 221, 221);
} */
.form-group {
margin-bottom: 0px;
}
.control.has-icon has-icon-right {
margin-bottom: 0px;
}
.form-group>p {
margin-bottom: 0px;
}
</style>
答案 0 :(得分:1)
我以前遇到过同样的问题。
问题是blur
事件将首先被触发,它将隐藏选择列表。然后click
事件将不会被触发。
我的解决方案是将@click
替换为@mousedown
事件
<div v-for="(item,index) in filterList"
:class="{'my-dropdwon--item':true,active:index === pointer}"
@mousedown="handleItemClick(item)"
@mouseover="pointer = index">
{{item}}
</div>
检查我的演示