特性:
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在这篇文章里面JS自动生成速记符、拼音简写/拼音的声母(例如:“你挚爱的强哥”转换为“NZADQG”)。提取首字母,返回大写形式;提取拼音, 返回首字母大写形式(全拼)。_你挚爱的强哥的博客-CSDN博客文章浏览阅读2.7k次。需要引用以下pinyin.js文件。https://blog.csdn.net/qq_37860634/article/details/130765296
用例
<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>