Vuejs模糊自定义选择元素不起作用(Vuejs on blur for custom select element not working)

编程入门 行业动态 更新时间:2024-10-27 08:25:18
Vuejs模糊自定义选择元素不起作用(Vuejs on blur for custom select element not working)

脚本

我已经构建了自定义的自动完成选择组件,在那里它自动完成,但是另外,如果没有找到结果,我们可以添加新的值(我发现它在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

更多推荐

本文发布于:2023-08-04 09:17:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1414865.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:自定义   不起作用   元素   模糊   Vuejs

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!