【sgAutocomplete】自定义组件:基于elementUI的el-autocomplete组件开发的自动补全下拉框组件(带输入建议的自动补全输入框)

特性:

1、支持本地保存选中过的记录

2、支持动态接口获取匹配下拉框内容

3、可以指定对应的显示label和字段组件key

4、自动生成速记符字段(包含声母和全拼两种类型),增强搜索匹配效率

sgAutocomplete源码

html 复制代码
<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

用例

html 复制代码
<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>
相关推荐
一 乐1 分钟前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
科技D人生11 分钟前
Vue.js 学习总结(20)—— Vue-Office 实战:word、pdf、excel、ppt 多种文档的在线预览
vue.js·word·vue-pdf·stylesheet·docx-preview·vue-office
vx1_Biye_Design13 分钟前
基于Spring Boot+Vue的学生管理系统设计与实现-计算机毕业设计源码46223
java·vue.js·spring boot·spring·eclipse·tomcat·maven
vx_Biye_Design14 分钟前
基于Spring Boot+vue的湖北旅游景点门票预约平台的设计--毕设附源码29593
java·vue.js·spring boot·spring cloud·servlet·eclipse·课程设计
hedley(●'◡'●)14 分钟前
基于cesium和vue的大疆司空模仿程序
前端·javascript·vue.js·python·typescript·无人机
qq5_81151751516 分钟前
web城乡居民基本医疗信息管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
百思可瑞教育16 分钟前
构建自己的Vue UI组件库:从设计到发布
前端·javascript·vue.js·ui·百思可瑞教育·北京百思教育
百锦再16 分钟前
Vue高阶知识:利用 defineModel 特性开发搜索组件组合
前端·vue.js·学习·flutter·typescript·前端框架
hdsoft_huge19 分钟前
1panel面板中部署SpringBoot和Vue前后端分离系统 【图文教程】
vue.js·spring boot·后端
CappuccinoRose42 分钟前
JavaScript 学习文档(二)
前端·javascript·学习·数据类型·运算符·箭头函数·变量声明