需求:vue用流程图展示数据

2023-11-03

问题描述:如标题所示(粗略的写了一版,没有细化)
UI
在这里插入图片描述

红框的地方本来想用canvas自己写,但是找资料的时候发现了一个插件LeaderLine,非常符合要求,然后发现了一篇文章vue横向树级组件(流程图、组件递归)套用了一下,然后按照自己的需求修改了一下。
注意点
1.弹窗显示的数据,所以有一个层级显示,需要把svg的z-index的值写大一点
2. 数据多的时候,弹窗会显示滚动条,这个时候,线条会跟着滚动条移动,需要调用postion()方法,重新定位一下
3. 需求里还有一个节点下展示的数据,这个图是用css画的,可以收起或者开始,点击的时候,线条也是会乱的,所以手动触发resize事件
解决方法:
安装插件:npm i leader-line-vue

package.json
“leader-line-vue”: “^2.1.1”

child.vue

<template>
    <div v-loading="loading">
        <right-tree
            v-if="list && list.length"
            :list="list"
        ></right-tree>
    </div>
</template>
<script>
import RightTree from './RightTree'

export default {
    components: {
        RightTree,
    },
    data() {
        return {
            list: [],
            flag: true,
            
            
        }
    },
    watch: {},
    methods: {
        /**
         * 获取列表数据
         */
        async getNodeList(flag) {
            this.loading = true
            try {
                this.list.splice(0)
                
                setTimeout(() => {
                    if (flag) {
                        this.list = [
                            {
                                id: '1',
                                name: '标题',
                                checked: true,
                                children: [
                                    {
                                        id: '1-1',
                                        name: '标题',
                                        checked: true,
                                        child: [
                                            {
                                                name: '1:1'
                                            }, {
                                                name: '1:2'
                                            }
                                        ]
                                    },
                                    {
                                        id: '1-2',
                                        name: '标题',
                                        checked: false,
                                        
                                    },
                                    {
                                        id: '1-3',
                                        name: '标题',
                                        checked: true,
                                        child: [
                                            {
                                                name: '1:1'
                                            }, {
                                                name: '1:1'
                                            }, {
                                                name: '1:2'
                                            }
                                        ]
                                    },
                                    {
                                        id: '1-4',
                                        name: '点击更多',
                                        checked: false,
                                    }
                                ],
                            },
                        ]
                    } else {
                        this.list = [
                            {
                                id: '1',
                                name: '标题',
                                checked: true,
                                children: [
                                    {
                                        id: '1-1',
                                        name: '标题',
                                        checked: true,
                                        child: [
                                            {
                                                name: '1:1'
                                            }, {
                                                name: '1:2'
                                            }
                                        ]
                                    },
                                    {
                                        id: '1-2',
                                        name: '标题',
                                        checked: false,
                                        
                                    },
                                    {
                                        id: '1-3',
                                        name: '标题',
                                        checked: true,
                                        child: [
                                            {
                                                name: '1:1'
                                            }, {
                                                name: '1:1'
                                            }, {
                                                name: '1:2'
                                            }
                                        ]
                                    },
                                    {
                                        id: '1-4',
                                        name: '标题',
                                        checked: true,
                                        child: [
                                            {
                                                name: '1:1'
                                            }, {
                                                name: '1:1'
                                            }, {
                                                name: '1:2'
                                            }
                                        ]
                                    },
                                    {
                                        id: '1-5',
                                        name: '标题',
                                        checked: true,
                                        child: [
                                            {
                                                name: '1:1'
                                            }, {
                                                name: '1:1'
                                            }, {
                                                name: '1:2'
                                            }
                                        ]
                                    }
                                ],
                            },
                        ]
                    }
                    
                    
                }, 1000)
            } catch (e) {
                console.log('e', e)
            }
            this.loading = false
        },
    },
    mounted() {
        this.getNodeList(this.flag)
        this.$eventBus.$on("changeData", value => {
            this.getNodeList(value)
        })
    },
    created() {
    
    }
    
}
</script>

RightTree.vue

