这是一个给 element-ui和element-plus的 el-tree
添加结构线的子组件,不会对 el-tree
原有的功能造成任何的影响,同时能够支持element-plus 的 Virtualized Tree 虚拟树,有了线的展示,从美观和树形结构清晰上都有很好的体现。(我总是在做不是很重要的东西,哈哈)
# npm
npm install element-tree-line -S
# yarn
yarn add element-tree-line -S
// 全局注册组件
import Vue from 'vue';
import ElementTreeLine from 'element-tree-line';
// css
import 'element-tree-line/dist/style.css';
// or scss
// import 'element-tree-line/dist/style.scss';
Vue.component(ElementTreeLine.name, ElementTreeLine);
// or 局部注册组件
import ElementTreeLine from 'element-tree-line';
// css
import 'element-tree-line/dist/style.css';
// or scss
// import 'element-tree-line/dist/style.scss';
export default {
components: { ElementTreeLine },
data() {
return {};
},
};
案例效果
<template>
<el-card shadow="never" :body-style="{ padding: '20px 0px 20px 20px' }">
<div style="margin-bottom: 10px">
<span style="margin-right: 5px">showLabelLine</span>
<el-switch v-model="treeProps['showLabelLine']"></el-switch>
<span style="margin-left: 20px;margin-right:5px;">indent</span>
<el-input-number v-model="treeProps['indent']"></el-input-number>
</div>
<el-tree
ref="tree"
:data="data"
draggable=""
show-checkbox
node-key="id"
:default-expanded-keys="[2, 3]"
:default-checked-keys="[5]"
:props="defaultProps"
:indent="treeProps['indent']"
>
<template v-slot:default="{ node }">
<element-tree-line
:node="node"
:showLabelLine="treeProps['showLabelLine']"
:indent="treeProps['indent']"
>
<!-- 自定义label的slot -->
<template v-slot:node-label>
<span style="font-size: 12px">
{{ node.label }}
<i class="el-icon-eleme"></i
></span>
</template>
<!-- 在右边追加内容的slot -->
<template v-slot:after-node-label>
<span style="padding-right: 10px">
<el-button
type="primary"
size="mini"
@click.stop="openDrawer(node)"
>新增子节点</el-button
>
<el-button
type="primary"
size="mini"
@click.stop="openDrawer(node)"
>修改</el-button
>
<el-button
type="danger"
size="mini"
@click.stop="openDialog"
>删除</el-button
></span
>
</template>
</element-tree-line>
</template>
</el-tree>
</el-card>
</template>
<script>
import ElementTreeLine from 'element-tree-line';
import 'element-tree-line/dist/style.css';
export default {
components: { ElementTreeLine },
data() {
return {
treeProps: {
indent: 16,
showLabelLine: true,
},
data: [
{
id: 1,
label: '一级 1',
children: [
{
id: 4,
label: '二级 1-1',
children: [
{
id: 9,
label: '三级 1-1-1',
},
{
id: 10,
label: '三级 1-1-2',
},
],
},
{
id: 9000,
label: '二级 1-2',
},
],
},
{
id: 2,
label: '一级 2',
children: [
{
id: 5,
label: '二级 2-1',
},
{
id: 6,
label: '二级 2-2',
},
],
},
{
id: 3,
label: '一级 3',
children: [
{
id: 7,
label: '二级 3-1',
},
{
id: 8,
label: '二级 3-2',
},
],
},
],
defaultProps: {
children: 'children',
label: 'label',
},
};
},
};
</script>
<style>
.el-tree-node__content {
padding-top: 5px;
padding-bottom: 5px;
}
</style>
// 全局注册组件
import { createApp, h } from 'vue';
import { getElementLabelLine } from 'element-tree-line';
// css
import 'element-tree-line/dist/style.css';
// or scss
// import 'element-tree-line/dist/style.scss';
// 创建一个Vue 应用
const app = Vue.createApp({});
// 全局注册ElementLabelLine
const ElementLabelLine = getElementLabelLine(h);
app.component(ElementLabelLine.name, ElementLabelLine);
// or 局部注册组件
import { getElementLabelLine } from 'element-tree-line';
// css
import 'element-tree-line/dist/style.css';
// or scss
// import 'element-tree-line/dist/style.scss';
import { h } from 'vue';
export default {
components: { ElementTreeLine: getElementLabelLine(h) },
data() {
return {};
},
};
案例效果
<template>
<el-tree
:data="data"
show-checkbox
node-key="id"
draggable
:default-expanded-keys="[2, 3]"
:default-checked-keys="[5]"
:props="defaultProps"
:indent="treeIndent"
><template v-slot:default="{ node }">
<element-tree-line
:node="node"
:showLabelLine="true"
:indent="treeIndent"
>
<template v-slot:node-label>
<span style="font-size: 12px">
{{ node.label }}
<el-tag type="danger" size="mini">Tag 5</el-tag>
</span>
</template>
<template v-slot:after-node-label>
<span style="padding-right: 10px">
<el-button size="mini">按钮</el-button>
</span>
</template>
</element-tree-line>
</template>
</el-tree>
</template>
<script>
import { getElementLabelLine } from 'element-tree-line';
import 'element-tree-line/dist/style.css';
import { h } from 'vue';
export default {
components: { ElementTreeLine: getElementLabelLine(h) },
data() {
return {
treeIndent: 30,
data: [
{
id: 1,
label: 'Level one 1',
children: [
{
id: 4,
label: 'Level two 1-1',
children: [
{
id: 9,
label: 'Level three 1-1-1',
},
{
id: 10,
label: 'Level three 1-1-2',
},
],
},
],
},
{
id: 2,
label: 'Level one 2',
children: [
{
id: 5,
label: 'Level two 2-1',
},
{
id: 6,
label: 'Level two 2-2',
},
],
},
{
id: 3,
label: 'Level one 3',
children: [
{
id: 7,
label: 'Level two 3-1',
},
{
id: 8,
label: 'Level two 3-2',
},
],
},
],
defaultProps: {
children: 'children',
label: 'label',
},
};
},
};
</script>
<style>
.el-tree-node__content {
padding-top: 5px;
padding-bottom: 5px;
}
</style>
案例效果
<template>
<el-tree-v2
:data="treeData"
:props="props"
:indent="treeIndent"
:height="400"
>
<template v-slot:default="{ node }">
<element-tree-line
:node="node"
:treeData="treeData"
:showLabelLine="true"
:indent="treeIndent"
>
</element-tree-line>
</template>
</el-tree-v2>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { getElementLabelLine } from 'element-tree-line';
import 'element-tree-line/dist/style.css';
import { h } from 'vue';
const getKey = (prefix, id) => {
return `${prefix}-${id}`;
};
const createData = (
maxDeep,
maxChildren,
minNodesNumber,
deep = 1,
key = 'node'
) => {
let id = 0;
return new Array(minNodesNumber).fill(deep).map(() => {
const childrenNumber =
deep === maxDeep ? 0 : Math.round(Math.random() * maxChildren);
const nodeKey = getKey(key, ++id);
return {
id: nodeKey,
label: nodeKey,
children: childrenNumber
? createData(
maxDeep,
maxChildren,
childrenNumber,
deep + 1,
nodeKey
)
: undefined,
};
});
};
export default defineComponent({
components: { ElementTreeLine: getElementLabelLine(h) },
setup() {
return {
treeData: createData(4, 30, 40),
treeIndent: 40,
props: ref({
id: 'id',
label: 'label',
children: 'children',
}),
};
},
});
</script>
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
node | 由el-tree 的 default slot 提供的作用域参数 node,必填。 | object | - | - |
showLabelLine | 是否显示 label 的横线 | boolean | - | false |
treeData | 对应element-plus 的 el-tree-v2 的 data,当用在 element-plus 的 el-tree-v2 时,treeData 是必填的。 | array | - | - |
indent | 相邻级节点间的水平缩进,单位为像素 ; 对应el-tree 的 indent。 | number | - | 16 |
插槽名称 | 说明 |
---|---|
node-label | 自定义 label 区域 |
after-node-label | 追加在 label line 之后 |
如果使用的是scss,可以覆盖scss变量修改线的颜色
$--element-tree-line-color: #dcdfe6;
$--element-tree-line-style: dashed;
$--element-tree-line-width: 1px;
@import 'element-tree-line/dist/style.scss';
在做 ElementLabelLine 之前,看 element-ui issues 有不少人提到 el-tree 结构线的需求,官方依然没有支持,有搜索到一些直接覆盖 el-tree 的 css 做法,在节点缩进、点击行效果、拖拽等方面没有很贴合的效果,并不是我想要的
ElementLabelLine 作为 el-tree 子组件的方式,无侵入性,可插拔,很优雅的添加结构线。