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

时间:2018-05-13 07:04:25

标签: javascript vue.js

方案

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

Codepen Link

问题

我尝试使用@blur,但如果点击该项目,菜单将会关闭。 我将自定义div作为选项的列表,如果焦点在文本字段上,则选择哪个项目。如果我删除模糊它完美但它不会关闭它我点击文本字段之外。 我已经复制了处理keyup,keydown,keyenter,scrolling,处理指针以选择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>

1 个答案:

答案 0 :(得分:1)

我以前遇到过同样的问题。

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

检查我的演示