集 el-input、el-select 优点于一身:el-autocomplete

884 阅读1分钟

需求产生原因

在日常业务开发当中,经常性地会用到 el-inputel-select 作为 筛选项 组件

二者均有不足之处。前者 无法提供建议,后者 无法模糊搜索

那么,是否有兼顾二者优势的组件?

通过检索 Element-UI 官方文档,竟发现 el-input 使用引导下,隐藏着另一组件 el-autocomplete

el-autocomplete使用.gif

所存在的不足及处理方法

下述处理,均在 继承el-autocomplete组件 基础上实现(继承相关内容可参照 Element组件全局调整

与调整相关源代码:

handleClear() {
  this.activated = false;
  this.$emit('clear');
},
handleKeyEnter(e) {
  if (this.suggestionVisible && this.highlightedIndex >= 0 && this.highlightedIndex < this.suggestions.length) {
    e.preventDefault();
    this.select(this.suggestions[this.highlightedIndex]);
  } else if (this.selectWhenUnmatched) {
    this.$emit('select', {value: this.value});
    this.$nextTick(_ => {
      this.suggestions = [];
      this.highlightedIndex = -1;
    });
  }
},
select(item) {
  this.$emit('input', item[this.valueKey]);
  this.$emit('select', item);
  this.$nextTick(_ => {
    this.suggestions = [];
    this.highlightedIndex = -1;
  });
},
handleChange(value) {
  this.$emit('change', value);
},

handleClear 为Input输入框值清空时的回调函数

handleKeyEnter 为监听Enter按键按下时的回调事件

select 为针对选中项的具体操作内容

未选择建议项,按下Enter键后,未隐藏输入建议框

问题复现

建议框未隐藏.gif

处理代码
handleKeyEnter(e) {
  if (this.suggestionVisible && this.highlightedIndex >= 0 && this.highlightedIndex < this.suggestions.length) {
    xxx
  } else if (this.selectWhenUnmatched) {
    xxx
  } else {
    // 无匹配项 且 回车不触发select事件 情况下
    this.$nextTick(_ => {
      // 延时180ms。避免快速输入、按击Enter键后,意外重现输入建议框
      setTimeout(() => {
        // 增补内容(输入框失焦、输入建议清空)
        this.$refs.input.blur();
        this.suggestions = [];
      }, 180)
    })
  }
}

通过键盘选中时,未触发change事件

处理代码
select(item) {
  xxx
  // 手动触发(源代码中对change事件触发做了进一步封装)
  this.handleChange(item[this.valueKey])
  xxx
},
// 配合select方法中的调整,避免短时间内发起重复请求
handleChange: debounce(16, function (value) {
  this.$emit('change', value)
}),

在输入框聚焦状态下,清空数据后,未失焦

情况复现

清空未自动失焦.gif

处理代码
handleClear() {
  xxx
  // 增补内容(输入框失焦)
  this.$refs.input.blur();
}

完整代码及应用示例

完整内容

import { Autocomplete } from 'element-ui'
import debounce from 'throttle-debounce/debounce'

const AutocompletePatch = {
  extends: Autocomplete,
  methods: {
    handleClear() {
      this.activated = false
      this.$emit('clear')
      // 增补内容(输入框失焦)
      this.$refs.input.blur()
    },
    handleKeyEnter(e) {
      if (
        this.suggestionVisible &&
        this.highlightedIndex >= 0 &&
        this.highlightedIndex < this.suggestions.length
      ) {
        e.preventDefault()
        this.select(this.suggestions[this.highlightedIndex])

        this.$nextTick((_) => {
          // 增补内容(输入框失焦)
          this.$refs.input.blur()
        })
      } else if (this.selectWhenUnmatched) {
        this.$emit('select', { value: this.value })
        this.$nextTick((_) => {
          this.suggestions = []
          this.highlightedIndex = -1
        })
      } else {
        // 无匹配项 且 回车不触发select事件 情况下
        this.$nextTick((_) => {
          setTimeout(() => {
            // 增补内容(输入框失焦、输入建议清空)
            this.$refs.input.blur()
            this.suggestions = []
          }, 180)
        })
      }
    },
    select(item) {
      this.$emit('input', item[this.valueKey])
      this.$emit('select', item)
      // 增补内容(选中时,同时触发change事件)
      this.handleChange(item[this.valueKey])

      this.$nextTick((_) => {
        this.suggestions = []
        this.highlightedIndex = -1
      })
    },
    // 配合select方法中的调整,避免短时间内发起重复请求
    handleChange: debounce(16, function (value) {
      this.$emit('change', value)
    }),
  },
}

export default {
  install(Vue) {
    Vue.component(Autocomplete.name, AutocompletePatch)
  }
}

应用示例

<el-autocomplete
  v-model="**绑定的参数**"
  clearable
  placeholder="请输入"
  :fetch-suggestions="
    (query, cb) => fetchSuggestions(**待建议数据集合**, query, cb)
  "
  @change="**回调函数**"
/>
fetchSuggestions(list, query, cb) {
  const filterValues = query
    ? list.filter((item) => item.includes(query))
    : list
  const results = filterValues.map((value) => {
    return { value }
  })

  cb(results)
}