filterable=true的el-select组件下拉框在滚动时出现错位的bug修复

454 阅读1分钟

bug出现场景-:

场景描述:在发生滚动时下拉框滚动出弹窗

原因分析: 没有做监听事件来控制下拉框的显示隐藏

image.png bug出现场景二:

场景描述:在增加滚动事件监听、已解决场景-bug的基础上。切换浏览器标签页、或者切换应用后又重新回到当前页面。此时下拉框再次错位出现

原因分析:切换窗口,浏览器会主动聚焦上次聚焦的input框

解决方案

思路:

1、针对场景一可增加滚动事件监听

2、针对场景二:动态设置el-select的filterable值。阅读el-select源码可以知道,浏览器主动聚焦时,调用了handleFoucs事件,当filterable为true时,会设visible为true(下拉框的v-show的值)。可通过调整filterable的状态来达到更新visible的值。el-select关键源码展示

 handleFocus(event) {
    if (!this.softFocus) {
      if (this.automaticDropdown || this.filterable) {
        if (this.filterable && !this.visible) {
          this.menuVisibleOnFocus = true;
        }
        this.visible = true;
      }
      this.$emit('focus', event);
    } else {
      this.softFocus = false;
    }
  },

bug修复代码展示:

/**
 *  自定义鼠标up、down事件
 *  因为在el-select 的自定义指令中v-clickoutside的实现就是,在点击其他区域,触发handleClose,下拉框收起
 *  这里自定义事件,为了主动触发事件。调用handleClose
 */
const MousedownEvent = new Event('mousedown', { bubbles: true })
const MouseupEvent = new Event('mouseup', { bubbles: true })
const autoClickOutside = () => {
  document.dispatchEvent(MousedownEvent)
  document.dispatchEvent(MouseupEvent)
}
/**
 * 节流
 * @param {} fn
 * @returns
 */
function throttle(fn) {
  let locked = false
  return function(...args) {
    locked = true
    window.requestAnimationFrame(_ => {
      fn.apply(this, args)
      locked = false
    })
  }
}

export default {
  data() {
    return {
      // 由于浏览器会在切换页面返回到当前页时input框会自动聚焦、当filterable=true时导致下拉框自动显示出来,出现UI错位bug,所以动态设置filterable
      ifFilterAble: true
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.throttleScroll = throttle(this.handleScroll, 20)
      window.addEventListener('scroll', this.throttleScroll, true)
    })
  },
  destroyed() {
    window.removeEventListener('scroll', this.throttleScroll)
  },
  methods: {
    handleScroll(e) {
      const classList = e.target.classList
      const scrollLeft = e.target.scrollLeft
      if (classList.contains('el-select-dropdown__item') || e.target.parentNode.classList.contains('el-select-dropdown__item')) {
        return
      }
      if (scrollLeft > 5) {
        this.ifFilterAble = false
        autoClickOutside()
      } else {
        this.ifFilterAble = true
      }
    }
  }
}

vue组件代码展示

<template>
  <el-select :filterable="ifFilterAble">
    <el-option v-for="(item) in sparts" :key="item.code" :label="item.code" :value="item.code"></el-option>
  </el-select>
</template>
<script>
import clickOutsides from '@/mixins/clickOutsides'
export default {
  mixins: [clickOutsides],
</script>