Skip to content

antd Select下拉框中 dropdownRender插槽不支持 input

参考issue链接: https://github.com/vueComponent/ant-design-vue/issues/7304

组件实现

支持 mouseleave popup 的时候自动关闭下拉框

vue
<template>
    <div style="width: 240px" class="refresh" @mousedown="handleSelectMouseDown">
      <a-select
        ref="selectRef"
        :open="selectOpen"
        default-value="7" style="width: 240px" @change="handleChange"
        :getPopupContainer="triggerNode =>triggerNode.parentNode"
      >
        <a-icon slot="suffixIcon" type="down" @click.stop="selectIconClick" :rotate="selectOpen ? 180 : 0"/>
        <a-select-option v-for="item in daySelectItems" :key="item.value" :value="item.value">{{ item.label }}
        </a-select-option>
        <div slot="dropdownRender" slot-scope="menu">
          <v-nodes :vnodes="menu"/>
          <a-divider style="margin: 4px 0;"/>
          <a-space style="padding: 4px 8px" >
            <a-input placeholder="请输入天数" v-model="days" @click="e=>e.target.focus()"/>
            <a-button type="primary" @click="addItem">添加</a-button>
          </a-space>
        </div>
      </a-select>
    </div>
<template>

<script>
export default {
  components: {
    VNodes: {
      functional: true,
      render: (h, ctx) => ctx.props.vnodes,
    },
  },
  data() {
    return {
      days: '',
      selectOpen: false,
      daySelectItems: [{ value: '7', label: '最近 7 天' },
        { value: '14', label: '最近 14 天' },
        { value: '30', label: '最近 30 天' },
        { value: '90', label: '最近 90 天' },
        { value: '', label: '全部时间' }
      ]
    }
  },
  methods: {
    handleChange(value) {
      this.selectOpen = false
      this.cleanupMouseLeaveListener()
      // TODO 发请求获取数据
    },
    addItem() {
      if (this.days === '') {
        this.$message.error('请输入天数');
        return;
      }
      //正则匹配正整数
      if (!/^[1-9]\d*$/.test(this.days)) {
        this.$message.error('请输入正整数');
        this.days = ''
        return;
      }
      
      // 重复的提示
      if (this.daySelectItems.some(item => item.value == this.days)) {
        this.$message.info('已包含此选项');
        return;
      }

      this.daySelectItems.push({ value: this.days.toString(), label: `最近 ${this.days} 天` });
      this.days = '';
    },
    async handleSelectMouseDown(e) {
      if (e.target.closest('.anticon')) return; // 解决点击图标时,不触发下拉框的展开的问题
      e.preventDefault()
      this.selectOpen = true
      this.mouseLeaveHandler = () => {
        this.selectOpen = false
      }
      this.$nextTick(() => {
        this.$refs.selectRef?.popupRef?.$el.addEventListener('mouseleave', this.mouseLeaveHandler)
      })
    },
    cleanupMouseLeaveListener() {
      if (this.mouseLeaveHandler) {
        this.$refs.selectRef?.popupRef?.$el.removeEventListener('mouseleave',this.mouseLeaveHandler)
        this.mouseLeaveHandler = null
      }
    },
    selectIconClick() {
      this.selectOpen = !this.selectOpen
    }
  },
  beforeDestroy() {
    this.cleanupMouseLeaveListener()
    EventBus.$off('currentRecord')
  },
}
</script>

<style lang="less" scoped>
// 解决弹出框闪烁的问题
/deep/ .ant-dropdown {
  pointer-events: auto!important;//确保了元素可以响应鼠标事件
  opacity: 1!important;//下拉菜单设置为完全不透明,避免透明度变化引起闪烁
}
/deep/ .slide-up-enter, .slide-up-appear {
  animation-duration: 0s;//动画持续时间为0
}
</style>

不支持 mouseleave 自动关闭

vue
<template>
    <div style="width: 240px" class="refresh" @mousedown="handleSelectMouseDown">
      <a-select
        ref="selectRef"
        :open="selectOpen"
        default-value="7" style="width: 240px" @change="handleChange"
        :getPopupContainer="triggerNode =>triggerNode.parentNode"
      >
        <a-icon slot="suffixIcon" type="down" @click.stop="selectIconClick" :rotate="selectOpen ? 180 : 0"/>
        <a-select-option v-for="item in daySelectItems" :key="item.value" :value="item.value">{{ item.label }}
        </a-select-option>
        <div slot="dropdownRender" slot-scope="menu">
          <v-nodes :vnodes="menu"/>
          <a-divider style="margin: 4px 0;"/>
          <a-space style="padding: 4px 8px" >
            <a-input placeholder="请输入天数" v-model="days" @click="e=>e.target.focus()"/>
            <a-button type="primary" @click="addItem">添加</a-button>
          </a-space>
        </div>
      </a-select>
    </div>
<template>

<script>
export default {
  components: {
    VNodes: {
      functional: true,
      render: (h, ctx) => ctx.props.vnodes,
    },
  },
  data() {
    return {
      days: '',
      selectOpen: false,
      daySelectItems: [{ value: '7', label: '最近 7 天' },
        { value: '14', label: '最近 14 天' },
        { value: '30', label: '最近 30 天' },
        { value: '90', label: '最近 90 天' },
        { value: '', label: '全部时间' }
      ]
    }
  },
  methods: {
    handleChange(value) {
      console.log('change', value);
      this.selectOpen = false
      // TODO 发请求获取数据
    },
    addItem() {
      if (this.days === '') {
        this.$message.error('请输入天数');
        return;
      }
      //正则匹配正整数
      if (!/^[1-9]\d*$/.test(this.days)) {
        this.$message.error('请输入正整数');
        this.days = ''
        return;
      }
      // 重复的提示
      if (this.daySelectItems.some(item => item.value == this.days)) {
        this.$message.info('已包含此选项');
        return;
      }
      this.daySelectItems.push({ value: this.days.toString(), label: `最近 ${this.days} 天` });
      this.days = '';
    },
    async handleSelectMouseDown(e) {
      if (e.target.closest('.anticon')) return; // 解决点击图标时,不触发下拉框的展开的问题
      e.preventDefault()
      this.selectOpen = true
    },
    selectIconClick() {
      this.selectOpen = !this.selectOpen
    }
  }
}

<style lang="less" scoped>
// 解决弹出框闪烁的问题
/deep/ .ant-dropdown {
  pointer-events: auto!important;//确保了元素可以响应鼠标事件
  opacity: 1!important;//下拉菜单设置为完全不透明,避免透明度变化引起闪烁
}
/deep/ .slide-up-enter, .slide-up-appear {
  animation-duration: 0s;//动画持续时间为0
}
</style>

问题整理和解决

图标点击展开收缩失效

图标箭头旋转失效

less
&-open {
    .@{select-prefix-cls}-arrow {
      &-icon svg {
        transform: rotate(180deg);
      }
    }
    .@{select-prefix-cls}-selection {
      .active();
    }
  }

解决弹出框闪烁的问题

less
/deep/ .ant-dropdown {
  pointer-events: auto!important;//确保了元素可以响应鼠标事件
  opacity: 1!important;//下拉菜单设置为完全不透明,避免透明度变化引起闪烁
}
/deep/ .slide-up-enter, .slide-up-appear {
  animation-duration: 0s;//动画持续时间为0
}

Released under the ISC License.