1. 为什么我们需要一个下拉树组件?
在Vue2和Element UI的项目里,el-select下拉框大家肯定都用得滚瓜烂熟了。选个简单的城市、选个部门,它都能轻松搞定。但不知道你有没有遇到过这种头疼的场景:你需要让用户从一个层级很深、结构复杂的树形数据里选一个节点。比如,选一个公司的组织架构(总公司-分公司-部门-小组),或者选一个商品的多级分类(大类-中类-小类-具体型号)。
这时候,如果还用传统的el-select,把整棵树的所有节点都平铺成el-option,那下拉列表会变得巨长无比,用户根本找不到北。你可能会想,那我用el-tree组件单独弹个窗不就行了?但这样操作路径就变长了,用户需要先点一个按钮打开弹窗,在树里找,再点确定,体验上不够直接和流畅。
所以,一个理想的需求就诞生了:能不能把el-tree直接“塞”进el-select的下拉框里?让用户点击下拉箭头,看到的就是一个可以展开折叠的树,选中后,输入框里又能正确显示选中的节点名称。这就是我们常说的“下拉树”组件。更关键的是,当我们从后端拿到一个ID(比如‘1-1-1’),需要把这个ID对应的完整路径在组件里“回显”出来时,原生的el-select更是无能为力。
我当初就是在做一个后台管理系统时,被这个需求卡住了。产品经理拿着设计稿过来,说这里要一个能选多级分类的下拉框,还要支持编辑时自动回显。我试了好几个网上找的第三方组件,不是样式冲突,就是功能不全,或者数据格式要求太死板。一咬牙,干脆自己基于el-select和el-tree封装一个。踩过几次坑之后,终于搞出了一个稳定、好用且支持完美数据回显的组件。今天我就把这个实战经验完整分享给你,你可以直接复制代码去用,也可以根据我的思路去定制属于你自己的下拉树。
2. 核心思路:el-select 与 el-tree 的巧妙结合
自己动手封装组件前,我们得先搞清楚,怎么把两个独立的组件“揉”到一起。el-select负责的是外层的输入框、下拉触发和整体的交互逻辑;而el-tree负责的是下拉面板里内容的展示和树形节点的交互。听起来好像很简单,直接把el-tree放在el-select的el-option里不就行了?但实际操作起来,有几个关键的“坑点”需要特别注意。
2.1 结构嵌套的奥秘
首先看模板结构。我们不能简单地把el-tree和el-select并列放置。Element UI的el-select组件,其下拉列表的内容是通过el-option来渲染的。所以,我们的el-tree必须作为唯一一个el-option的子内容来存在。这样,当下拉框展开时,整个树形结构就会在这个选项的位置被渲染出来。
<template>
<div class="tree-select">
<el-select
:value="valueTitle"
ref="selectEl"
@clear="clearHandle"
:filterable="filterable"
:clearable="clearable"
>
<!-- 关键在这里:只用一个el-option,里面包裹整个el-tree -->
<el-option :value="valueId" :label="valueTitle">
<el-tree
id="tree-option"
ref="selectTree"
:data="options"
:props="treeProps"
:node-key="treeProps.value"
@node-click="handleNodeClick"
>
</el-tree>
</el-option>
</el-select>
</div>
</template>
你可能会问,为什么el-option的value和label要绑定到valueId和valueTitle?这是因为el-select组件内部需要靠这两个值来管理当前选中的状态。当我们点击树节点时,会动态更新这两个值,从而让el-select知道“哦,用户选了这个”,并正确地在输入框里显示对应的标签。
2.2 样式穿透与高度控制
这是第一个大坑。默认情况下,el-select的下拉框有一个最大高度限制,并且每个el-option也有固定行高。当我们把一整棵树塞进去后,很可能会出现下拉框高度不够、显示不全,或者出现双重滚动条(下拉框一个,树自己一个)的尴尬情况。
所以,我们必须通过CSS的深度选择器(在Vue2中常用::v-deep或/deep/)来覆盖Element UI的默认样式。核心目标是:让包裹树的那个el-option高度自适应,并取消外层下拉框的滚动限制。
<style lang="scss" scoped>
.tree-select {
/* 调整输入框内部文字颜色等,按需 */
}
/* 关键样式:让下拉项容器能容纳整个树 */
::v-deep .el-select-dropdown__item {
height: auto !important;
max-height: none !important;
padding: 0 !important;
}
/* 取消el-select下拉框自身的滚动条 */
::v-deep .el-scrollbar .el-select-dropdown__wrap {
max-height: none !important;
overflow: hidden !important;
}
::v-deep .el-scrollbar .el-scrollbar__bar {
display: none !important;
}
/* 设置树节点样式,确保悬停、选中状态清晰 */
::v-deep #tree-option .el-tree-node__content {
height: 36px; /* 给树节点一个合适的高度 */
line-height: 36px;
}
::v-deep #tree-option .el-tree-node__content:hover {
background-color: #f5f7fa;
}
</style>
实测下来,这几条样式规则非常关键,能确保下拉树在任何情况下都能完整展示,且交互流畅。我当初就是没处理好滚动条,导致树只能显示一小截,调试了好久。
2.3 事件处理的联动
第二个关键点是事件联动。el-tree有点击节点的事件node-click,而el-select有选中选项、清空、下拉框收起等事件。我们需要把它们打通。
-
节点点击选中:

1万+

被折叠的 条评论
为什么被折叠?



