characteristic:
1. Support local saving of selected records
2. Support dynamic interface to obtain matching drop-down box content
3. You can specify the corresponding display label and field component key
4. Automatically generate shorthand fields (including initial consonants and full spelling types) to enhance search and matching efficiency
sgAutocomplete source code
<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>
Example
<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>