<template>
    <div
        class="FaultRegion"
    >
        <div class="fault_content ">
            <div
                class="child"
                v-for="(dataItem,index) in list"
                :key="dataItem.id +'-child-'+index"
            >
                <div
                    class="column"
                    :style="{marginRight: dataItem.children && dataItem.children.length > 1 ? '20px' :''}"
                >
                    <div
                        class="column_name"
                        :id="dataItem"
                        :style="dataItem.children&& dataItem.children.length?'justify-content: center;':''"
                    >
                        <div
                            class="column_box"
                            :class="dataItem.children&& dataItem.children.length?'father':'child'"
                            :ref="dataItem.id"
                            :id="dataItem.id"
                            style="width:110px"
                        >
                            <!-- 集群or节点的名称-->
                            <div class="name">
                                <!--集群-->
                                <div v-if="dataItem.children&& dataItem.children.length" style="display: flex">
                                    <div class="father_title">{{ dataItem.name }}</div>
                                </div>
                                <!--节点-->
                                <div v-else :class="dataItem.checked?'active':'noActive'">
                                    <div class="line" v-if="!dataItem.children"></div>
                                    <div class="child_title">{{ dataItem.name }}</div>
                                </div>
                                <p class="icon" @click="iconClcik(dataItem)" :class="dataItem.name==='点击更多'?'more':''"
                                   style="margin-left:10px;">
                                    <i :class="dataItem.checked?'el-icon-minus':'el-icon-plus'"
                                       v-if="dataItem.name!='点击更多'"></i>
                                    <i v-else class="el-icon-d-arrow-right"></i>
                                </p>
                            </div>
                        </div>
                    </div>

                    <!--     节点的下一级              -->
                    <div v-if="dataItem.name !='集群'">
                        <div class="child_list" v-show="dataItem.checked">
                            <div class="child_icon" v-show="dataItem.checked &&dataItem.child && dataItem.child.length">
                                <div class="child_line"></div>
                                <div class="child_brackets"></div>
                            </div>
                            <div class="child_content">
                                <div v-for="(item,index) in dataItem.child" class="child_list_row">
                                    <div class="child_circle"></div>
                                    {{ item.name }}
                                </div>
                            </div>
                        </div>
                    
                    </div>
                </div>
                <!-- 递归组件展示子节点 -->
                <div
                    class="node_list"
                    v-if="dataItem.children && dataItem.children.length && dataItem.checked"
                >
                    <RightTree
                        :list="dataItem.children"
                    />
                </div>
            
            </div>
        </div>
    
    </div>
</template>

<script>
import LeaderLine from 'leader-line-vue'

export default {
    name: 'RightTree',
    components: {},
    data() {
        return {
            lines: [],
        }
    },
    props: {
        list: {
            type: Array,
            default: () => [],
        },
    },
    mounted() {
        this.$nextTick(() => {
            this.drawLeaderLine(this.list)
        })
         // 检测滚动事件
        const dom = document.getElementsByClassName('f_con')[0]
        if (dom) {
            dom.onscroll = () => {
                this.drawLine()
                this.doResize();
            }
        }
        
    },
    
    beforeDestroy() {
        /**
         * 离开页面时销毁所有line
         */
        if (this.lines && this.lines.length) {
            this.lines.forEach(line => {
                line.remove()
            })
        }
    },
    methods: {
        
        /**
         * 销毁所有线条
         */
        destoryLine() {
            if (this.lines && this.lines.length) {
                this.lines.forEach(line => {
                    line.remove()
                })
            }
        },
        /**
         * 根据上下级关系绘制线条
         */
        drawLeaderLine(list) {
            this.lines.splice(0)
            list.forEach(element => {
                let start = document.getElementById(element.id)
                if (element.children && element.children.length) {
                    element.children.forEach(child => {
                        let line = LeaderLine.setLine(start, document.getElementById(child.id))
                        line.color = '#1890ff'
                        line.size = 2
                        line.setOptions({
                            solid: {animation: true},
                        })
                        this.lines.push(line)
                    })
                }
            })
        },
        /**
         * icon点击
         */
        iconClcik(dataItem) {
            dataItem.checked = !dataItem.checked
            if (dataItem.name === '点击更多') {
                if (dataItem.checked) {
                    this.$eventBus.$emit('changeData', false)
                } else {
                    this.$eventBus.$emit('changeData', true)
                }
            } else {
                //  集群
                if (dataItem.children && dataItem.children.length) {
                    if (dataItem.checked) {
                        this.$nextTick(() => { // 划线
                            this.drawLeaderLine(this.list)
                        })
                    } else {
                        this.destoryLine() // 清除线
                    }
                } else {// 子节点
                    this.doResize();
                }
            }
            
            
        },
        /**
         * 手动触发resize事件
         */
        doResize() {
            setTimeout(function () {
                //手动触发窗口resize事件
                if (document.createEvent) {
                    var event = document.createEvent("HTMLEvents");
                    event.initEvent("resize", true, true);
                    window.dispatchEvent(event);
                } else if (document.createEventObject) {
                    window.fireEvent("onresize");
                }
            }, 100);
        },
        /**
         * 渲染线条
         */
        drawLine() {
            if (this.lines && this.lines.length) {
                this.lines.forEach(line => {
                    line.position()
                })
            }
        },
    },
}
</script>

