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

查看:26
本文介绍了Vuejs 模糊自定义选择元素不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

场景

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

Codepen 链接

问题

我尝试使用@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).

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>

解决方案

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

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