功能介绍
本节要优化的 el-Tree 组件具有以下功能:
- 搜索之后显示所有的子级
- 节点匹配到关键字 高亮展示
- 节点失焦后 去掉背景色
实现思路
- 通过自定义filter-node-method 去改变搜索的逻辑
- 高亮通过加入class类名显示
- 背景色去除通过伪类解决,让高亮的样式优先级大于聚焦,并将聚集后的节点背景色设置为白色
Dom部分
<el-tree
ref="tree"
:data="data"
:props="props"
:filter-node-method="filterNodeMethod"
:highlight-current="true"
node-key="value"
:current-node-key="currentNodeKey"
@node-click="handleNodeClick"
>
<template #default="scope">
<div
:class="
keyword === ''
? ''
: scope.data.label.indexOf(keyword) !== -1
? 'has-key-word-style'
: ''
"
>
{{ scope.data.label }}
</div>
</template>
</el-tree>
js部分
// 注意node参数 为所有节点
// 返回值为每个节点的visable属性值 决定是否展示
filterNodeMethod (value, data, node) {
if (!value) {
return true
}
return this.getHasKeyword(value, node)
},
// 递归查找是否还有父节点
getHasKeyword (value, node) {
if (node.data instanceof Array) {
node.data = node.data.length > 0 ? node.data[0] : {}
}
if (node.data.label && node.data.label.indexOf(value) !== -1) {
return true
} else {
return node.parent && this.getHasKeyword(value, node.parent)
}
}
style 部分
// 当前高亮的样式
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background-color: #edf6ff !important;
}
// 鼠标移入的样式
.el-tree-node:hover > .el-tree-node__content {
background: #f5f7fa !important;
}
// 节点聚焦的样式
.el-tree-node:focus > .el-tree-node__content {
background: #ffffff;
}
完整代码
<template>
<div class="organization-tree">
<span class="tree-title">{{ title }}</span>
<div class="tree-list">
<div class="tree-filter">
<el-input v-model="keyword" :placeholder="placeholder" @input="handleInput" />
<el-button v-if="isCreate" icon="el-icon-plus" />
</div>
<div class="tree-all" :class="!activeNode ? 'tree-all-iscurrent' : ''" @click="clickAll">
全部
</div>
<div class="tree-content">
<el-tree
ref="tree"
:data="data"
:props="props"
:filter-node-method="filterNodeMethod"
:highlight-current="true"
node-key="value"
:current-node-key="currentNodeKey"
@node-click="handleNodeClick"
>
<template #default="scope">
<div
:class="
keyword === ''
? ''
: scope.data.label.indexOf(keyword) !== -1
? 'has-key-word-style'
: ''
"
>
{{ scope.data.label }}
</div>
</template>
</el-tree>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'OrganizationTree',
props: {
isCreate: {
type: Boolean,
default: true
},
title: {
type: String,
default: '组织树'
},
data: {
type: Array,
default: () => []
},
props: {
type: Object,
default: () => ({})
},
placeholder: {
type: String,
default: '请输入关键字'
}
},
data () {
return {
keyword: '',
currentNodeKey: null,
filterData: [], // 过滤后的数据
activeNode: null // 默认激活全部
}
},
methods: {
async handleInput (v) {
this.$refs.tree.filter(v)
},
clickAll () {
this.activeNode = null
this.currentNodeKey = null
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(null)
})
this.$emit('all-click')
},
handleNodeClick (data, node) {
if (this.activeNode === data.value) {
// 二次点击
this.clickAll()
return
}
this.activeNode = data.value
this.$emit('node-click', data, node)
},
filterNodeMethod (value, data, node) {
if (!value) {
return true
}
return this.getHasKeyword(value, node)
},
getHasKeyword (value, node) {
if (node.data instanceof Array) {
node.data = node.data.length > 0 ? node.data[0] : {}
}
if (node.data.label && node.data.label.indexOf(value) !== -1) {
return true
} else {
return node.parent && this.getHasKeyword(value, node.parent)
}
}
}
}
</script>
<style lang="scss">
.organization-tree {
background: #ffffff;
width: 264px;
border-radius: 2px;
.tree-title {
display: inline-block;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC, serif;
font-weight: 400;
color: #666666;
box-sizing: border-box;
padding: 16px 24px;
}
.tree-list {
border-top: 1px solid #e9e9e9;
box-sizing: border-box;
padding: 16px 24px;
.tree-filter {
display: flex;
margin-bottom: 24px;
.el-input__inner {
height: 36px;
background: #ffffff;
border-radius: 2px;
border: 1px solid #d9d9d9;
}
.el-button {
width: 32px;
height: 36px;
background: #ffffff;
border-radius: 2px;
border: 1px solid #d9d9d9;
padding: 0 5px;
margin-left: 10px;
}
}
.tree-all {
cursor: pointer;
color: #666666;
height: 26px;
line-height: 26px;
&-iscurrent {
background-color: #edf6ff !important;
}
}
.tree-all:hover {
background-color: #f5f7fa;
}
.tree-content {
height: 500px;
overflow: auto;
}
.has-key-word-style {
background-color: #d5ebfc;
}
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background-color: #edf6ff !important;
}
.el-tree-node:hover > .el-tree-node__content {
background: #f5f7fa !important;
}
.el-tree-node:focus > .el-tree-node__content {
background: #ffffff;
}
}
</style>