Element自定义下拉框搜索

2020/5/8 Vue

TIPS

问题背景

Element-UI的下拉框只能搜索绑定的 label 字段,需要搜索该条数据的其他字段,比如名称、拼音等

# FilterSelect组件

<template>
  <el-select
    :value="currentValue"
    filterable
    :clearable="clearable"
    :disabled="disabled"
    :placeholder="placeholder"
    :filter-method="filterMethod"
    default-first-option
    @change="$emit('change', $event)"
    @foucs="selectFocus"
  >
    <el-option
      v-for="item in filterOptions"
      :key="item[optionConfig.value]"
      :label="item[optionConfig.label]"
      :value="item[optionConfig.value]"
    />
  </el-select>
</template>

<script>
export default {
  name: "FilterSelect",
  model: {
    prop: "currentValue",
    event: "change"
  },
  props: {
    // 父级的v-model的value
    currentValue: [String, Number, Boolean, Array], // eslint-disable-line

    clearable: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    placeholder: {
      type: String,
      default: "请选择"
    },
    // 原始的options数据
    options: {
      type: Array,
      default: () => []
    },
    // 支持搜索的属性名称
    filterAttrs: {
      type: Array,
      default: () => []
    },
    // options绑定的属性名
    optionConfig: {
      type: Object,
      default: () => {
        return { label: "label", value: "value" }
      }
    },
  },
  data() {
    return {
      filterOptions: this.options // 过滤后的options值
    }
  },
  methods: {
    toUpperCase(data) {
      return String(data).toUpperCase()
    },
    filterMethod(key) {
      const newKey = this.toUpperCase(key)
      this.filterOptions = this.options.filter(el => {
        let flag = false
        this.filterAttrs.forEach(attr => {
          if (this.toUpperCase(el[attr]).indexOf(newKey) > -1) {
            flag = true
          }
        })
        return flag
      })
    },
    // focus时重置搜索数据
    selectFocus() {
      this.filterOptions = this.options
    }
  }
}
</script>

<style lang="scss" scoped>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

# 使用

<template>
  <div>
    <filter-select
      v-model="value"
      placeholder="请输入搜索条件"
      clearable
      :options="options"
      :filter-attrs="[ 'name', 'py' ]"
      :option-config="{ label: 'name', value: 'code'}"
      @change="selectChange"
    />
  </div>
</template>

<script>
import FilterSelect from "./FilterSelect"

export default {
  name: "index",
  components: {
    FilterSelect
  },
  data() {
    return {
      value: '',
      options: [
        { name: '橘子', code: '001', py: 'JZ' },
        { name: '苹果', code: '002', py: 'PG' },
        { name: '香蕉', code: '003', py: 'XJ' },
      ]
    };
  },
  methods: {
    selectChange(val) {
      console.log(val)
    }
  }
};
</script>

<style lang="scss" scoped>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 一个更优雅的写法

TIPS

  • $attrs 会继承除了 props 接收的其他全部属性,class style 除外
  • $listeners 父级全部监听事件,.native修饰器的除外
  • inheritAttrs: false 默认情况下父作用域的不被作为props特性绑定的属性,将会作为普通的 HTML 属性,应用在根元素。设置interitAttrs 为 false,之后,不会应用到跟元素上
<template>
  <el-select
    filterable
    :clearable="clearable"
    :disabled="disabled"
    :placeholder="placeholder"
    :filter-method="filterMethod"
    default-first-option
    v-bind="$attrs"
    @focus="selectFocus"
    v-on="$listeners"
  >
    <el-option
      v-for="item in filterOptions"
      :key="item[optionConfig.value]"
      :label="item[optionConfig.label]"
      :value="item[optionConfig.value]"
    />
  </el-select>
</template>

<script>
export default {
  name: "FilterSelect",
  inheritAttrs: false,
  props: {
    clearable: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    placeholder: {
      type: String,
      default: "请选择"
    },
    // 原始的options数据
    options: {
      type: Array,
      default: () => []
    },
    // 支持搜索的属性名称
    filterAttrs: {
      type: Array,
      default: () => []
    },
    // options绑定的属性名
    optionConfig: {
      type: Object,
      default: () => {
        return { label: "label", value: "value" }
      }
    },
  },
  data() {
    return {
      filterOptions: this.options // 过滤后的options值
    }
  },
  methods: {
    toUpperCase(data) {
      return String(data).toUpperCase()
    },
    filterMethod(key) {
      const newKey = this.toUpperCase(key)
      this.filterOptions = this.options.filter(el => {
        let flag = false
        this.filterAttrs.forEach(attr => {
          if (this.toUpperCase(el[attr]).indexOf(newKey) > -1) {
            flag = true
          }
        })
        return flag
      })
    },
    // focus时重置搜索数据
    selectFocus() {
      this.filterOptions = this.options
    }
  }
}
</script>

<style lang="scss" scoped>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
最近更新: 2023年03月21日 14:47:21