ElTree组件可以带线了?

近期有需求希望树形控件可以带线,UI可能觉得这样逼格会高点。无奈我们的ElTree组件不带这个功能,于是手动基于ElTree来扩展一个,方便平时开发中使用。

先看下组件扩展后的样子

嗯,这是目前扩展后的功能,有了上图的样子后,就得定义使用姿势,然后再看如何实现,先看下使用姿势

js 复制代码
<template> 
  <el-line-tree 
    style="max-width: 600px" 
    :data="data" 
    @node-click="handleNodeClick" 
  /> 
</template>

主要使用姿势和ElTree一样,只是新增了几个属性控制线的颜色和弧度。

代码全部黏贴,比较浪费空间,可以点这个文档地址去查看

有了上面的ui及使用姿势,接下来就是看看如何实现

  1. 因为要保留ElTree组件的所有功能,且扩张其功能,我们先把$attrs绑定给el-tree,然后把el-tree的default和empty插槽给开放出来,然后重写default插槽即可,这样就把el-tree组件的所有功能都继承了。
js 复制代码
<template>
  <el-tree
    :class="ns.b()"
    :style="treeStyle"
    v-bind="$attrs"
    :expand-on-click-node="expandOnClickNode"
  >
    <template #default="{ node, data }">
      <div
        :class="nsNode.e('collapse')"
        @click.stop="handleExpandIconClick(node)"
      >
        <slot name="collapse" v-bind="{ node, data }">
          <el-icon
            :class="[
              nsNode.is('leaf', node.isLeaf),
              {
                expanded: !node.isLeaf,
              },
            ]"
            size="15"
            v-bind="iconProps"
          >
            <component :is="icon ? icon : node.expanded ? Expand : PutAway" />
          </el-icon>
        </slot>
      </div>

      <div
        :class="[
          nsNode.e('content'),
          showContentLine ? nsNode.m('content-line') : '',
        ]"
        :level="node.level"
      >
        <slot v-bind="{ node, data }">
          <span>{{ node.label }}</span>
        </slot>
      </div>
    </template>
    <template #empty>
      <slot name="empty" />
    </template>
  </el-tree>
</template>

<script lang="ts" setup>
import { computed } from 'vue'
import { ElIcon, ElTree, useNamespace } from 'element-plus'
import * as IconsVue from '@element-plus/components/icons-vue'
import { lineTreeEmits, lineTreeProps } from './line-tree'
const { Expand, PutAway } = IconsVue

defineOptions({
  name: 'ElLineTree',
  inheritAttrs: false,
})
const ns = useNamespace('line-tree')
const nsNode = useNamespace('line-tree-node')

const props = defineProps(lineTreeProps)
defineEmits(lineTreeEmits)

const treeStyle = computed(() => {
  const prefix = `--${ns.namespace.value}`
  return {
    [`${prefix}-line-tree-line-color`]: props.lineColor,
    [`${prefix}-line-tree-line-radius`]: props.lineRadius,
    [`${prefix}-line-tree-collapse-width`]: props.collapseWidth,
  }
})

const handleExpandIconClick = (node: any) => {
  if (node.isLeaf || !props.expandOnClickNode) return
  node.expanded ? node.collapse() : node.expand()
}
</script>

一键省流,上面代码主要给自定义节点中添加了一个collapse元素和内容元素,这个collapse元素很重要,因为后续的连线需要基于它来计算位置,其他不用管,因为主要是css连的线,后面才是重点

css连线

  1. 先看下el-tree的dom结构
  • .el-tree-node元素包含 .el-tree-node__content元素和 .el-tree-node__children元素
  • .el-tree-node__content元素包含三角箭头,checkbox,loading, .el-line-tree-node__collapse, .el-line-tree-node__content这5个元素,只不过checkbox,loading元素没渲染出来。

  • 注意.el-line-tree-node__collapse, .el-line-tree-node__content元素是我们新增的元素。

  • .el-tree-node__children元素又包含.el-tree-node元素,这也是递归渲染出来的结果

  1. 先画折线
  • 根据border-left和border-bottom画出2条线
  • 宽度需要为折叠器的一半,left需要偏移折叠器折叠器一半且-1,因为线本身有1px的宽度
  • bottom则为节点高度减去折叠器高度,其实我认为50%更好,这还得根据不同节点高度去尝试
  • 这样就把这个折线画好了,但是你会发现有断层,接下来就把断层补上
  1. 断层线补上
  • 给.el-tree-node__children元素添加伪元素
  • 主要说下left值,为折叠器的一半,-1是为了平衡border-left值为1的效果
  • 所以到这里,线已出来了,也知道了折叠器元素宽高的重要性了

总结

这个组件本质就是通过css伪元素设置的,并没有修改el-tree组件的源代码,其实我先前的做法是通过js控制的。 还有希望el-tree组件能够开放一个折叠的插槽就完美了

在上面再包一层插槽不香吗,你都想到了让用户传入icon来换图标,咋不再做的更通用点呢?

当然element-plus组件确实帮助我们开发节省了大量时间,还是非常感谢elp团队的。

由于平时开发中,也基于element-plus组件开发了一些通用组件,有element-plus组件没有的组件,也有增强版的组件(比如上述的line-tree组件)。该组件库叫 element-plus-x

element-plus-x 文档地址

element-plus-x github地址

喜欢的同学,希望可以给个小星星,谢谢

相关推荐
伍哥的传说5 分钟前
daisyUI 扩展之 pin input 组件开发,极致pin码输入框
前端·javascript·react.js·交互
云小遥33 分钟前
Cornerstone3D 2.x升级调研
前端·数据可视化
李明卫杭州38 分钟前
浅谈JavaScript中Blob对象
前端·javascript
springfe010139 分钟前
Cesium 3D地图 图元 圆柱 图片实现
前端·cesium
meng半颗糖41 分钟前
vue3 双容器自动扩展布局 根据 内容的多少 动态定义宽度
前端·javascript·css·vue.js·elementui·vue3
yt9483243 分钟前
jquery和CSS3圆形倒计时特效
前端·css3·jquery
teeeeeeemo44 分钟前
CSS3 动画基础与技巧
前端·css·笔记·css3
年纪轻轻就扛不住1 小时前
CSS3 渐变效果
前端·css·css3
Aisanyi1 小时前
【鸿蒙开发】使用HMRouter路由的使用
前端·harmonyos
杉木笙1 小时前
Flutter 代码雨实现(矩阵雨)DLC 多图层
前端·flutter