前些天实现了一个树结构的下拉组件,可最近又让我反对下拉搜寻性能,查了一圈没有找到适合的,只好明天本人写了一下,对付能用吧,反对搜寻性能了最起码,可有些参数还是要配置的
<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); }
有哪里须要优化的提一下,继续改良哈。