Vue实现流程图,借鉴vue-tree-color 实现流程框架技术
创始人
2024-03-03 20:21:15
0

Vue实现流程图,借鉴vue-tree-color 实现流程框架技术

文章目录

  • Vue实现流程图,借鉴vue-tree-color 实现流程框架技术
    • 借鉴鸣谢
    • 演示效果
    • 引入依赖
    • 添加全局
    • 组件的二次封装
      • 步骤1 创建组件目录
        • Vue
        • node.js
        • tree.less
    • 使用
      • 组件引入使用
      • 数据结构案例

借鉴鸣谢

实现组织架构图(vue-org-tree)
如果向使用原来的依赖可以使用这个人的,因为我也是根据这个博客大佬仿照Vue-org-tree实现的方案
对此有几点不惑,问了大佬,大佬也没有回复我

  • className 貌似不起作用,看了文章底部,她也意识到这个问题,但是没有给出详细的解决方案
  • node.js中虽然做了充分的注释,但是她把子节点渲染和主节点渲染给单独分开了,指定了render函数去渲染

演示效果

在这里插入图片描述
由于还在启动项目中,还没有完善,目前已经可以支持动态创建节点了
在这里插入图片描述
这是通过点击实现抽屉展示
在这里插入图片描述
这是通过hover鼠标悬停高亮,由于我并不是一个正儿八经的前端,准确的说我是来搞笑的。所以对于每个节点面板渲染是很简陋的。

引入依赖

# 这里是安装大佬提供的依赖
npm install vue-tree-color

检查less和less-loader,因为该组件使用到了less,可以看看项目工程是否已经安装

npm install --save-dev less less-loader

注意这里可能会在项目启动的时候出现以下问题

报错信息:Syntax Error: TypeError: this.getOptions is not a function

解决方案-需要在安装less和lessloader时,指定版本号,否则就会导致兼容问题。

npm i less@3.9.0 less-loader@4.1.0 -D

添加全局

找到main.js中追加一下内容

import Vue2OrgTree from 'vue-tree-color'
Vue.use(Vue2OrgTree)

组件的二次封装

在公共层面@components 目录下,我们需要进行二次封装,为什么要二次封装,上面已经说到原因了,因为定制化内容不同, 肯定会涉及更改组件渲染方式以及样式,因为二次封装是非常有必要的
在这里插入图片描述

步骤1 创建组件目录

我就随便给取了一个名字 SimpleTree 目录

Vue

组件页面,我没做更改,直接拿来用



node.js

这个js就是组件渲染的函数,可以稍微研究一下

// 判断是否叶子节点
const isLeaf = (data, prop) => {return !(Array.isArray(data[prop]) && data[prop].length > 0)
}
// 创建 node 节点
export const renderNode = (h, data, context) => {const { props } = contextconst cls = ['org-tree-node']const childNodes = []const children = data[props.props.children]if (isLeaf(data, props.props.children)) {cls.push('is-leaf')} else if (props.collapsable && !data[props.props.expand]) {cls.push('collapsed')}if (data) {childNodes.push(renderLabel(h, data, context))}if ((!props.collapsable || data[props.props.expand]) && children.length > 0) {childNodes.push(renderChildren(h, children, context))}return h('div', {domProps: {className: cls.join(' ')}}, childNodes)
}// 创建展开折叠按钮
export const renderBtn = (h, data, { props, listeners }) => {const expandHandler = listeners['on-expand']let cls = ['org-tree-node-btn']if (data[props.props.expand]) {cls.push('expanded')}return h('span', {domProps: {className: cls.join(' ')},on: {click: e => expandHandler && expandHandler(e,data)}})
}// 创建 label 节点
export const renderLabel = (h, data, context) => {const { props, listeners } = contextconst label = data[props.props.label]const renderContent = props.renderContent// event handlersconst clickHandler = listeners['on-node-click']const mouseOverHandler = listeners['on-node-mouseover']const mouseOutHandler = listeners['on-node-mouseout']const childNodes = []if (typeof renderContent === 'function') {let vnode = renderContent(h, data)vnode && childNodes.push(vnode)} else {childNodes.push(label)}if (props.collapsable && !isLeaf(data, props.props.children)) {childNodes.push(renderBtn(h, data, context))}const cls = ['org-tree-node-label-inner']let { labelWidth, labelClassName, selectedClassName, selectedKey ,judge,NodeClass} = propsif (typeof labelWidth === 'number') {labelWidth += 'px'}if (typeof labelClassName === 'function') {labelClassName = labelClassName(data)}labelClassName && cls.push(labelClassName)// add selected class and key from propsif (typeof selectedClassName === 'function') {selectedClassName = selectedClassName(data)}selectedClassName && selectedKey && data[selectedKey] && cls.push(selectedClassName)return h('div', {domProps: {className: 'org-tree-node-label'}}, [h('div', {domProps: {className:ChangeTheColor(data,judge,NodeClass) + " org-tree-node-label-inner"},style: { width: labelWidth },on: {'click': e => clickHandler && clickHandler(e, data),'mouseover': e => mouseOverHandler && mouseOverHandler(e, data),'mouseout': e => mouseOutHandler && mouseOutHandler(e, data)}}, childNodes)])
}function ChangeTheColor(e,judge,NodeClass){if(judge !== "" && judge !== undefined && judge !== null && judge.swtich !== false){for(var k in judge) {var a = (eval("e."+k))if(NodeClass){for(let c =0 ;cif( a === NodeClass[c])return  NodeClass[c]else if(NodeClass.length-1==c)return ""}}else{return ""}}}else{return ""}
}
// 创建 node 子节点
export const renderChildren = (h, list, context) => {if (Array.isArray(list) && list.length > 0) {const children = list.map(item => {return renderNode(h, item, context)})return h('div', {domProps: {className: 'org-tree-node-children'}}, children)}return ''
}export const render = (h, context) => {const {props} = contextif (props.data.id) {return renderNode(h, props.data, context)} else {return ''}}export default render