<style lang="scss" scoped>
.FaultRegion {
    .fault_content {
        margin-top: 20px;
        
        .child {
            display: flex;
            background-color: #fff;
            
            .column {
                display: flex;
                align-items: center;
                margin: 10px 0;
                
                .column_name {
                    cursor: pointer;
                    height: 100%;
                    display: flex;
                    align-items: center;
                    width: 180px;
                    text-align: center;
                    justify-content: end;
                    position: relative;
                    padding: 10px 0;
                    //background-color: red;
                    
                    .column_box {
                        text-align: left;
                        width: 32px;
                        font-size: 16px;
                        font-family: MicrosoftYaHei;
                        color: #333333;
                        display: flex;
                        justify-content: end;
                        
                        .name {
                            display: flex;
                            justify-content: end;
                            align-items: center;
                            font-family: MicrosoftYaHei;
                            color: #333333;
                            
                            .line {
                                width: 2px;
                                height: 14px;
                                background: #E05E5E;
                                margin-right: 5px;
                                
                            }
                            
                            .father_title {
                                font-size: 15px;
                                max-width: 56px;
                                overflow: hidden;
                                white-space: nowrap;
                                text-overflow: ellipsis;
                            }
                            
                            .child_title {
                                font-size: 14px;
                                width: 56px;
                                overflow: hidden;
                                white-space: nowrap;
                                text-overflow: ellipsis;
                            }
                            
                            .noActive {
                                padding: 10px;
                                display: flex;
                            }
                            
                            .active {
                                display: flex;
                                justify-content: center;
                                align-items: center;
                                padding: 10px;
                                height: 33px;
                                background: rgba(223, 239, 255, 0.7);
                                border-radius: 4px;
                                border: 1px solid #64A9EF;
                            }
                        }
                        
                        .icon {
                            width: 14px;
                            height: 14px;
                            border-radius: 2px;
                            border: 1px solid #D4D4D4;
                            color: #D4D4D4;
                            display: flex;
                            align-items: center;
                            justify-content: center;
                            cursor: pointer;
                            //margin-left: 30px;
                            //margin-right: 60px;
                            
                            i {
                                font-size: 4px;
                            }
                        }
                        
                        .more {
                            border: none;
                            
                            i {
                                transform: rotate(90deg);
                            }
                        }
                    }
                    
                    .father {
                        display: flex;
                        justify-content: end;
                        align-items: center;
                    }
                    
                }
            }
            
            .node_list {
                display: flex;
                flex-direction: column;
                justify-content: center;
            }
            
            .child_list {
                display: flex;
                
                .child_icon {
                    display: flex;
                    flex-direction: row;
                    justify-content: center;
                    align-items: center;
                    position: relative;
                    
                    .child_line {
                        width: 45px;
                        height: 2px;
                        background-color: #1B70CA;
                    }
                    
                    .child_brackets {
                        width: 2px;
                        height: 100%;
                        background: #1B70CA;
                    }
                    
                    &::before {
                        content: "";
                        width: 2px;
                        height: 7px;
                        position: absolute;
                        right: -2px;
                        bottom: -5px;
                        background: #1B70CA;
                        transform: rotate(-45deg);
                    }
                    
                    &::after {
                        content: "";
                        width: 2px;
                        height: 7px;
                        position: absolute;
                        right: -2px;
                        top: -5px;
                        background: #1B70CA;
                        transform: rotate(45deg);
                    }
                }
                
                .child_content {
                    display: flex;
                    flex-direction: column;
                    
                    
                    .child_list_row {
                        display: flex;
                        align-items: center;
                        margin-left: 10px;
                        margin-bottom: 10px;
                        
                        .child_circle {
                            width: 4px;
                            height: 4px;
                            background: #A7D2FF;
                            border-radius: 50%;
                            margin-right: 10px;
                        }
                    }
                    
                }
                
                .child_content :last-child {
                    margin-bottom: 0;
                }
            }
        }
        
        
    }
}
</style>

father.vue

