vue 实现树状流程图的CUD(新增~修改~删除)
效果图实现原理1.放弃div的flex布局, 利用table可以更好地控制新增子节点的对齐,利用::before和::after实现虚线,不需要多余的div2.使用组件递归,利用子传父emit传值,v−on="emit传值,v-on="emit传值,v−on="listeners"实现跨层级事件监听父组件.vue<template><div id="app"><Tre
效果图
实现原理
1.放弃div的flex布局, 利用table可以更好地控制新增子节点的对齐,利用::before和::after实现虚线,不需要多余的div
2.使用组件递归,利用子传父
e
m
i
t
传
值
,
v
−
o
n
=
"
emit传值,v-on="
emit传值,v−on="listeners"实现跨层级事件监听
父组件.vue
<template>
<div id="app">
<TreeChart :model="tree" @on-add="add" @on-update="update" @on-remove="remove"/>
</div>
</template>
<script>
/**
* 使用方式
* <TreeChart :model="data" >
* data 参数格式为树形结构
*
* {
* resName: "xxx",
* extend": true, 是否展开
* children: [{
* resName: "xxx",
* children: []
* }]
* }
*/
import TreeChart from './components/TreeChart'
const dataTree= {
"resId":"root",
"resName":"跟节点",
"extend": true,
"children": [{
"resId":"07fe2e8c976047e186bb6bcb8f4d6574",
"resName":"跟节点1",
"extend": true,
"children": []
}]
}
export default {
data() {
return {
tree: dataTree
}
},
components: {
TreeChart
},
methods:{
// 添加
add: function(node){
const newNode = {
resName: '222',
resId: new Date().getTime(),
message: '',
extend: true,
children: []
}
node.children.push(newNode)
},
// 修改
update: function(node){
node.resName = new Date().getTime()
},
// 删除
remove: function(node){
if (node.resId == 'root'){
alert('跟节点不能删除')
return console.log('跟节点不能删除')
}
const deepSearch = (tree) => {
for (let i = tree.length - 1; i >= 0; i--) {
if (tree[i].resId == node.resId){
console.log(tree[i])
tree.splice(i, 1)
} else if(tree[i].children){
deepSearch(tree[i].children)
}
}
}
deepSearch(this.tree.children)
}
},
}
</script>
<style lang="scss">
*{
padding: 0;
margin: 0;
#app{
height: 100vh;
width: 100vw;
}
}
</style>
递归组件TreeChart.vue
<template>
<table>
<tr>
<td
:colspan="hasChild ? model.children.length * 2 : 1"
:class="{ extend: hasChild && model.extend }"
>
<div class="card">
<div class="title">{{ model.resName }}</div>
<div class="body">{{ model.message }}</div>
<div class="footer">
<div @click="$emit('on-add', model)">添加</div>
<div @click="$emit('on-update', model)">修改</div>
<div @click="$emit('on-remove', model)">删除</div>
</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"
>
<!--跨层级监听事件 v-on="$listeners"(.native原生事件无效) -->
<TreeChart :model="item" v-on="$listeners"/>
</td>
</tr>
</table>
</template>
<script>
export default {
name: 'TreeChart',
props: ['model'],
computed: {
hasChild () {
return this.model.children && this.model.children.length
}
},
methods: {
toggleExtend () {
this.model.extend = !this.model.extend
}
}
}
</script>
<style lang="scss">
.card {
background: rgb(227, 236, 247);
border: 2px solid #ffffff;
border-radius: 5px;
margin: 0 auto;
width: 200px;
.title {
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-between;
div {
font-size: 12px;
color: rgb(20, 126, 192);
cursor: pointer;
}
}
}
.extend_handle {
cursor: pointer;
}
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>
更多推荐
所有评论(0)