【解决方案】选择器组件开发中,下拉框显示隐藏中出现的问题及解决方式

468 阅读2分钟

当我们在开发选择器组件的时候,一定会遇到一个问题,点击选项时,让下拉框隐藏,无法触发选项的点击事件选中选项

以下是两种解决方案,mark下来,下次你女朋友问你的时候,直接那这篇笔记给她看

使用input的focus和blur事件控制下拉框显示隐藏

在使用 input 的 focus 和 blur 事件控制下拉框的显示隐藏时,如果点击选项时,会先触发 input 的 blur 事件让下拉框隐藏,隐藏后无法触发选项的点击事件

<template>
    <div>
        <input @focus="handleFocus" @blur="handleBlur">
        <ul>
            <li @click="handleClick"></li>
        </ul>
    </div>
</template>
<script>
export default {
    data() {
        return {
            show: !1
        }
    },
    methods: {
        handleFocus() {
            this.show = true
        }
        handleBlur() {
            this.show = false
        }
        handleClick() {
            console.log('click')
        }
    }
}
</script>

解决方式

将隐藏的操作用setTimeout延迟执行,也就是将该操作放入宏任务中,执行完点击事件上的主代码再去执行隐藏的操作

handleBlur() {
    setTimeout(()=>{ this.show = false },0)
}

使用click事件控制下拉框显示隐藏

如果选择器没有输入框,在使用 click 事件控制下拉框的显示隐藏时,需要添加一个方法,点击文档任意地方触发下拉框的隐藏事件

<template>
    <div>
        <button @click="handleClickDiv">111</button>
        <ul v-if="show">
             <li @click.stop="handleClickLi">111</li>
        </ul>
  </div>
</template>
<script>
export default {
    data() {
        return {
            show: !1
        }
    },
    methods: {
        handleClickDiv(){
            this.show = !this.show
        },
        handleClickLi() {
            console.log('handleClickLi')
        }
    }
}
</script>

解决方式

  1. 添加点击文档任意地方触发下拉框的隐藏事件(注意销毁组件时要解绑事件)
created() {
    this.documentClickEvent = ()=> {
        this.show = false
    }
    document.addEventListener('click',this.documentClickEvent)
},
destroyed() {
    document.removeEventListener('click',this.documentClickEvent)
}
  1. 阻止选项的点击事件冒泡(避免两个点击事件冲突)
<template>
    <div>
        <button @click.stop="handleClickDiv">111</button>
        <ul v-if="show">
             <li @click.stop="handleClickLi">111</li>
        </ul>
  </div>
</template>

补充

上述方法,未考虑到多个组件时,绑定在document中的事件的影响,如果引入多次组件,会对组件间隐藏显示造成影响,需对document绑定的方法进行以下修改

this.documentClickEvent = (e) => {
    if (
        !this.$el.contains(e.target) ||
        (!this.show && e.target == this.$refs.button)
      ) {
        this.show = false;
      } else {
        this.show = true;
      }
};
<button @click="handleClickDiv" ref="button">111</button>

解除 button 的冒泡,通过 ref 获取 Dom 对象,在所绑定的 document 点击事件中添加判断,不是当前组件中的 button 就隐藏,或者通过点击按钮隐藏了,就不再打开