<template>
    <div class="box FaultRegion">
      
        <div class="con">
            <div class="row">
                <div class="label">标题:</div>
                <div class="value" @click="FaultRegionShow = true">点击我,显示弹窗</div>
            </div>
          
        <Modal :show.sync="FaultRegionShow" title="标题" class="faultRegionModal" :hideBottom=false>
            <div class="menu">
                <div title="缩小" class="minus">
                    <i class="el-icon-minus"></i>
                </div>
                <div title="放大" class="plus">
                    <i class="el-icon-rank"></i>
                </div>
                <div title="刷新" class="refresh">
                    <i class="el-icon-refresh"></i>
                </div>
            </div>
              <div class="f_con">
               
                <Test/>
            </div>
        
        </Modal>
    </div>
</template>

<script>

import Modal from "@/components/XcdataModal/XcdataModal";
import Test from "views/systemConfig/SystemConfig/Test/child";

export default {
    name: "index",
    data() {
        return {
            FaultRegionShow: false,
        }
        
    },
    components: {
        Modal,
        Test
    },
  
}
</script>

<style scoped lang="scss">
.FaultRegion {
    .con {
        .row {
            display: flex;
            align-items: center;
            font-size: 14px;
            font-family: MicrosoftYaHei;
            margin-bottom: 38px;
            
            .label {
                padding: 0 12px 0 0;
                width: 160px;
                text-align: right;
            }
            
            .value {
                color: var(--primary-color);
                cursor: pointer;
                display: flex;
                flex-direction: row;
                
                .value_box {
                    height: 34px;
                    border-radius: 2px;
                    border: 1px solid #1B70CA;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    margin-right: 10px;
                    color: #333333;
                    font-size: 14px;
                    font-family: MicrosoftYaHei;
                    padding: 10px 8px;
                    position: relative;
                    cursor: pointer;
                }
                
                .checked {
                    color: #fff;
                    border-style: solid;
                    border-width: 0px 0px 18px 17px;
                    border-color: transparent transparent var(--primary-color) transparent;
                    position: absolute;
                    bottom: 0;
                    right: 0;
                }
                
                .checked::after {
                    content: "";
                    width: 4px;
                    height: 8px;
                    border-color: #fff;
                    border-style: solid;
                    border-width: 0 1px 1px 0;
                    transform: rotate(45deg);
                    position: absolute;
                    bottom: -16px;
                    right: 3px;
                }
                
                .active {
                    background: rgba(27, 112, 202, 0.11);
                }
                
            }
        }
        
        & > div:nth-child(3) {
            margin-bottom: 18px;
        }
    }
    
    
}
</style>

<style lang="scss">
.faultRegionModal {
    .modal {
        width: 622px;
        height: 477px;
        
        .con_wrap {
            display: flex;
            flex-direction: column;
            
            .menu {
                display: flex;
                justify-content: end;
                margin-top: 10px;
                margin-right: 20px;
                
                .minus, .plus, .refresh, {
                    width: 16px;
                    height: 16px;
                    background: #EFEFEF;
                    border-radius: 2px;
                    margin-left: 10px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    cursor: pointer;
                    
                    i {
                        font-size: 6px;
                        color: var(--primary-color);
                    }
                }
            }
            
            .f_con {
                height: 400px;
                overflow-y: auto;
            }
            
        }
        
    }
}
</style>
<style lang="scss">
.leader-line {
    z-index: 999999;
}
</style>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

需求:vue用流程图展示数据 的相关文章

