前些天实现了一个树结构的下拉组件,可最近又让我反对下拉搜寻性能,查了一圈没有找到适合的,只好明天本人写了一下,对付能用吧,反对搜寻性能了最起码,可有些参数还是要配置的

<template>  <div>    <el-popover      v-model:visible="popVisible"      placement="bottom"      :width="popoverWidth"      trigger="click"    >      <template #reference>        <el-input          v-model="filterText"          v-bind="$attrs"          :placeholder="placeholder"          @blur="handleBlur"          @focus="handleFocus"        >          <template #suffix>            <div class="suffix" @click="handleIcon">              <i :class="`el-icon-arrow-${popVisible ? 'up' : 'down'}`" />            </div>          </template>        </el-input>      </template>      <el-tree        ref="tree"        class="filter-tree"        :data="options"        :props="defaultProps"        default-expand-all        :filter-node-method="filterNode"        @node-click="handleNodeClick"      />    </el-popover>  </div></template><script>import { defineComponent, watch, onMounted, ref, computed } from "vue";export default defineComponent({  props: {    popoverWidth: {      type: Number,      default: 400,    },    modelValue: {      type: String,      default: "",    },    options: {      type: Array,      default: () => [],    },  },  emits: ["update:modelValue", "selected"],  setup(props, context) {    const defaultProps = ref({      children: "children",      label: "label",    });    const popVisible = ref(false);    function handleIcon() {      popVisible.value = !popVisible.value;    }    const preText = ref("");    const placeholder = computed(() =>      preText.value ? preText.value : "select"    );    function filterNode(value, data) {      if (!value) return true;      return data.label.indexOf(value) !== -1;    }    function findLabel(arr, target) {      let res = target;      function find(arr) {        for (let i = 0; i < arr.length; i += 1) {          if (arr[i].value === target) {            res = arr[i].label;            return;          }          if (arr[i].children && arr[i].children.length) {            find(arr[i].children, target);          }        }      }      find(arr);      return res;    }    const filterText = ref("");    function handleNodeClick(node) {      popVisible.value = false;      filterText.value = node.label;      preText.value = node.label;      context.emit("selected", node);      context.emit("update:modelValue", node.value);    }    function handleBlur() {      setTimeout(() => {        filterText.value = preText.value;      }, 100);    }    function handleFocus() {      preText.value = filterText.value;      filterText.value = "";    }    watch(      () => props.modelValue,      () => {        filterText.value = findLabel(props.options, props.modelValue);      }    );    const tree = ref();    watch(      () => filterText.value,      (val) => {        tree.value.filter(val);      }    );    onMounted(() => {      filterText.value = findLabel(props.options, props.modelValue);    });    return {      tree,      placeholder,      defaultProps,      filterText,      popVisible,      preText,      handleNodeClick,      handleBlur,      handleFocus,      filterNode,      handleIcon,    };  },});</script><style scoped>.suffix {  cursor: pointer;  display: flex;  width: 100%;  height: 100%;  align-items: center;}</style>

应用起来比之前那一篇麻烦了一丢丢,绝对还是好用的
且看,

<treeSelect      style="width: 226px"      :popoverWidth="200"      v-model="selectData"      :options="options"      @selected="handleSelect"    ></treeSelect>   

在父组件里咱们组要把对应要批改的value传进去,options对应树结构的array模样,不过肯定要有value的,或者读者能够本人再略微改改,emit进去的参数。
对于el-popover的宽度和高度都没有做设置,不适宜过多的数据,需要的话就本人加个div限度一下,或者须要的人多的话,我再把它优化下。。

const selectData = ref("");    const options = ref([      {        label: "选项1",        value: "1",        children: [{ label: "选项1-1", value: "1-1" }],      },      { label: "选项2", value: "2" },    ]);    function handleSelect(node) {      console.log(node);    }

有哪里须要优化的提一下,继续改良哈。