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

效果图
在这里插入图片描述
实现原理
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":"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>
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: Vue是一种现代化的JavaScript框架,可以用于构建用户界面。要实现绘制流程图的功能,可以借助Vue的强大功能和生态系统。 首先,需要选择一个适合绘制流程图的第三方库。常用的有mxGraph、GoJS和JointJS等。这些库提供了丰富的绘图工具和API,可以帮助我们快速实现绘制流程图的功能。 在Vue项目中,可以使用npm或yarn等包管理工具安装所选择的第三方库。然后,在组件中引入相关库文件,并使用相应的API方法来创建流程图。 在Vue组件中,可以定义一个Canvas或Div元素作为绘制流程图的容器。通过调用第三方库的方法,可以在容器内创建节点、连线等图形元素,然后通过事件监听来处理用户的交互操作。 为了能够让用户自由操作和修改流程图,可以使用Vue的双向绑定功能,将图形元素的位置、形状等属性与Vue组件中的数据进行绑定。这样,当用户拖动节点或调整连线时,数据会自动更新,从而实现图形的即时更新。 此外,可以使用Vue的计算属性来处理复杂的图形逻辑,例如判断节点之间的连线是否符合某些条件,以及根据用户的选择动态生成节点等。 最后,为了提高用户体验,可以使用Vue的过渡效果和动画来实现平滑的节点拖动、连线过渡等效果,让用户能够更直观地理解和操作流程图。 总之,通过利用Vue提供的强大功能和第三方库的支持,我们能够相对轻松地实现绘制流程图的功能,从而为用户提供一个友好和灵活的图形化界面。 ### 回答2: Vue.js是一个流行的JavaScript框架,可用于构建用户界面。要实现绘制流程图的功能,我们可以使用Vue.js的一些核心概念和功能来实现。 首先,我们可以利用Vue.js的组件化开发方式来构建流程图的各个组件。每个组件可以包含特定的功能,例如一个节点组件、一个箭头组件等等。通过将这些组件组合起来,我们可以构建出一个完整的流程图。 其次,我们可以使用Vue.js的数据驱动视图的特性来将流程图数据与视图进行绑定。这意味着我们可以定义一个流程图数据对象,其中包含节点的坐标、连接的关系等信息。然后,我们可以将这个数据对象传递给流程图组件,并通过Vue.js的数据绑定将数据与视图进行关联。这样,当我们修改流程图数据时,视图会自动更新。 此外,Vue.js还提供了一些生命周期钩子函数和观察者模式,可以帮助我们实现流程图的一些特定功能。例如,当一个节点被点击时,我们可以通过生命周期钩子函数来触发特定的事件处理逻辑。或者使用观察者模式来监听数据的变化,从而实现一些自定义的逻辑。 最后,我们还可以利用Vue.js的动态组件功能来实现流程图编辑功能。通过动态组件,我们可以根据用户的操作,动态地添加、删除修改节点和连接关系。并且,我们可以使用Vue.js的动画功能来实现一些视觉效果,例如节点拖拽或连接箭头的绘制过程。 综上所述,通过利用Vue.js的组件化开发、数据驱动视图、生命周期钩子函数、观察者模式和动态组件等特性,我们可以实现一个功能完备的流程图绘制工具。 ### 回答3: Vue可以通过使用图形库(如D3.js、jsPlumb等)来实现绘制流程图的功能。下面是一个简单的示例: 1. 首先,在Vue组件中引入所需的图形库,可以通过npm安装或者CDN引入。 2. 在Vue的data选项中定义流程图的数据结构,包括节点、连接和样式等。 3. 在Vue的template中使用HTML元素来展示流程图的容器。 4. 在Vue的mounted钩子中,通过图形库的API来实现流程图的绘制。首先获取到流程图的容器元素,然后根据数据结构,循环创建节点和连接,并添加到容器中。 5. 在Vue的methods中定义操作流程图的方法,如添加节点、删除节点、修改节点样式等。 6. 在Vue的template中使用事件绑定来调用方法,实现流程图的交互操作。 7. 最后,在Vue的样式中定义流程图的样式,使其更加美观。 通过以上步骤,我们可以在Vue实现绘制流程图的功能。需要注意的是,具体的实现方式会依赖所选用的图形库,不同图形库的API和使用方式可能会有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值