el-tree图标改成带线的

149 阅读2分钟

实现思路:给el-tree-node__children添加伪类画竖线,给el-tree-node__content添加伪类画横线,通过位置调整让竖线和直线正好连在一起。图标通过icon-class先去除原先图标后根据之前图标的类名重添加置背景图。这样还可以保留之前图标的点击旋转

<!-- 
 * @fileName: GroupChatTree.vue.vue 
!-->
<template>
  <div :class="ns.b()">
    <el-scrollbar style="height: 100%">
      <el-tree
        class="treeCont"
        :indent="0"
        :data="treeData"
        :props="defaultProps"
        highlight-current
        check-strictly
        current-node-key="id"
        node-key="id"
        default-expand-all
        @node-click="handleNodeClick"
        icon-class="empty-icon"
      >
        <template #default="{ node, data }">
          <div :class="[ns.b('label'), ns.is('leftLable', node?.isLeaf), ns.is('active', node?.isLeaf && data?.id === treeValue)]" :title="data?.label">
            <img :src="$utils.format.getIconByAppType(data.appType, data.type)" width="18px" height="18px" class="mr6" />
            <div :class="ns.e('label')">{{ data?.label || '' }}</div>
          </div>
        </template>
      </el-tree>
    </el-scrollbar>
  </div>
</template>

<script>
import { NameSpace } from '@/common/utils/nameSpace'
import { getBelongAccountAndGroup } from '@/common/api/analysisModuleApi'

export default {
  components: {},
  model: {
    prop: 'value',
    event: 'changeEvent'
  },
  props: {
    value: {
      type: String,
      default: ''
    },
    api: {
      type: Function,
      required: false
    },
    params: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      ns: new NameSpace('GroupChatTree'),
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      // interface ITreeData {
      //   id: string | number
      //   accountId: String, // 账户id(可能重复)
      //   label:String
      //   appType:String
      //   type:String
      //   children:ITreeData[]
      // }
      treeData: []
    }
  },
  computed: {
    // 树的value
    treeValue: {
      get() {
        return this.value
      },
      set(val) {
        this.$emit('changeEvent', val)
        // //递归树通过id找到对应节点并返回
        const item = this.findItemById({ children: this.treeData }, val)
        // console.log('00000item', item)
        this.$emit('change', { val, item, treeData: this.treeData })
      }
    }
  },
  watch: {
    params: {
      handler() {
        this.init()
      },
      deep: true
    }
  },
  created() {
    this.init()
  },
  mounted() {},
  methods: {
    async init() {
      let res = {}
      if (this.api) {
        res = await this.api(this.params)
      } else {
        res = await getBelongAccountAndGroup({
          suspectId: this.$cookies.get('suspectId') || this.$store.state?.project.curSuspectId
        })
      }
      if (!res?.data || !Array.isArray(res?.data)) return
      this.treeData = res?.data || []
      const { id } = this.getFirstLeafNode(res.data[0])
      //默认选中第一个节点的第一个叶子节点
      this.treeValue = id
    },
    handleNodeClick(data, node) {
      if (!node.isLeaf) return
      this.treeValue = data?.id || ''
      // this.$emit('changeEvent', (this.treeValue = data?.id || ''))
    },
    //递归获取第一个节点的第一个叶子节点
    getFirstLeafNode(item) {
      if (item.children && Array.isArray(item.children) && item.children.length) {
        return this.getFirstLeafNode(item.children[0])
      } else {
        return item
      }
    },
    // 通过id查找节点
    findItemById(tree, id) {
      // 检查当前节点是否匹配
      if (tree.id === id) {
        return tree
      }
      // 如果当前节点有子节点,递归查找
      if (tree.children && tree.children.length > 0) {
        for (let i = 0; i < tree.children.length; i++) {
          const result = this.findItemById(tree.children[i], id)
          if (result) {
            return result
          }
        }
      }
      // 如果没有找到匹配的节点,返回 null
      return null
    }
  }
}
</script>
<style lang="scss" scoped>
.dyt-GroupChatTree {
  height: 100%;

  .dyt-GroupChatTree-label {
    width: calc(100% - 28px);
    height: 100%;
    display: flex;
    align-items: center;

    .dyt-GroupChatTree__label {
      white-space: nowrap; /* 不换行 */
      overflow: hidden; /* 溢出隐藏 */
      text-overflow: ellipsis; /* 溢出显示省略号 */
    }
  }

  .is-leftLable {
    width: 100% !important;
    padding-left: 5px;
    box-sizing: border-box;
  }
}

.is-active {
  color: #4b8dff;
}

/deep/ .custom-scrollbar .el-scrollbar__bar {
  right: 20px; /* 向右移动 20px */
}

/deep/ .el-scrollbar__wrap {
  padding-right: 12px;
}

/deep/ .el-tree-node {
  //margin-bottom: 6px;
  padding: 3px 0;
}

::v-deep .treeCont {
  .el-tree-node__children {
    position: relative;
    padding-left: 24px;

    .el-tree-node__content {
      position: relative;
    }

    .el-tree-node__content:before {
      content: '';
      width: 12px;
      height: 1px;
      background-color: #ccc;
      position: absolute;
      left: -16px;
      top: 50%;
    }
  }

  .el-tree-node__children:before {
    content: '';
    width: 24px;
    height: 100%;
    border-left: 1px solid #ccc;
    position: absolute;
    left: 8px;
    top: -16px;
  }
}

//菜单自定义按钮
/deep/ .el-tree-node__expand-icon {
  background-image: url('../../../assets/images/analysisModule/tree-open.png');
  background-size: cover; /* 或者你可以根据需要调整大小 */
  width: 16px !important; /* 根据图片大小调整 */
  height: 16px !important; /* 根据图片大小调整 */
  margin-right: 5px !important;
  margin-bottom: 0 !important;
}

/deep/ .expanded {
  background-image: url('../../../assets/images/analysisModule/tree-close.png') !important;
  width: 14px !important; /* 根据图片大小调整 */
  height: 14px !important; /* 根据图片大小调整 */
  margin-right: 6px !important;
  margin-left: 1px !important;
}

//叶子节点的icon不显示
/deep/ .is-leaf {
  display: none !important;
}
</style>

image.png