自定义选择元素的模糊 Vuejs 不起作用



场景

我已经构建了自定义自动完成选择组件,它可以自动完成,但除此之外,如果找不到结果,我们可以添加新值。(我发现在 vue-select 模块中是不可能的(。

代码笔链接

问题

我尝试使用@blur但是如果我单击该项目,菜单就会关闭。 我将div 自定义为项目列表,用于选择在焦点在文本字段上时切换的项目。如果我删除模糊,它可以完美工作,但它没有被关闭,我单击文本字段之外。我已经复制了用于处理键向上,向下键,键输入,滚动,处理从vue-select中选择的指针的函数

法典

<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>

我以前和你有同样的问题。

问题是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>

在 https://codepen.io/ittus/pen/qYKRPv 查看我的演示

最新更新