特性:
1、支持本地保存选中过的记录
2、支持动态接口获取匹配下拉框内容
3、可以指定对应的显示label和字段组件key
4、自动生成速记符字段(包含声母和全拼两种类型),增强搜索匹配效率
sgAutocomplete源码
<template> <!-- 基于elementUIel-autocomplete组件开发的自动补全下拉框组件 --> <el-autocomplete :class="$options.name" style="width: 100%" ref="autocomplete" :popper-class="'sgAutocomplete-el-autocomplete'" v-model="inputSearchValue" :placeholder="placeholder || `输入关键词…`" :value-key="valueKey || `label`" :fetch-suggestions="fetchSuggestions" :hide-loading="false" @focus="$refs.autocomplete.$el.querySelector('input').select()" @select="selectSuggestionsItem" @clear="focusAutocomplete" :debounce="0" clearable > <template slot-scope="{ item }"> <div> <i v-if="item.isHistory" class="history-icon el-icon-time" /> <span class="label">{{ item[labelKey || `label`] }}</span> </div> </template> <!-- 搜索按钮1 --> <i class="el-icon-search el-input__icon" slot="suffix" v-if="showSearchButton == 1" /> <!-- 删除历史记录按钮 --> <i :title="clearHistoryTitle || `删除历史记录`" class="el-icon-delete el-input__icon clearHistory" slot="suffix" v-if="showHistoryBtn" @click="clearHistory" /> <!-- 搜索按钮2 --> <el-button slot="append" icon="el-icon-search" @click="focusAutocomplete" v-if="showSearchButton == 2" ></el-button> </el-autocomplete> </template> <script> import pinyin from "@/js/pinyin"; export default { name: "sgAutocomplete", components: {}, data() { return { inputSearchValue: null, historyListLocalStorageName: null, //保存到本地记录的localStorage Key searchItems: [], showHistoryBtn: false, }; }, props: [ "data", //可选项数组(必选参数) "value", "valueKey", //获取值 "labelKey", //显示值 "placeholder", "clearHistoryTitle", //删除历史记录按钮提示 "filterKeys", //匹配搜索的字段(数组)不传此参数默认就用labelKey "showHistory", //显示历史选择记录 "showSearchButton", //显示搜索按钮(样式:1 是在输入框里面的icon,2 是在输入框后面的按钮) "autofocus", ], watch: { data: { handler(newValue, oldValue) { if (newValue && Object.keys(newValue).length) { this.searchItems = JSON.parse(JSON.stringify(newValue)); this.searchItems.forEach((v) => { v.SJF = pinyin.getCamelChars(v[this.labelKey || "label"]); //速记符(声母) v.SJF_full = pinyin.getFullChars(v[this.labelKey || "label"]); //速记符(全拼) }); } }, deep: true, //深度监听 immediate: true, //立即执行 }, value: { handler(newValue, oldValue) { this.inputSearchValue = newValue; }, deep: true, //深度监听 immediate: true, //立即执行 }, inputSearchValue: { handler(newValue, oldValue) { this.$emit(`input`, newValue); }, deep: true, //深度监听 immediate: true, //立即执行 }, showHistory: { handler(newValue, oldValue) { this.historyListLocalStorageName = newValue; }, deep: true, //深度监听 immediate: true, //立即执行 }, }, mounted() { (this.autofocus === "" || this.autofocus) && this.focusAutocomplete(); //默认聚焦 }, methods: { focusAutocomplete(d) { this.$nextTick(() => { this.$refs.autocomplete.focus(); this.$refs.autocomplete.activated = true; //这句话是重点 }); }, // 搜索下拉框 fetchSuggestions(queryString, callback) { if (queryString) { queryString = queryString.toString().trim(); let r = this.searchItems.filter((v, i, ar) => { let filterKeys = this.filterKeys || [this.labelKey]; filterKeys.push("SJF", "SJF_full"); //自动匹配声母、全屏组合 return filterKeys.some((filterKey) => v[filterKey].toLocaleLowerCase().includes(queryString.toLocaleLowerCase()) ); }); this.showHistoryBtn = false; callback(r); } else { let historys = this.getHistorys(); historys.forEach((v) => (v.isHistory = true)); //标识是历史记录 this.showHistoryBtn = historys.length > 0; callback(historys); } }, selectSuggestionsItem(d) { let historys = this.getHistorys(); if (historys.length) { let k = this.valueKey || this.labelKey || "label"; let has = historys.some((v) => v[k] == d[k]); has || historys.unshift(d); localStorage[this.historyListLocalStorageName] = JSON.stringify(historys); } else { localStorage[this.historyListLocalStorageName] = JSON.stringify([d]); } this.$emit(`change`, d); }, getHistorys() { let historys = localStorage[this.historyListLocalStorageName]; return JSON.parse(historys || "[]"); }, clearHistory(d) { delete localStorage[this.historyListLocalStorageName]; this.showHistoryBtn = false; this.focusAutocomplete(); }, }, }; </script> <style lang="scss" scoped> .sgAutocomplete { .clearHistory { cursor: pointer; &:hover { color: #409eff; } } } </style>
里面用到的pinyin.js在这篇文章里面
用例
<template> <div> <sgAutocomplete autofocus v-model="sgAutocompleteValue" :data="data" :placeholder="`输入搜索关键词...`" :valueKey="`value`" :labelKey="`label`" showHistory="localStorageHistoryName" showSearchButton="2" @change="changeSgAutocomplete" /> <p style="margin-top: 20px">选择的数据:{{ sgAutocompleteValue }}</p> <p style=" margin-top: 20px; word-wrap: break-word; word-break: break-all; white-space: break-spaces; " > <span>选择的对象:</span> {{ sgAutocompleteObject ? JSON.stringify(sgAutocompleteObject, null, 2) : "" }} </p> </div> </template> <script> import sgAutocomplete from "@/vue/components/admin/sgAutocomplete"; export default { components: { sgAutocomplete }, data() { return { sgAutocompleteValue: null, sgAutocompleteObject: null, data: [], //模拟数据1 dataA: [ { value: "1", label: "A显示文本1" }, { value: "2", label: "A显示文本2" }, { value: "3", label: "A显示文本3" }, { value: "4", label: "A显示文本4" }, { value: "5", label: "A显示文本5" }, ], //模拟数据2 dataB: [ { value: "1", label: "B显示文本1" }, { value: "2", label: "B显示文本2" }, { value: "3", label: "B显示文本3" }, { value: "4", label: "B显示文本4" }, { value: "5", label: "B显示文本5" }, ], }; }, watch: { // 模拟动态更新筛选项 sgAutocompleteValue: { handler(newValue, oldValue) { if (newValue && Object.keys(newValue).length) { switch (newValue.toLocaleLowerCase()) { case "a": this.data = this.dataA; break; case "b": this.data = this.dataB; break; } } }, }, }, methods: { changeSgAutocomplete(d) { this.sgAutocompleteObject = d; }, }, }; </script>