下拉树单选
<el-select
v-model="selectModel"
placeholder="请选择..."
size="small"
clearable
filterable
:filter-method="singleTreeFilterMethod"
ref="select"
popper-class="customSelectPopper"
@focus="singleTreeFocus"
@clear="singleTreeClear">
<el-option
v-for="item of selectOptions"
:key="item.id"
:label="item.label"
:value="item.id"
v-show="false">
</el-option>
<div class="singleTree">
<el-tree
:data="selectTreeData"
ref="selectTree"
node-key="id"
empty-text="无匹配数据"
highlight-current
:expand-on-click-node="expandOnClickNode" // 是否在点击节点的时候展开或者收缩节点
:default-expanded-keys="defaultExpandedkeys" // 默认展开的节点的 key 的数组
:props="{'label': 'label', children: 'children', disabled: 'disabled', isLeaf: 'isLeaf'}"
:filter-node-method="filterNode"
@node-click="selectTreeNodeClickEvent">
</el-tree>
</div>
</el-select>
data(){
return {
selectModel: '',
selectOptions: [],
selectTreeData: [{
id: '1',
label: '一级 1',
isLeaf: false,
children: [{
id: '1-1',
label: '二级 1-1',
isLeaf: false,
children: [{
id: '1-1-1',
label: '三级 1-1-1',
isLeaf: true
}]
}]
}, {
id: '2',
label: '一级 2',
isLeaf: false,
children: [{
id: '2-1',
label: '二级 2-1',
isLeaf: false,
children: [{
id: '2-1-1',
label: '三级 2-1-1',
isLeaf: true
}]
}, {
id: '2-2',
label: '二级 2-2',
isLeaf: false,
children: [{
id: '2-2-1',
label: '三级 2-2-1',
isLeaf: true
}]
}]
}, {
id: '3',
label: '一级 3',
isLeaf: false,
children: [{
id: '3-1',
label: '二级 3-1',
isLeaf: false,
children: [{
id: '3-1-1',
label: '三级 3-1-1',
isLeaf: true
}]
}, {
id: '3-2',
label: '二级 3-2',
isLeaf: false,
children: [{
id: '3-2-1',
label: '三级 3-2-1',
isLeaf: true
}]
}]
}],
expandOnClickNode: false,
defaultExpandedkeys: []
}
},
methods:{
/**
* select 单选下拉树自定义搜索
* @param {Object} val
*/
singleTreeFilterMethod(val){
this.$refs.selectTree.filter(val);
},
/**
* select 获取焦点事件
*/
singleTreeFocus(){
this.$refs.selectTree.filter("");
},
/**
* tree 节点过滤
* @param {Object} value
* @param {Object} data
*/
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
/**
* tree 节点点击事件
* @param {Object} data
*/
selectTreeNodeClickEvent(data){
if(this.expandOnClickNode){ // 只有叶子节点可被选择
if(data.isLeaf && data.isLeaf == true){
this.selectModel = data.id; // select v-model 赋值
this.selectOptions = [data]; // 隐藏的 select option 赋值
this.$refs.select.blur(); // 收起 select 下拉框
}
}else{ // 任意节点可被选择
this.selectModel = data.id; // select v-model 赋值
this.selectOptions = [data]; // 隐藏的 select option 赋值
this.$refs.select.blur(); // 收起 select 下拉框
}
},
/**
* select 清空按钮点击事件
*/
singleTreeClear(){
// do something
},
/**
* 回显数据
*/
echoData(){
let data = 请求接口返回值;
// select v-model 赋值
this.selectModel = data.id;
// 隐藏的 select option 赋值
this.selectOptions = [{
id: data.id,
label: data.label
}];
this.defaultExpandedkeys = [data.id]; // 展开选中的节点
this.$refs.selectTree.setCurrentKey(data.id); // 设置节点高亮
// 无法使用 current-node-key(当前选中的节点) 属性,如果在 data 里定义初始值,可以实现该 id 对应节点的默认选中高亮效果
// 但如果用 this.currentNodeKey = xx 再修改这个值,没有任何变化
}
}
下拉树多选
<el-select
v-model="selectModel"
placeholder="请选择..."
multiple
size="small"
clearable
ref="select"
class="selectMultiple"
popper-class="customSelectPopper"
@remove-tag="removeTag"
@clear="multipleTreeClear">
<el-option
v-for="item of selectOptions"
:key="item.id"
:label="item.label"
:value="item.id"
v-show="false">
</el-option>
<div class="multipleTree">
<!-- 当 el-select 在 el-form 表单中,并且属于必填项,添加 el-form-item 标签 以便解决 在搜索 input 中输入时执行 el-select 验证 -->
<el-form-item style="margin-bottom: 0;" v-if="inForm">
<el-input v-model="selectTreeNodeFilterText" size="small" placeholder="请输入关键字搜索" class="filterInp"></el-input>
</el-form-item>
<el-input v-else v-model="selectTreeNodeFilterText" size="small" placeholder="请输入关键字搜索" class="filterInp"></el-input>
<div class="treeWrapper">
<el-scrollbar class="commonScrollbar">
<el-tree
:data="selectTreeData"
show-checkbox
ref="selectTree"
node-key="id"
empty-text="无匹配数据"
:default-expanded-keys="defaultExpandedkeys" // 默认展开的节点的 key 的数组
:default-checked-keys="defaultCheckedKeys" // 默认勾选的节点的 key 的数组
:props="{'label': 'label', children: 'children', disabled: 'disabled', isLeaf: 'isLeaf'}"
:filter-node-method="filterNode"
@check="selectTreeNodeCheckEvent">
</el-tree>
</el-scrollbar>
</div>
</div>
</el-select>
data(){
return {
inForm: false,
selectModel: [],
selectOptions: [],
selectTreeData: [{
id: '1',
label: '一级 1',
isLeaf: false,
children: [{
id: '1-1',
label: '二级 1-1',
isLeaf: false,
children: [{
id: '1-1-1',
label: '三级 1-1-1',
isLeaf: true
}]
}]
}, {
id: '2',
label: '一级 2',
isLeaf: false,
children: [{
id: '2-1',
label: '二级 2-1',
isLeaf: false,
children: [{
id: '2-1-1',
label: '三级 2-1-1',
isLeaf: true
}]
}, {
id: '2-2',
label: '二级 2-2',
isLeaf: false,
children: [{
id: '2-2-1',
label: '三级 2-2-1',
isLeaf: true
}]
}]
}, {
id: '3',
label: '一级 3',
isLeaf: false,
children: [{
id: '3-1',
label: '二级 3-1',
isLeaf: false,
children: [{
id: '3-1-1',
label: '三级 3-1-1',
isLeaf: true
}]
}, {
id: '3-2',
label: '二级 3-2',
isLeaf: false,
children: [{
id: '3-2-1',
label: '三级 3-2-1',
isLeaf: true
}]
}]
}],
defaultExpandedkeys: [],
defaultCheckedKeys: [],
selectTreeNodeFilterText: ''
}
},
watch: {
selectTreeNodeFilterText(val) {
this.$refs.selectTree.filter(val);
}
},
methods:{
/**
* tree 节点过滤
* @param {Object} value
* @param {Object} data
*/
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
/**
* tree 节点 check 事件(当复选框被点击的时候触发)
* @param {Object} currentNodeObj 传递给 data 属性的数组中该节点所对应的对象
* @param {Object} treeCheckNodeObj 树目前的选中状态对象
*/
selectTreeNodeCheckEvent(currentNodeObj, treeCheckNodeObj){
// 获取所有选中的节点 key 并给 select v-model 赋值
this.selectModel = treeCheckNodeObj.checkedKeys;
// 获取所有选中的节点对象 并给 隐藏的 select option 赋值
this.selectOptions = treeCheckNodeObj.checkedNodes;
},
/**
* 多选模式下移除 tag 事件
* @param {Object} tag 当前 tag 对象
*/
removeTag(data){
// 获取所有选中的节点对象
let checkNode = this.$refs.selectTree.getCheckedNodes(true);
// 删除节点
for(let i = 0; i < checkNode.length; i++){
if(checkNode.id == data.id){
checkNode.splice(i, 1);
break;
}
}
// 设置 tree 选中的节点
this.$refs.selectTree.setCheckedNodes(checkNode);
},
/**
* 点击清空按钮时触发
*/
multipleTreeClear(){
this.$refs.selectTree.setCheckedNodes([]);
},
/**
* 回显数据
*/
echoData(){
let data = 请求接口返回值;
// select v-model 赋值
this.selectModel = data.ids;
// 隐藏的 select option 赋值
for(let i = 0; i < data.ids.length; i++){
this.selectOptions.push({
id: data.ids[i],
label: data.label[i]
});
}
this.defaultExpandedkeys = data.ids; // 展开选中的节点
this.$refs.selectTree.setCheckedKeys(data.ids); // 默认选中的节点
// 或者
this.defaultCheckedKeys = data.ids; // 默认选中的节点
}
}
css
<style lang="scss" scoped>
/* 自定义 select 下拉 公共样式 */
.customSelectPopper{
.el-scrollbar{
display: block !important;
.el-scrollbar__wrap{
max-height: 317px;
.el-scrollbar__view{
.el-select-dropdown__item{
display: none;
}
// 自定义下拉树-----单选
.singleTree{
.el-tree__empty-block{
padding: 4px 0;
font-size: 14px;
min-height: 14px;
height: 14px;
.el-tree__empty-text{
color: #999;
}
}
}
// 自定义下拉树-----多选
.multipleTree{
.filterInp{
width: calc(100% - 40px);
display: block;
margin: 0 auto;
}
.treeWrapper{
padding: 10px 0;
height: 207px;
box-sizing: border-box;
.el-tree__empty-block{
padding: 4px 0;
font-size: 14px;
min-height: 14px;
height: 14px;
.el-tree__empty-text{
color: #999;
}
}
.el-scrollbar{
.el-scrollbar__bar{
z-index: 2;
}
}
}
}
}
}
&.is-empty{
.el-scrollbar__wrap{
.el-scrollbar__view{
padding: 6px 0;
}
}
}
}
// 隐藏 select 空数据提示
.el-select-dropdown__empty{
display: none;
}
}
/* 下拉多选 公共样式 */
.selectMultiple{
.el-select__tags{
&>span{
display: block;
width: 100%;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
margin-left: 2px;
.el-tag{
display: inline-block;
}
&::-webkit-scrollbar{
width: 0;
height: 0;
}
}
}
&.noneClose{
.el-select__tags{
.el-tag{
.el-tag__close{
display: none;
}
}
}
}
}
/* 全局设置el-scrollbar高度 */
.commonScrollbar.el-scrollbar{
height: 100%;
}
/* 全局隐藏el-scrollbar横向滚动条 */
.commonScrollbar.el-scrollbar .el-scrollbar__wrap{
overflow-x: hidden;
}
/* 全局设置子容器高度 */
// .commonScrollbar.el-scrollbar .el-scrollbar__wrap .el-scrollbar__view{
// height: 100%;
// }
</style>