递归树形组件 ,带添加修改删除功能,并且当前选中树颜色高亮
展示出来样例
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210126153825998.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FteV9kYW41MjA=,size_16,color_FFFFFF,t_70#pic_center)
子组件 封装树形组件
<template>
<table>
<tr>
<td :colspan="hasChild ? model.children.length * 2 : 1" :class="{extend: hasChild && model.extend}">
<div :class="{card:true,select:nodeParamsId===model.resId}">
<div class="title">{{model.resName}}</div>
<div class="body">
{{model.message}}
</div>
<div class="footer">
<a href="javascript:;" @click="$emit('on-add', model)">添加</a>
<a href="javascript:;" @click="$emit('on-update', model)" v-if="model.type!=='root'">修改</a>
<a href="javascript:;" @click="$emit('on-remove', model)" v-if="model.type!=='root'">删除</a>
</div>
</div>
<div class="extend_handle" v-if="hasChild" @click="toggleExtend()">{{model.extend?'展开': '隐藏'}}</div>
</td>
</tr>
<tr v-if="hasChild && model.extend">
<td v-for="(item, index) in model.children" :key="index" colspan="2" class="child">
<TreeChart :nodeParamsId="nodeParamsId" :model="item" @on-add="$emit('on-add', $event)" @on-update="$emit('on-update', $event)" @on-remove="$emit('on-remove', $event)" />
</td>
</tr>
</table>
</template>
<script>
export default {
name: 'TreeChart',
props: ['model','nodeParamsId'],
computed: {
hasChild(){
return this.model.children && this.model.children.length
}
},
methods: {
toggleExtend() {
this.model.extend = !this.model.extend
}
}
}
</script>
<style lang="less">
.select{
background: gold !important;
}
.card{
background: rgb(227, 236, 247);
border: 2px solid #ffffff;
border-radius: 5px;
margin: 0 auto;
width: 200px;
.title{
height: 18px;
padding: 10px 0;
font-size: 12px;
}
.body{
height: 100px;
background: #ffffff;
width: auto;
margin: 0 15px;
}
.footer{
display: flex;
margin: 5px 15px;
justify-content: space-around;
a{
font-size: 12px;
color: rgb(20, 126, 192);
text-decoration: none;
}
}
}
table{
border-collapse: separate!important;
border-spacing: 0!important;
td{
position: relative;
vertical-align: top;
padding:0 0 50px 0;
text-align: center;
&.extend{
&::after{
content: "";
position: absolute;
left: 50%;
bottom: 18px;
height: 30px;
border-left: 2px dashed rgb(159, 186, 202);
transform: translate3d(-1px, 0, 0);
}
}
&.child{
&::before{
content: "";
position: absolute;
left:50%;
bottom:100%;
height:15px;
border-left:2px dashed rgb(159, 186, 202);
transform: translate3d(-1px,0,0)
}
&::after{
content: "";
position: absolute;
left:0;
right:0;
top:-15px;
border-top:2px dashed rgb(159, 186, 202);
}
&:first-child:before,
&:last-child:before{
display: none;
}
&:first-child:after{
left:50%;
height:15px;
border:2px dashed;
border-color:rgb(159, 186, 202) transparent transparent rgb(159, 186, 202);
border-radius: 6px 0 0 0;
transform: translate3d(1px,0,0)
}
&:last-child:after{
right:50%;
height:15px;
border:2px dashed;
border-color:rgb(159, 186, 202) rgb(159, 186, 202) transparent transparent;
border-radius: 0 6px 0 0;
transform: translate3d(-1px,0,0)
}
&:first-child.child:last-child::after{
left:auto;
border-radius: 0;
border-color:transparent rgb(159, 186, 202) transparent transparent;
transform: translate3d(1px,0,0)
}
}
}
}
</style>
父组件引用
<template>
<div id="app">
<el-button type="text" @click="btn">添加message</el-button>
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%"
>
<el-form :model="form" class="demo-form-inline">
<el-form-item label="审批人" label-width="80px">
<el-input v-model="form.name" placeholder="审批人"></el-input>
</el-form-item>
<el-form-item label="活动区域" label-width="80px">
<el-select v-model="form.message" placeholder="活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="confirm(form)">确 定</el-button>
</span>
</el-dialog>
<TreeChart :model="tree" @on-add="add" @on-update="update" @on-remove="remove" :nodeParamsId="nodeParams.resId"/>
</div>
</template>
<script>
import TreeChart from '../components/TreeChart'
export default {
components: {
TreeChart
},
data(){
return {
tree:{
resId:1,
type:'root',
hasChild:['22'],
children:[],
resName:'全量客户',
message:'客户数',
extend:true,
},
id:2,
dialogVisible:false,
form:{
name:'',
message:""
},
isNullNode:false,
type:null,
nodeParams:{
resId:null,
parentId:null,
},
activeArr:[]
}
},
watch:{
type(newval){
console.log('type',newval)
}
},
methods:{
add(node){
if(this.isNullNode){
this.$message.warning('是空白节点,请先编辑')
return
}
this.type=1
const newNode = {
resName: '',
resId: this.id++,
message: '',
extend: true,
children: [],
parentId:node.resId,
type:'normal'
}
node.children.push(newNode)
this.isNullNode=true,
this.activeArr.push(newNode.resId)
this.nodeParams={
resId:newNode.resId,
parentId:newNode.parentId
}
},
update(node){
if(this.isNullNode){
this.$message.warning('请先完成节点编辑')
return
}
this.nodeParams={
resId:node.resId,
parentId:node.parentId
}
this.type=2
this.dialogVisible=true
},
remove(node){
if (node.type == 'root'){
this.$message.warning('根节点不能删除')
return
}
if(node.children.length>0){
this.$message.warning('该节点下有子节点,不可删除')
return
}
let ids=''
this.activeArr.splice(this.activeArr.indexOf(node.resId),1)
ids=this.activeArr[this.activeArr.length -1]
const deepSearch = (tree) => {
for (let i = tree.length - 1; i >= 0; i--) {
if(tree[i].resId == ids){
this.nodeParams={
resId:tree[i].resId,
parentId:tree[i].parentId
}
}
if (tree[i].resId == node.resId){
if(tree[i].message==''){
this.type=null
this.isNullNode=false
}
tree.splice(i, 1)
} else if(tree[i].children){
deepSearch(tree[i].children)
}
}
}
deepSearch(this.tree.children)
},
confirm(form){
if(this.type==null){
this.$message.warning('请在右侧添加节点')
return
}
const deepSearch = (tree) => {
if (tree.resId == this.nodeParams.resId){
tree.message=form.message
tree.resName=form.name
} else if(tree.children&&tree.children.length){
tree.children.forEach(el => {
deepSearch(el)
});
}
}
deepSearch(this.tree)
this.dialogVisible=false
this.isNullNode=false
this.type=2
},
btn(){
if(this.tree.children.length==0){
this.$message.warning('请添加节点')
return
}
if(this.type==null){
this.$message.warning('请添加节点')
return
}
this.dialogVisible=true
}
},
}
</script>
<style lang="less">
</style>