前些天实现了一个树结构的下拉组件,可最近又让我支持下拉搜索功能,查了一圈没有找到合适的,只好今天自己写了一下,凑合能用吧,支持搜索功能了最起码,可有些参数还是要配置的
```
v-model:visible="popVisible" placement="bottom" :width="popoverWidth" trigger="click" > v-model="filterText" v-bind="$attrs" :placeholder="placeholder" @blur="handleBlur" @focus="handleFocus" @input="handleFilter" > ref="tree" class="filter-tree" :data="options" :props="defaultProps" default-expand-all :filter-node-method="filterNode" @node-click="handleNodeClick" />
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();
function handleFilter(val){
tree.value.filter(val);
}
onMounted(() => {
filterText.value = findLabel(props.options, props.modelValue);
});
return {
tree,
handleFilter,
placeholder,
defaultProps,
filterText,
popVisible,
preText,
handleNodeClick,
handleBlur,
handleFocus,
filterNode,
handleIcon,
};
},
});
.suffix {
cursor: pointer;
display: flex;
width: 100%;
height: 100%;
align-items: center;
}
```
使用起来比之前那一篇麻烦了一丢丢,相对还是好用的
且看,
```
style="width: 226px" :popoverWidth="200" v-model="selectData" :options="options" @selected="handleSelect" >
```
在父组件里我们组要把对应要修改的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);
}
```
有哪里需要优化的提一下,持续改进哈。