vue 实现树状流程图的CUD(新增~修改~删除)

vue 实现树状流程图的CUD(新增~修改~删除)效果图 实现原理 1 放弃 div 的 flex 布局 利用 table 可以更好地控制新增子节点的对齐 利用 before 和 after 实现虚线 不需要多余的 div 2 使用组件递归 利用子传父 e m i t 传 值

大家好,我是讯享网,很高兴认识大家。

效果图
在这里插入图片描述
讯享网
实现原理
1.放弃div的flex布局, 利用table可以更好地控制新增子节点的对齐,利用::before和::after实现虚线,不需要多余的div
2.使用组件递归,利用子传父 e m i t 传 值 , v − o n = " emit传值,v-on=" emitvon="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":"07fe2e8ce186bb6bcb8f4d6574", "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> 
小讯
上一篇 2025-04-08 14:12
下一篇 2025-03-02 08:19

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/123352.html