【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>
相关推荐
前端之虎陈随易2 小时前
2年没用Nodejs了,Bun很香
linux·前端·javascript·vue.js·typescript
好运的阿财3 小时前
OpenClaw工具拆解之host_workspace_write+host_workspace_edit
前端·javascript·人工智能·机器学习·ai编程·openclaw·openclaw工具
XiYang-DING3 小时前
JavaScript
开发语言·javascript·ecmascript
空中海4 小时前
02 React Native状态、导航、数据流与设备能力
javascript·react native·react.js
空中海5 小时前
02 状态、Hooks、副作用与数据流
开发语言·javascript·ecmascript
abcnull5 小时前
传统的JavaWeb项目Demo快速学习!
java·servlet·elementui·vue·javaweb
空中海5 小时前
04 React Native工程化、质量、发布与生态选型
javascript·react native·react.js
杨超凡6 小时前
豆包收费了?我特么自己用“意念”搓了一个!
javascript
threelab7 小时前
Three.js 咖啡杯烟雾效果 | 三维可视化 / AI 提示词
开发语言·javascript·人工智能