脚本
我已经构建了自定义的自动完成选择组件,在那里它自动完成,但是另外,如果没有找到结果,我们可以添加新的值(我发现它在vue-select模块中是不可能的)。
Codepen Link
题
我尝试使用@blur,但如果点击该项目,菜单会关闭。 如果焦点位于文本字段上,我已将自定义div作为用于选择切换哪些项目的列表。 如果我删除模糊它完美的作品,但它不会关闭它,我点击文本字段外。 我已经复制函数来处理keyup,keydown,keyenter,滚动,处理vue-select中的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>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).
Codepen Link
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>最满意答案
我之前也有同样的问题。
问题是blur事件会先被触发,它会隐藏选择列表。 然后click事件不会被解雇。
我的解决方案是用@mousedown事件替换@click
<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查看我的演示
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
更多推荐
发布评论