tree.less

.org-tree-container {display: inline-block;padding: 15px;background-color: #fff;
}.org-tree {// display: inline-block;display: table;text-align: center;&:before, &:after {content: '';display: table;}&:after {clear: both;}
}.org-tree-node,
.org-tree-node-children {position: relative;margin: 0;padding: 0;list-style-type: none;&:before, &:after {transition: all .35s;}
}
.org-tree-node-label {position: relative;display: inline-block;.org-tree-node-label-inner {padding: 10px 15px;text-align: center;border-radius: 5px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);-webkit-transition-duration: 0.3s;transition-duration: 0.3s;cursor: pointer;}.org-tree-node-label-inner:hover {background-color: #c6e2ff;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)}}.render-node-panel-header {display: flex;flex-direction: row;flex-wrap: nowrap;justify-content: center;align-items: center;margin: 10px 0;
}
.node-box {min-width: 200px;
}.render-node-panel-middle {display: flex;flex-direction: row;justify-content: space-around;align-items: center;
}.org-tree-node-btn {position: absolute;top: 100%;left: 50%;width: 20px;height: 20px;z-index: 10;margin-left: -11px;margin-top: 9px;background-color: #fff;border: 1px solid #ccc;border-radius: 50%;box-shadow: 0 0 2px rgba(0, 0, 0, .15);cursor: pointer;transition: all .35s ease;&:hover {background-color: #e7e8e9;transform: scale(1.15);}&:before, &:after {content: '';position: absolute;}&:before {top: 50%;left: 4px;right: 4px;height: 0;border-top: 1px solid #ccc;}&:after {top: 4px;left: 50%;bottom: 4px;width: 0;border-left: 1px solid #ccc;}&.expanded:after {border: none;}
}
.org-tree-node {padding-top: 20px;display: table-cell;vertical-align: top;&.is-leaf, &.collapsed {padding-left: 10px;padding-right: 10px;}&:before, &:after {content: '';position: absolute;top: 0;left: 0;width: 50%;height: 19px;}&:after {left: 50%;border-left: 1px solid #ddd;}&:not(:first-child):before,&:not(:last-child):after {border-top: 1px solid #ddd;}}
.collapsable .org-tree-node.collapsed {padding-bottom: 30px;.org-tree-node-label:after {content: '';position: absolute;top: 100%;left: 0;width: 50%;height: 20px;border-right: 1px solid #ddd;}
}
.org-tree > .org-tree-node {padding-top: 0;&:after {border-left: 0;}
}
.org-tree-node-children {padding-top: 20px;display: table;&:before {content: '';position: absolute;top: 0;left: 50%;width: 0;height: 20px;border-left: 1px solid #ddd;}&:after {content: '';display: table;clear: both;}
}.horizontal {.org-tree-node {// display: flex;// flex-direction: row;// justify-content: flex-start;// align-items: center;display: table-cell;float: none;padding-top: 0;padding-left: 20px;&.is-leaf, &.collapsed {padding-top: 10px;padding-bottom: 10px;}&:before, &:after {width: 19px;height: 50%;}&:after {top: 50%;left: 0;border-left: 0;}&:only-child:before {top: 1px;border-bottom: 1px solid #ddd;}&:not(:first-child):before,&:not(:last-child):after {border-top: 0;border-left: 1px solid #ddd;}&:not(:only-child):after {border-top: 1px solid #ddd;}.org-tree-node-inner {display: table;}}.org-tree-node-label {display: table-cell;vertical-align: middle;}&.collapsable .org-tree-node.collapsed {padding-right: 30px;.org-tree-node-label:after {top: 0;left: 100%;width: 20px;height: 50%;border-right: 0;border-bottom: 1px solid #ddd;}}.org-tree-node-btn {top: 50%;left: 100%;margin-top: -11px;margin-left: 9px;}& > .org-tree-node:only-child:before {border-bottom: 0;}.org-tree-node-children {// display: flex;// flex-direction: column;// justify-content: center;// align-items: flex-start;display: table-cell;padding-top: 0;padding-left: 20px;&:before {top: 50%;left: 0;width: 20px;height: 0;border-left: 0;border-top: 1px solid #ddd;}&:after {display: none;}& > .org-tree-node {display: block;}}
}

使用

组件引入使用

 
  • 参数说明:
data: 就是树形结构,下面会有案例
horizontal:排列形式
collapsable: 是否展开
  • 函数说明:
on-expand: 展开、闭合节点
on-node-click: 节点点击事件
on-node-mouseover:鼠标悬停
on-node-mouseout:鼠标悬出
renderContent:渲染函数

数据结构案例

data(){return{labelClassName: "bg-color-orange", // 看到node.js 中这个实际没用的basicInfo: { id: null, label: null },basicSwitch: false,data: {id: 0,label: "XXX科技有限公司",className: 'nxnnxnxn', // 切记HTML的class 标签属性不能以数字开头children: [{id: 2,label: "产品研发部",className: 'nxnnxnxn-1',children: [{id: 5,label: "研发-前端",children: [{id: 55,className: 'nxnnxnxn-55',label: "前端1"},{id: 56,className: 'nxnnxnxn-56',label: "前端2"},{id: 57,className: 'nxnnxnxn-57',label: "前端3"},{id: 58,className: 'nxnnxnxn-58',label: "前端4"}]}]}]},}
},
methods:{//渲染节点renderContent(h, data) {// 通过data中的className属性来对div元素进行注入class// 每个节点渲染必然会走这个函数//这里对应的不同的className 需要在上面的tree.less中写入样式return (
data.className}>
{data.label}
测试人员
);},//鼠标移出onMouseout(e, data) {console.log("onMouseout", data)},//鼠标移入onMouseover(e, data) {console.log("onMouseover", data)},//点击节点NodeClick(e, data) {console.log(e, data);},//默认展开toggleExpand(data, val) {if (Array.isArray(data)) {data.forEach(item => {this.$set(item, "expand", val);if (item.children) {this.toggleExpand(item.children, val);}});} else {this.$set(data, "expand", val);if (data.children) {this.toggleExpand(data.children, val);}}},collapse(list) {list.forEach(child => {if (child.expand) {child.expand = false;}child.children && this.collapse(child.children);});},//展开onExpand(e, data) {if ("expand" in data) {data.expand = !data.expand;if (!data.expand && data.children) {this.collapse(data.children);}} else {this.$set(data, "expand", true);}}, }

相关内容

热门资讯

山东诸城偷排危废致4死案一名主... 山东潍坊诸城市舜王街道一厂房深夜偷排危废,产生硫化氢等大量有毒气体,导致4人死亡、3人重伤以及32人...
男子称在邯郸一超市购买的猪肉检... 近日,河北省邯郸市丛台区一消费者王先生反映,其在阳光超市龙湖店购买的猪肉,食用时感觉有异样。随后,他...
市场监管总局:今年首次以法律形... 市场监管总局副局长柳军23日在专题发布会上介绍,2025年,全国食品安全形势总体平稳。市场监管总局坚...
关于健全对刑事案件犯罪嫌疑人、... “两高一部”发布《关于健全对刑事案件犯罪嫌疑人、被告人身份审查工作机制的意见》 为准确、及时查明案件...
完善幼儿园收费政策 三部门发通... 中新网12月23日电 据国家发展和改革委员会网站消息,23日,国家发展改革委、教育部、财政部发布关于...
男子4年强奸继女六七十次,被判... 日前,河北省石家庄市栾城区人民法院在中国裁判文书网公开了一份刑事判决书,男子刘冬(化名)在4年间竟六...
合肥一烤肉店回应宠物狗上桌吃饭... 12月22日,安徽合肥一家烤肉店有宠物狗上桌吃饭,餐桌上的餐盘里放有食物,宠物狗在不断啃食生肉。 2...
中国人民银行关于实施一次性信用... 中国人民银行上海总部,各省、自治区、直辖市及计划单列市分行,征信中心;国家开发银行,各政策性银行、国...
徐杰20分萨林杰32+11 广... 【搜狐体育战报】北京时间12月23日CBA常规赛第5轮,客场作战的广东东阳光以93-85击败广州朗肽...
完善幼儿园收费政策,三部门发通... 今天(12月23日),国家发展改革委、教育部、财政部发布关于完善幼儿园收费政策的通知,全文如下: 各...