elementui tree 组件搜索显示子级并高亮以及节点失焦后去掉背景色

2,016 阅读1分钟

功能介绍

image.png

本节要优化的 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>