起因
如何实现支持搜索、选择节点的弹出框树,选择器只能选择列表形式的数据,不能选择树形结构的数据
传统select选择器只能实现下拉框选择列表数据
无法实现选择树形结构的数据
思路:
- 自定义输入框+Popover弹出框,popover组件的内容为Tree树控件
- 使用v-popover将输入框关联到Popover弹出框,这样点击输入框就会弹出popover组件的内容
- 自定义输入框设置contenteditable属性和input事件,使其可编辑,用于搜索弹出框的树节点
- 输入框需要展示选中节点的值,这时就需要css样式设置选中值区域和编辑区区域
整体布局
<div v-clickoutside="clickAll">
<el-popover ref="treePopover">
<el-tree :filter-node-method="filterNodeMethod"></el-tree>
</el-popover>
<div
ref="input"
v-popover:treePopover
tabindex="0"
style="display: flex"
>
<!--选中值区-->
<template></template>
<!--编辑区-->
<div
style="flex: 1; min-width: 32px"
contenteditable
@input="changeContent"
/>
</div>
</div>
v-popover是Popover弹出框与其他组件建立联系的,这里treePopover指向Popover的索引ref,使其建立联系,所以在这个输入框点击就会弹出popover组件的内容。
注意设置自定义输入框样式,以及输入框编辑区和选中值区域样式,通过display布局将编辑区和选中值区域都放置于输入框内,编辑区宽度自适应并且设置最小宽度,保障在有选中值时也能输入内容。
编辑区支持可编辑需要用到contenteditable属性,并且调用input输入事件拿到输入的值,用于筛选树节点。
v-clickoutside,用于触发鼠标失焦后,关闭弹出框
关闭弹出框
clickAll() {
if (this.$refs.treePopover.showPopper) {
this.$refs.treePopover.doClose()
}
}
搜索树节点
// 方法
filterNodeMethod(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
changeContent(e) {
this.query = e.target.innerText
}
// 监听
watch: {
query(v) {
this.$refs.tree.filter(v)
}
}
选择树,支持单选或多选
<el-tree @check="nodeCheck" @Current-change="currentChange"></el-tree>
// 方法
nodeCheck(data) {
this.checkedNodes = this.$refs.tree.getCheckedNodes()
},
currentChange(data, node) {
this.checkedNodes = [this.$refs.tree.getCurrentNode()]
},
展示选中值
<template v-if="checkedNodes.length">
<span class="checked first">
{{ checkedNodes[0].label }}
</span>
<span
v-if="checkedNodes.length > 1"
class="checked"
style="margin-left: 8px"
>
+{{ checkedNodes.length - 1 }}
</span>
</template>
checkedNodes就是选中值,可以自定义展示形式到选中值区域
总结
通过Popover弹出框树和自定义输入框实现了输入内容进行筛选树节点、选中树节点,并将选中值展示到输入框里面。