Vuejs 模糊自定义选择元素不起作用 [英] Vuejs on blur for custom select element not working
问题描述
场景
我已经构建了自定义的自动完成选择组件,它会自动完成,但另外,如果没有找到结果,我们可以添加新值.(我发现在 vue-select 模块中是不可能的).
问题
我尝试使用@blur,但如果我点击该项目,菜单就会关闭.我已自定义 div 作为项目列表,用于选择如果焦点位于文本字段上将切换哪个项目.如果我删除模糊,它可以完美运行,但它不会关闭它,我在文本字段外单击.我已经复制了用于处理 keyup、keydown、keyenter、滚动、处理从 vue-select 中选择的指针的函数
代码
<模板><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 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>
</模板><脚本>导出默认{name: 'VSelect',道具: {'选项':数组,'标签':字符串,'值':字符串,},数据() {返回 {选择:空,切换:假,过滤器列表:[],可变值:空,可变选项:[],指针:0}},方法: {过滤器选择:功能(键){如果 (!this.toggled) this.toggled = !this.toggled;让 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 => {如果 (item.toLowerCase().includes(this.mutableValue.toLowerCase()))返回真;})this.filterList = oldArr;//console.log('type', this.filterList)}//if (key.key == '回车')//this.toggled = !this.toggled;this.$emit('input', this.mutableValue);},handleItemClick:函数(项目){this.mutableValue = 项目;this.$emit('input', item);this.toggled = !this.toggled;},焦点:函数(){this.$refs.dropdown.scrollTop = 0;this.toggled = !this.toggled;},onBlur: 函数 () {this.handleItemClick(this.mutableValue)this.$refs.selected.blur();},onKeyUp: 函数 () {if (this.pointer > 0) this.pointer--;如果(this.maybeAdjustScroll){this.maybeAdjustScroll()}},onKeyDown: 函数 () {if (this.pointer < this.options.length && this.filterList.length) this.pointer++;if (this.pointer == this.options.length) this.pointer = 0;如果(this.maybeAdjustScroll){this.maybeAdjustScroll()}},onKeyEnter: 函数 () {//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;},也许调整滚动(){让 pixelToPointerTop = this.pixelsToPointerTop()让 pixelToPointerBottom = this.pixelsToPointerBottom()//console.log(pixelsToPointerTop,pixelsToPointerBottom);if (pixelsToPointerTop <= this.viewport().top) {返回 this.scrollTo(pixelsToPointerTop)} else if (pixelsToPointerBottom >= this.viewport().bottom) {返回 this.scrollTo(this.viewport().top + this.pointerHeight())}},pixelToPointerTop() {让pixelsToPointerTop = 0如果 (this.$refs.dropdown && this.$refs.dropdown.children) {for (let i = 0; i < this.pointer; i++) {pixelToPointerTop += this.$refs.dropdown.children[i].offsetHeight}}返回pixelsToPointerTop},pixelToPointerBottom() {返回 this.pixelsToPointerTop() + this.pointerHeight()},指针高度(){让元素 = this.$refs.dropdown ?this.$refs.dropdown.children[this.pointer] : false返回元素?element.offsetHeight : 0},视口(){返回 {顶部: this.$refs.dropdown ?this.$refs.dropdown.scrollTop : 0,底部: this.$refs.dropdown ?this.$refs.dropdown.offsetHeight + this.$refs.dropdown.scrollTop : 0}},滚动到(位置){//console.log(位置);返回 this.$refs.dropdown ?this.$refs.dropdown.scrollTop = 位置:空},},安装(){this.filterList = this.options;},手表: {价值(价值){this.mutableValue = val},选项(val){this.mutableOptions = val},指针(){this.maybeAdjustScroll()}}}<样式范围>.vselect {显示:块;位置:相对;}.my-下拉{宽度:100%;背景:#f7f7f7;边距顶部:0.1rem;边框:1px 实心 #ced4da;边框半径:3px;过渡:全0.5s;位置:绝对;z-索引:1;最大高度:10rem;溢出:自动}.my-dropdwon--item {填充:0.5rem;宽度:100%;过渡:全0.5s;}.积极的 {光标:指针;背景颜色:RGB(223、221、221);}/* .my-dropdwon--item:hover {光标:指针;背景颜色:RGB(223、221、221);} */.form-group {底边距:0px;}.control.has-icon has-icon-right {底边距:0px;}.form-group>p {底边距:0px;}</风格>
我之前也遇到过同样的问题.
问题是 blur
事件将首先被触发,它将隐藏选择列表.然后 click
事件不会被触发.
我的解决方案是用 @mousedown
事件替换 @click
事件
{{物品}}
在 https://codepen.io/ittus/pen/qYKRPv
Scenario
I've built custom autocomplete select component where it autocompletes but in addition, if the result is not found we can add new value.(I found it is not possible in vue-select module).
Question
I tried using @blur but the menu gets closed if I click on the item. I've custom div as a list of items for selecting which is getting toggled if the focus is on text field. If I remove blur it works perfect but it doesn't get closed it I click outside of text field. I've copied functions for handling keyup,keydown,keyenter,scrolling,handling pointer for select from 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>
I have same problem with you before.
The problem is blur
event will be fired first, it will hide the list of selection. Then click
event will not be fired.
My solution is replacing @click
with @mousedown
event
<div v-for="(item,index) in filterList"
:class="{'my-dropdwon--item':true,active:index === pointer}"
@mousedown="handleItemClick(item)"
@mouseover="pointer = index">
{{item}}
</div>
Check my demo at https://codepen.io/ittus/pen/qYKRPv
这篇关于Vuejs 模糊自定义选择元素不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!