对 Element UI 中option组件的扩展,以至于能支持更多字段的搜索

181 阅读4分钟

业务描述

element UI el-select 组件可谓是非常方便,支持了对数据Item的检索label,但是因业务需要,需要针对数据Item 的其他字段进行检索,比如 item 的数据格式是这样的: {value,label,pinyin,...} 现在需要对 value, pinyin,... 等字段进行检索, 我们应该怎么去支持它呢?

解决思路

我们先查看文档 了解el-select 组件的搜索描述

el-select添加filterable属性即可启用搜索功能。默认情况下,Select 会找出所有label属性包含输入值的选项。如果希望使用其他的搜索逻辑,可以通过传入一个filter-method来实现。filter-method为一个Function,它会在输入值发生变化时调用,参数为当前输入值。

从文档得知,为el-select 组件添加filterable 属性,就可以支持label 的搜索

要想实现我们上面的需求我们暂时可以想到有以下几种方式:

  • 既然他支持label 的检索,那我们把需要检索的字段拼接进label,就自然而然的支持了。但是这样就存在另外一个问题,选项的lable 出现了不该出现的数据显示,故此法应该行不通,暂不考虑。

  • 检索条件传给后端开发,让后端去模糊匹配检索条件,返回结果集,成功将锅甩给后端开发,非常的 nice . 夸夸我这聪明的小脑瓜。

  • 前端自己过滤option列表,找出结果集;这方式实现起来没什么难度。 使用 filter-method 方法,filter-method为一个Function,它会在输入值发生变化时调用,参数为当前输入值;也能成功解决这个问题;但是在所有系统或组件中都能使用就不得重复写filter-method, 哪位了不重复写或者统一维护这个 filter-method, 我们又可以将 filter-method 以 mixins 的方式抽出,采用局部按需混入,或全局混入。到这 里,我们也能成功的将问题完美解决。那么有没有一种一劳永逸或者更优的解决方案呢,让们不写filter-method 不混入呢?

  • 思考片刻 他既然默认能对 label 进行过滤检索,那肯定就能扩展别的字段进行检测,让我们翻一番他是怎么实现的,我们针对他的源码进行改造,让他能够自己适配其他字段的检索;这个主意甚好,让组件使用者无感知,不用维护太多的代码,甚至多业务系统可以做到统一,不由感叹 甚好 甚好 .....

那我们就来简单分析分析 el-option 组件他是怎么做的label 的过滤检索的

点击查看 option.vue 源码

经过我们的分析就是下面这个方法 (Line:137):

queryChange(query) {
        this.visible = new RegExp(escapeRegexpString(query), 'i').test(this.currentLabel) || this.created;
        if (!this.visible) {
          this.select.filteredOptionsCount--;
        }
      }
<template>
  <li
    @mouseenter="hoverItem"
    @click.stop="selectOptionClick"
    class="el-select-dropdown__item"
    v-show="visible"
    :class="{
      'selected': itemSelected,
      'is-disabled': disabled || groupDisabled || limitReached,
      'hover': hover
    }">

    <slot>
      <span>{{ currentLabel }}</span>
    </slot>
  </li>
</template>

通过简单的分析: 我们发现 它是通过 v-show="visible" 来控制可选项的显示/隐藏的;就是说我们控制 visible 变量的值就可以了。那事情到这就变得简单了。

至此 我们只要重写 queryChange(query) 的实现就能够愉快的实现需求了。

参考代码

我们以 pinyin 字段为例进行简单的重写


  import { Option } from 'element-ui';
  import { escapeRegexpString } from 'element-ui/src/utils/util';

  export default {
    name: 'ElOption2',
    inject: ['select'],
    props: {
      pinyin: {
        type: String,
        default: ''
      }
    },
    computed: {
      currentPinyin() {
        return this.pinyin || (this.isObject ? '' : this.label)
      }
    },
    methods: {
      queryChange(query) {

       const hasLabel = new RegExp(escapeRegexpString(query), 'i').test(this.currentLabel) || this.created;
    
        // 新增代码...
        let hasPinyin = true
        if (this.currentPinyin){
            hasPinyin = new RegExp(escapeRegexpString(query.toUpperCase()), 'i').test(this.currentPinyin) || this.created;
        }
        this.visible = hasLable || hasPinyin
        if (!this.visible) {
          this.select.filteredOptionsCount--
        }
      }

    }
  }

当然我们甚至还可以 设计 props 接受 整个Item 数据, 吧 Item 数据的所有属性值转换成一个 字符串,进行检索匹配;

那么我们在使用的时候,全局注册 el-option2 组件,或者覆盖 el-option

接着在项目中 使用的时候 传入 pinyin 属性 应有或者期望检索的字符串,即可完成对选项的检索;

甚至 如果系统中的业务比较统一, 我们甚至可以直接内置,不提供props 传参。

so . 到此就结束了....

下面请上我们今天的主角:有请小趴菜

小趴菜.jpeg