随机推荐

  • IDEA插件Free Mybatis Plugin使用心得

    目录 问题现象 问题分析 问题现象 今天在项目组长的推荐下 我在IDEA上安装了Free Mybatis Plugin插件 怎么安装我就不说了 很简单的 网上也有很多资料 这里我提一下我的一些使用心得 首先看它的介绍 其实里面唯一吸引到我的
  • 部署无线覆盖,安装无线网桥设备要注意的问题

    互联网产品和设备不断更新和迭代 以适应实际的发展 随着无线覆盖范围的发展 无线网桥产品也在升级以满足更好的需求 显然 新的无线网桥设备对安装的要求也越来越高 虽然无线网桥安装看起来很简单 但您只需将设备安装到正确的位置即可 但是 要使无线网
  • 分布式调度 Elastic-job

    分布式调度 Elastic job 1 概述 1 1什么是任务调度 我们可以思考一下下面业务场景的解决方案 某电商平台需要每天上午10点 下午3点 晚上8点发放一批优惠券 某银行系统需要在信用卡到期还款日的前三天进行短信提醒 某财务系统需要
  • Cookie的简单使用

    在JSP中 使用cookie 有以下几个步骤 1 使用page指令导入类javax servlet http cookie 2 创建Cookie对象 Cookie newCookie new Cookie String key Object
  • vue html实体空格无效

    空格类型 当第一列空格不能用时试试第二列 空格分为 两种 普通文本空格和html实体空格 普通文本空格 unicode 正则 描述 全角 中文空格键 u3000 中文网页上常会出现 半角 英文空格键 u0020 s 最常见 写代码 html
  • liquibase报错 waiting for changelog lock

    今天项目启动控制台突然卡住 liquibase一直在打印 waiting for changelog lock 这可能是由于一个被杀死的liquibase进程未在DATABASECHANGELOGLOCK表上释放其锁定 通过以下方法解决 查
  • Essential Google Cloud Infrastructure: Foundation

    最后更新2022 03 08 有点事情 中断了几天 继续GCP GCP Fundamental看完了 但是lab还没做 翻墙越脊的 太麻烦 过些时候方便了一起练习 继续学习下一课 essential系列其实是再走一遍fundamentals
  • python21天打卡Day10-string和bytes互转

    a 21 python b a encode utf 8 string转为bytes print format b type b c b 21 python d c decode utf 8 print format d type d D
  • Gstreamer推送摄像头数据到RTMP服务器的方法(SRS成功示例)

    最近在研究如何将Linux中的视频数据推送到流媒体服务器 看到gstreamer还比较不错 于是试了一下 服务端用的SRS RTMP推流 搭建非常简单 教程可参考 https blog csdn net qq 52514123 articl
  • sort根据结构体中某一元素进行排序

    先看一下简单的sort全排序 int a 100 for int i 1 i lt 10 i scanf d a i sort a a 10 OK 排完了 但是 想根据结构体的一个元素 对结构体数组排序 看完下面例题 多思考 例题 FatM
  • CoordinatorLayout 的滑动监听--自定义

    public abstract static class AppBarStateChangeListener implements AppBarLayout OnOffsetChangedListener public enum State
  • Nginx实战练习

    1 Nginx安装 以centos7为例 详解博文 Nginx安装搭建之源码方式 Centos7 centos7源码安装nginx IT之一小佬的博客 CSDN博客 2 简单搭建站点 2 1 单个站点搭建 正常开放情况下 开发代码防止网站的
  • require() of ES modules is not supported.

    问题 如图所示 看了一些答案是版本问题 解决办法其其实提示已经有了 use import 找到提示的文件 require改为import 问题即可解决
  • 前端如何接接口

    前端一般静态页面写完后 就要从后端获取数据了 就要进行接接口 接接口其实说白了就是发送网络请求 从后端获取数据 然后再将数据渲染到页面上 今天就以一个简单的uniapp项目为例 介绍一下接口怎么写 首先 是封装一个request js文件
  • rockchip rk3368(px5)车载开发之路6,系统开机bootanimation播放视频需求

    本系列记载作者来到一个新的车载后装市场小公司 负责从新开始维护一套代码的心路过程 系统使用瑞芯微的rk3368芯片 版本是PX5 Android 8 0 release 20180726 从无到有的每个patch修改以及思考 其中着重点是驱
  • PyTorch知识点总结100问

    PyTorch知识点总结 什么是PyTorch 它有什么特点和优势 PyTorch中的张量 Tensor 是什么 它与NumPy中的数组有何区别 请介绍一下PyTorch的执行流程 PyTorch中的autograd是什么 它有什么作用 请
  • Salesforce中国区解散,谁是替代的最佳选择?

    摘要 全球第一大CRM厂商退出 对中国市场有何影响 8月3日 Salesforce中国区解散的消息 在IT业界引发热议 虽然是全球第一大CRM厂商 但Salesforce在中国区业务不多 整个团队只有60 70人规模 主要业务是全球500强
  • 分布式系统消息通信技术:MOM与RPC

    一 中间件 什么是中间件 中间件 Middleware 是处于操作系统和应用程序之间的软件 也有人认为它应该属于操作系统中的一部分 人们在使用中间件时 往往是一组中间件集成在一起 构成一个平台 包括开发平台和运行平台 但在这组中间件中必须要
  • ifconfig命令无法识别,提示“Command 'ifconfig' is available in '/sbin/ifconfig'”

    有台虚拟机 用的时候发现ifconfig命令不好用了 提示如下 Command ifconfig is available in sbin ifconfig The command could not be located because
  • 需求:vue用流程图展示数据

    问题描述 如标题所示 粗略的写了一版 没有细化 UI 红框的地方本来想用canvas自己写 但是找资料的时候发现了一个插件LeaderLine 非常符合要求 然后发现了一篇文章vue横向树级组件 流程图 组件递归 套用了一下 然后按照自己的