vue3使用element-plus,树组件el-tree增加引导线
vue3项目element-plus,树组件el-tree增加引导线
element-plus组件库的el-tree
样式
因为element
的样式不满足当前的的需求,UI图,所以对el-tree
进行增加了引导线
修改样式如下,增加引导线,并且实现增删,输入框
代码实现
1、在vue3中组件里面template模板引入el-tree组件,需要设置:indent=“0”,不然每层树padding-left呈18px的倍数增加
<div class="mytree">
<el-tree
:indent="0"
:data="data"
:props="defaultProps"
:expand-on-click-node="false"
:highlight-current="false"
node-key="id"
@node-click="handleNodeClick"
:default-expanded-keys="expDtable"
>
</el-tree>
</div>
- indet:设置每层叔padding-left为0
- data:绑定的展示数据
- props:配置选项,里面配置节点,子节点字段等,默认绑定子节点children,element-plus里面有详细的解说[Tree 树形控件 | Element Plus]
- expand-on-click-node:是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。
- node-key:每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
- node-click:当节点被点击的时候触发
- default-expanded-keys:默认展开节点
2.在setup中声明变量data,defaultProps,handleNodeClick,expDtable
import { computed, shallowRef,ref,onMounted } from 'vue';
const expDtable = ref([])
const data = ref([
{
name: '',
type: '',
describe: '',
cekk: true,
id: 1
}
])
const defaultProps = {
children: 'children',
label: 'label',
}
const handleNodeClick = data => {
console.log(data)
}
3.在el-tree里面写入输入框已经增删,接着上面模板的代码 我们往里面继续写
<el-tree
:indent="0"
:data="data"
:props="defaultProps"
:expand-on-click-node="false"
:highlight-current="false"
node-key="id"
@node-click="handleNodeClick"
:default-expanded-keys="expDtable"
>
<template #default="{ node, data }">
<!-- {{node.level}} -->
<div class="custom-tree-node" style="display: flex; width: 100%">
<div :style="{'width': node.level == 1 ? '120px' : node.level == 2 ? '100px' : '80px'}">
<el-input v-model="data.name" placeholder="变量名" :disabled="data.id == 1" />
</div>
<div style="width: 100px; margin-left: 10px">
<el-select v-model="data.type" placeholder="Select" :disabled="data.id == 1">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div style="width: 120px; margin-left: 10px">
<el-input
v-model="data.describe"
placeholder="请输入用户变量用途"
type="number"
:disabled="data.id == 1"
/>
</div>
<div style="width: 50px; text-align: center; margin-left: 20px">
<el-checkbox type="checkbox" v-model="data.cekk" :disabled="data.id == 1" />
</div>
<div style="width: 40px; text-align: right">
<span style="cursor: pointer" v-if="data.type == '2' && data.boolean != 1" @click="childAdd(node,data)"
>+</span
>
</div>
<div style="width: 40px; text-align: right">
<span style="cursor: pointer" v-if="data.id != 1" @click="remove(node, data)">-</span>
</div>
</div>
</template>
</el-tree>
4.在setup里面加上我们的新增方法,删除方法,以及选择框绑定的数据
import { computed, shallowRef,ref,onMounted } from 'vue';
const containerRef = shallowRef()
const options = [
{
value: '1',
label: 'javaScript'
},
{
value: '2',
label: 'Array<object>'
}
]
const expDtable = ref([])
const data = ref([
{
name: '',
type: '',
describe: '',
cekk: true,
id: 1
}
])
// 新增
const addUser = () => {
data.value.push({
name: '',
type: '',
describe: '',
cekk: true,
children: [],
id: getRandomSixDigitNumber()
})
}
const remove = (node, datas) => {
const parent = node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex(d => d.id === datas.id);
children.splice(index, 1)
}
const getRandomSixDigitNumber = () => {
// 生成一个介于0(包含)和1(不包含)之间的随机浮点数
let randomFloat = Math.random()
// 将这个浮点数放大到1000000(10^6)的范围内,并四舍五入到最近的整数
let randomInt = Math.floor(randomFloat * 1000000)
// 检查生成的数是否小于100000(六位数的最小值),如果是,则加上100000
// 确保生成的数是一个六位数
if (randomInt < 100000) {
randomInt += 100000
}
return randomInt
}
const childAdd = (node,value) => {
if (node.level == 3) {
return false
}
expDtable.value = [value.id]
value.children.push({
name: '',
type: '',
describe: '',
cekk: true,
id: getRandomSixDigitNumber(),
children: []
})
data.value = data.value
}
const defaultProps = {
children: 'children',
label: 'label',
}
const handleNodeClick = data => {
console.log(data)
}
5.最后就是css,主要代码实现在css部分,该项目使用scss,deep深度选择器使用如下方式,css代码如下
<style>
/* 鼠标浮动过的背景颜色 */
.el-tree-node__content:hover {
background: #eeeeee;
}
/* 鼠标点击时节点的背景颜色 */
.el-tree-node:focus>.el-tree-node__content {
background-color: #eeeeee !important;
color: node;
}
/* 鼠标失去焦点时节点背景的颜色 */
.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content {
background: #eeeeee;
}</style>
<style lang="scss" scoped>
::v-deep .el-input__wrapper {
border-radius: 10px;
}
::v-deep .el-select__wrapper {
border-radius: 10px;
}
.mytree {
width: 110%;
margin-left: -30px;
}
:deep(.mytree) {
.el-tree-node {
position: relative;
padding-left: 10px;
margin-top: 10px;
// height:50px;
background: none;
// margin-bottom: 10px;
}
.el-tree-node__children {
padding-left: 10px;
// height:100px;
// margin-top:10px;
}
.el-tree-node :last-child:before {
height: 38px;
}
.el-tree > .el-tree-node:before {
border-left: none;
}
.el-tree > .el-tree-node:after {
border-top: none;
}
.el-tree {
background: none;
}
.el-tree-node:before {
content: '';
left: -4px;
position: absolute;
right: auto;
border-width: 1px;
border-left: 1px dashed #1389bc;
bottom: 0px;
height: 100%;
top: -26px;
width: 1px;
}
.el-tree-node:after {
content: '';
left: -4px;
position: absolute;
right: auto;
border-width: 1px;
border-top: 1px dashed #1389bc;
height: 20px;
top: 12px;
width: 18px;
}
// .el-tree .el-tree-node__expand-icon.expanded {
// -webkit-transform: rotate(0deg);
// transform: rotate(0deg);
// }
.el-tree .el-icon-caret-right:before {
content: '\e723';
font-size: 16px;
color: #1389bc;
position: absolute;
left: -20px;
top: -8px;
}
.el-tree .el-tree-node__expand-icon.expanded.el-icon-caret-right:before {
content: '\e722';
font-size: 16px;
color: #1389bc;
position: absolute;
left: -20px;
top: -8px;
}
.el-tree-node__expand-icon.is-leaf:before {
content: '\e722';
font-size: 16px;
color: #1389bc;
position: absolute;
left: -20px;
top: -8px;
}
.el-tree-node__content > .el-tree-node__expand-icon {
padding: 0;
// padding:10px 0;
}
}
.start {
width: 100%;
// height: 400px;
background: #eeeeee;
margin: 0 auto;
border-radius: 5px;
.start-input {
font-weight: 700;
margin: 0 20px;
}
.table {
width: 90%;
margin: 0 auto;
.table-row {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #ccc;
}
.table-row-one {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.button {
margin: 0 20px;
}
}
</style>
完整代码
<template>
<div style="padding: 10px; width: 100%;">
<div class="start" style=" overflow: auto">
<div class="start-input">输入</div>
<div class="table">
<div class="table-row">
<div class="table-header" style="width: 18%">变量名</div>
<div class="table-header" style="width: 13%">变量类型</div>
<div class="table-header" style="width: 15%; text-align: center">描述</div>
<div class="table-header">是否必要</div>
<div class="table-header"></div>
<div class="table-header"></div>
</div>
<div>
<div class="table-row-one">
<!-- <div style="width: 20%">
<el-input v-model="input" placeholder="Please input" />
</div>
<div style="width: 25%">
<el-select v-model="value" placeholder="Select">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div style="width: 25%">
<el-input v-model="input1" placeholder="Please input" type="number" />
</div>
<div style="width: 25%; margin-right: -70px">
<el-checkbox type="checkbox" />
</div>
<div>
<span style="cursor: pointer">+</span>
</div>
<div>
<span style="cursor: pointer">-</span>
</div> -->
<div class="mytree">
<el-tree
:indent="0"
:data="data"
:props="defaultProps"
:expand-on-click-node="false"
:highlight-current="false"
node-key="id"
@node-click="handleNodeClick"
:default-expanded-keys="expDtable"
>
<template #default="{ node, data }">
<!-- {{node.level}} -->
<div class="custom-tree-node" style="display: flex; width: 100%">
<div :style="{'width': node.level == 1 ? '120px' : node.level == 2 ? '100px' : '80px'}">
<el-input v-model="data.name" placeholder="变量名" :disabled="data.id == 1" />
</div>
<div style="width: 100px; margin-left: 10px">
<el-select v-model="data.type" placeholder="Select" :disabled="data.id == 1">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div style="width: 120px; margin-left: 10px">
<el-input
v-model="data.describe"
placeholder="请输入用户变量用途"
type="number"
:disabled="data.id == 1"
/>
</div>
<div style="width: 50px; text-align: center; margin-left: 20px">
<el-checkbox type="checkbox" v-model="data.cekk" :disabled="data.id == 1" />
</div>
<div style="width: 40px; text-align: right">
<span style="cursor: pointer" v-if="data.type == '2' && data.boolean != 1" @click="childAdd(node,data)"
>+</span
>
</div>
<div style="width: 40px; text-align: right">
<span style="cursor: pointer" v-if="data.id != 1" @click="remove(node, data)">-</span>
</div>
</div>
</template>
</el-tree>
</div>
</div>
</div>
</div>
<div class="button">
<el-button
v-for="button in buttons"
@click="addUser()"
:key="button.text"
:type="button.type"
text
bg
style="margin-top: 30px"
>
{{ button.text }}
</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { computed, shallowRef,ref,onMounted } from 'vue';
const buttons = [{ type: 'primary', text: '+新增' }]
const input = ref('')
const input1 = ref('')
const value = ref('')
const options = [
{
value: '1',
label: 'javaScript'
},
{
value: '2',
label: 'Array<object>'
}
]
const expDtable = ref([])
const data = ref([
{
name: '',
type: '',
describe: '',
cekk: true,
id: 1
}
])
// 新增
const addUser = () => {
data.value.push({
name: '',
type: '',
describe: '',
cekk: true,
children: [],
id: getRandomSixDigitNumber()
})
}
const remove = (node, datas) => {
const parent = node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex(d => d.id === datas.id);
children.splice(index, 1)
// const parent = node.parent
// const children = parent.data.children || parent.data
// console.log(children)
// const id = children.filter(d => d.id === datas.id)
// if (id.length > 0) {
// console.log(id[0].id)
// const T = data.value.slice(id[0].id, 1)
// console.log(data.value)
// console.log(T)
// data.value = [...data.value]
// }
}
const getRandomSixDigitNumber = () => {
// 生成一个介于0(包含)和1(不包含)之间的随机浮点数
let randomFloat = Math.random()
// 将这个浮点数放大到1000000(10^6)的范围内,并四舍五入到最近的整数
let randomInt = Math.floor(randomFloat * 1000000)
// 检查生成的数是否小于100000(六位数的最小值),如果是,则加上100000
// 确保生成的数是一个六位数
if (randomInt < 100000) {
randomInt += 100000
}
return randomInt
}
const childAdd = (node,value) => {
if (node.level == 3) {
return false
}
expDtable.value = [value.id]
value.children.push({
name: '',
type: '',
describe: '',
cekk: true,
id: getRandomSixDigitNumber(),
children: []
})
data.value = data.value
}
const defaultProps = {
children: 'children',
label: 'label',
}
const handleNodeClick = data => {
console.log(data)
}
</script>
<style>
/* 鼠标浮动过的背景颜色 */
.el-tree-node__content:hover {
background: #eeeeee;
}
/* 鼠标点击时节点的背景颜色 */
.el-tree-node:focus>.el-tree-node__content {
background-color: #eeeeee !important;
color: node;
}
/* 鼠标失去焦点时节点背景的颜色 */
.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content {
background: #eeeeee;
}</style>
<style lang="scss" scoped>
::v-deep .el-input__wrapper {
border-radius: 10px;
}
::v-deep .el-select__wrapper {
border-radius: 10px;
}
.mytree {
width: 110%;
margin-left: -30px;
}
:deep(.mytree) {
.el-tree-node {
position: relative;
padding-left: 10px;
margin-top: 10px;
// height:50px;
background: none;
// margin-bottom: 10px;
}
.el-tree-node__children {
padding-left: 10px;
// height:100px;
// margin-top:10px;
}
.el-tree-node :last-child:before {
height: 38px;
}
.el-tree > .el-tree-node:before {
border-left: none;
}
.el-tree > .el-tree-node:after {
border-top: none;
}
.el-tree {
background: none;
}
.el-tree-node:before {
content: '';
left: -4px;
position: absolute;
right: auto;
border-width: 1px;
border-left: 1px dashed #1389bc;
bottom: 0px;
height: 100%;
top: -26px;
width: 1px;
}
.el-tree-node:after {
content: '';
left: -4px;
position: absolute;
right: auto;
border-width: 1px;
border-top: 1px dashed #1389bc;
height: 20px;
top: 12px;
width: 18px;
}
// .el-tree .el-tree-node__expand-icon.expanded {
// -webkit-transform: rotate(0deg);
// transform: rotate(0deg);
// }
.el-tree .el-icon-caret-right:before {
content: '\e723';
font-size: 16px;
color: #1389bc;
position: absolute;
left: -20px;
top: -8px;
}
.el-tree .el-tree-node__expand-icon.expanded.el-icon-caret-right:before {
content: '\e722';
font-size: 16px;
color: #1389bc;
position: absolute;
left: -20px;
top: -8px;
}
.el-tree-node__expand-icon.is-leaf:before {
content: '\e722';
font-size: 16px;
color: #1389bc;
position: absolute;
left: -20px;
top: -8px;
}
.el-tree-node__content > .el-tree-node__expand-icon {
padding: 0;
// padding:10px 0;
}
}
.start {
width: 100%;
// height: 400px;
background: #eeeeee;
margin: 0 auto;
border-radius: 5px;
.start-input {
font-weight: 700;
margin: 0 20px;
}
.table {
width: 90%;
margin: 0 auto;
.table-row {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #ccc;
}
.table-row-one {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.button {
margin: 0 20px;
}
}
</style>