vue2+element 结合element的效果
效果图
treeSelect.vue
components-treeSelect.vue
PS 如果输入框部分 点击不生效使用@mousedown.native替代@click
<template>
<div class="tree-select" @click.stop>
<!-- 输入框部分 -->
<el-input
v-model="selectedLabel"
:placeholder="placeholder"
@click="toggleTree"
>
</el-input>
<!-- 树形下拉区域 -->
<div v-show="showTree" class="tree-container">
<el-tree
ref="tree"
:data="options"
show-checkbox
:props="defaultProps"
@node-click="handleNodeClick"
node-key="id"
:check-strictly="true"
@check="handleCheckChange"
></el-tree>
</div>
</div>
</template>
<script>
export default {
props: {
value: [String, Number, Array], // 选中的值(单选)
options: { type: Array, default: () => [] }, // 树形数据
placeholder: { type: String, default: '请选择' },
defaultProps: {
type: Object,
default: () => ({ })
}
},
data() {
return {
showTree: false,
selectedLabel: ''
};
},
watch: {
value(newVal) {
// 根据 value 回显 label
this.updateLabel(newVal);
}
},
mounted() {
// 监听点击其他空白区域事件
document.addEventListener('click', this.handleOutsideClick);
},
beforeDestroy() {
// 移除点击其他空白区域事件监听
document.removeEventListener('click', this.handleOutsideClick);
},
methods: {
toggleTree() {
this.showTree = !this.showTree;
},
handleNodeClick(node) {
// 手动勾选当前节点
this.$nextTick(() => {
this.$refs.tree.setChecked(node, true, false);
this.handleSingleSelect(node);
});
},
handleCheckChange(data, checked) {
if (checked) {
// 清空所有选中状态
this.$refs.tree.setCheckedKeys([]);
// 设置当前节点为选中状态
this.$refs.tree.setChecked(data.id, true);
this.handleSingleSelect(data);
} else {
// 取消当前节点的选中状态
this.$refs.tree.setChecked(data.id, false);
this.selectedLabel = '';
this.$emit('input', null);
}
},
handleSingleSelect(node) {
// 取消所有其他节点的勾选状态
const allNodes = this.$refs.tree.getCheckedNodes(false, true);
allNodes.forEach(n => {
if (n.id!== node.id) {
this.$refs.tree.setChecked(n, false, false);
}
});
this.$emit('input', node.id);
this.selectedLabel = node[this.defaultProps.label];
},
updateLabel(value) {
if (!value) return;
const findNode = (nodes) => {
for (const node of nodes) {
if (node.id === value) {
return node;
}
if (node.childs) {
const found = findNode(node.childs);
if (found) {
return found;
}
}
}
return null;
};
const node = findNode(this.options);
if (node) {
this.selectedLabel = node[this.defaultProps.label];
}
},
handleOutsideClick() {
// 点击其他空白区域隐藏树形菜单
this.showTree = false;
}
}
};
</script>
<style>
.tree-select {
position: relative;
}
.tree-container {
position: absolute;
width: 100%;
border: 1px solid #e4e7ed;
z-index: 999;
background: white;
}
.el-icon-arrow-down.is-reverse {
transform: rotate(180deg);
}
</style>
使用页面
<template>
<tree-select
v-model="selectedId"
:options="treeData"
:defaultProps="defaultProps"
placeholder="请选择"
@change="handleChange"
/>
</template>
<script>
import TreeSelect from '@/components/pop.vue';
export default {
components: { TreeSelect },
data() {
return {
selectedId: '',
defaultProps:{label: 'label', value: 'id', children: 'children' },
treeData: [
// 示例树形数据
{
id: 1,
label: '一级节点 1',
children: [
{
id: 11,
label: '二级节点 1-1',
},
{
id: 12,
label: '二级节点 1-2',
},
],
},
{
id: 2,
label: '一级节点 2',
children: [
{
id: 21,
label: '二级节点 2-1',
},
],
},
]
};
},
methods: { handleChange(value) { console.log('选中的值改变为:', value); } }
};
</script>