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

2023-12-14 14:33:55

d4f50ad8f5e54f549e447d0a0a6c694f.gif

特性:

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>

?

?

文章来源:https://blog.csdn.net/qq_37860634/article/details/134851806
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。