背景
antdv select 官方使用dropdownRender对下拉菜单进行自由扩展,
为了解决点击 dropdownRender 里的内容浮层关闭的问题,官方建议添加preventDefault,但是这样扩展内容里的输入框无法聚焦
一开始采取的方案是手动给自定义的输入框focus事件,但是基于页面只会有一个focus的原则,会因此触发select的输入框blur,反而导致下拉菜单收起,最后还是采取手动控制select的open属性来解决了问题
解决思路
- 在select上添加一个透明的div作为select替身,只用来控制open,这样不用调用select组件的blur和focus,避免和原组件的处理有冲突
- 选中选项(单选时)或者点击select控件外的地方操控open = false (dropdownRender处阻止冒泡stopPropagation,这样便于监听除下拉选项的全局事件)
实现效果
具体代码如下
selectInput.vue
<template>
<div class="select-wrapper">
<a-select default-value="lucy"
style="width: 300px"
dropdownClassName="dropdown-class-name"
placeholder="请选择"
:open="open"
@select="selectOption"
:class="{'ant-select-open': open}"
option-label-prop="label"
:filter-option="filterOption"
show-search
>
<div slot="dropdownRender" slot-scope="menu" @click="(e) => {e.stopPropagation()}">
<v-nodes :vnodes="menu" />
<a-divider style="margin: 4px 0" />
<div style="padding: 4px 8px; cursor: pointer">
<a-input class="input-txt" v-model="value" placeholder="请输入" allowClear @pressEnter="addItem" />
</div>
</div>
<a-select-option v-for="item in items" :key="item" :value="item" :label="item">
{{ item }}
</a-select-option>
</a-select>
<!--原来的,因为有遮罩的div导致不能使用自带的搜索和删除
<div class="select_overlap" @mousedown="openSelect"></div>-->
<!--最新方案,展开后隐藏遮罩即可使用组件本身的功能-->
<div v-show="!open" class="select_overlap" @mouseup="openSelect"></div>
</div>
</template>
<script>
export default {
components: {
VNodes: {
functional: true,
render: (h, ctx) => ctx.props.vnodes
}
},
data: () => ({ items: ['jack', 'lucy'], value: '', open: false, clickHandle: null }),
methods: {
addItem() {
this.items.push(this.value)
},
openSelect() {
this.open = !this.open
},
selectOption() {
// 单选时设置
this.open = false
},
filterOption(input, option) {
return option.componentOptions.propsData.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
},
},
mounted() {
this.clickHandle = (e) => {
if (e.target && 'className' in e.target && this.open) {
const className = e.target.className;
if (className.indexOf('select_overlap') === -1) {
this.open = false
}
} else {
this.open = false
}
}
document.body.addEventListener('click', this.clickHandle)
},
beforeDestroy() {
if (this.clickHandle) {
document.body.removeEventListener('click', this.clickHandle)
this.clickHandle = null
}
}
}
</script>
selectInput.less
.select-wrapper {
position: relative;
.select_overlap {
cursor: pointer;
height: 32px;
width: 300px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
}
}