2023年6月21日发(作者:)

【javascript】纯原⽣js的轻便组织结构图,树状图,⽀持⾃定义样式前⾔写这个插件呢,只是⼀时兴起,公司的项⽬中使⽤到了组织结构图,然后本着⾯向百度、⾕歌编程的思想,我去摸索了半天。结果⼀⽆所获,可能这个词⽤的有点重了,但是就是没有符合我公司项⽬要求的,然后我⼜去了全球最⼤的同性社交⽹站(github)还是没有找到⾃⼰满意的插件。但是整个过程借鉴下来也有了⾃⼰的⼀些⼩思路,⼲脆⾃⼰封装⼀个得了(本⽂的插件⾮常简单,⼤佬勿喷)效果图没图没真相,先放效果图1.竖向渲染效果图2.横向渲染效果图在此就不放 gif 图了,节点皆可动态显⽰和隐藏,也⽀持⾃定义样式。思路和实现思路呢,⼤概是这样的,先定数据结构,因为有了结构才好拿着去定 dom 的结构。因为是结构图嘛,所以⽗⼦关系肯定是跑不掉了,那基本的关系就如下了:{ body: {}, //这个代表当前节点 children: [], //这个代表⼦节点}有⼈问那如果还有孙⼦节点怎么办?诶,问的好!那就开始套娃了(刚好⽅便后期递归渲染),所以结构如下:{ //这个代表当前节点 body: {}, //这个代表⼦节点 children: [ { //这个代表孙⼦节点 body: {}, ... } ],}ok,结构搞定以后,就去拿着⽣成 dom 吧,这⾥我简单写个了⽅法⽤来创建元素,省的每次都写⼀堆...// 创建元素的⽅法function createEl(tag, domStyle, domClass) { let _dom = Element(tag); (_, domStyle); if (domClass) _ame = domClass; return _dom;}是不是简单明了,传标签名、标签的内联样式、标签的类名就可以直接⽣成 dom 元素了。搞定了创建元素的⽅法,在此基础上再去写⼀个创建节点的⽅法,把 body ⾥⾯的新增两个字段t 代表当前节点的内容,为了让节点更丰富化所以这⾥⽀持富⽂本格式。ame 代表当前节点的类名,⽀持多个类名,⽤空格隔开就⾏。有了这两个字段,基本上节点就具备基础的内容和类名了,创建节点⽅法如下:// 创建节点⽅法function createNode(body){ let _body = body; let _node = createEl("div", { margin: "20px", padding: "10px", border: "1px solid #2288ff" boxSizing: "border-box", position: "relative", flexShrink: 0 }, _ame); _TML = _t; return _node;}ok,现在创建元素和创建节点的⽅法都搞定了,下⾯就是要根据结构去渲染出来节点了,这⾥为了更直观的渲染出来结构,我使⽤了 flex布局。为了省事,这⾥直接贴递归渲染节点⽅法的思路,如下:// 递归创建节点的⽅法// data 是数据源、wrap是挂载的容器、id是后⾯⽤来表名⽗⼦关系的标识let nodeNum = 0;function renderNode(data,wrap,id){ // 1.创建⽗元素节点 let parentNode = createEl("div", { display: "flex", alignItems: "center", userSelect: "none" }); // 2.创建当前元素节点 let currentNode = createNode(); // 注意这⾥每个节点上⾯都有属性 id 和 fid 就是为了后⾯表名⽗⼦关系的标识 ribute("data-id", ++nodeNum); ribute("data-fid", id ? id : 0); // 添加公共类名,这⾥防⽌覆盖原有的类名,所以使⽤ ⽅法 ("tree-map-node"); // 3.是否给当前元素节点创建伸缩符 if (!! && !!en && > 0){ // 符合这个条件就渲染,然后⽗相⼦绝放到当前元素上⾯(记得绑定点击事件) ...... } // 4.创建⼦元素节点 if (!!en && > 0 && !) { // 有⼦节点就⾛这个⽅法 let childrenNode = createEl("div"); Child(currentNode); Child(childrenNode); // 注意:因为是使⽤的递归(深度遍历优先)所以parentId需要根据DOM结构去取出来! let parentId = ribute("data-id"); for (let index = 0; index < ; index++) { renderNode(en[index], childrenNode, parentId); } } else { // 没有就直接不创建⼦节点 Child(currentNode); }

// 5.最后挂载到外部容器中 Child(parentNode);}ok,到此节点就全部渲染出来了,渲染出来后,就根据之前说的 id 和 fid 去绘制两点之间的连线,⽅法如下:// 绘制节点之间的连线function drawline() { // 此处写你给每个节点起的公共类名 let selector = ".tree-map-node"; // 获取所有渲染出来的节点 let treeNodes = electorAll(selector); h(function (currentNode) { // 根据 fid 去选中他的⽗元素节点 let parentNode = elector(".tree-map-node[data-id='" + ribute("data-fid") + "']"); if (parentNode) drawLineBetweenNode(parentNode, currentNode); })}// 连接节点的⽅法function drawLineBetweenNode(parentNode,childNode){ // 这⾥根据offsetWidth、offsetHeight、offsetLeft、offsetTop // 找到两点之间的中⼼点和关系就可以连线了 // 具体代码就省略了,可以看源码 ......}到此,插件主要的思路和实现⽅法都介绍完了,剩下的就是把他们组合起来,并且⽀持⾃定义样式了,具体的就不在此展开了。插件已经上传 和 可以点击传送门查看。总结1. ⽬前只定义了⽂本的节点,如果想新增可以在 calssName 上新增类名,根据类名⾃定义样式2. 渲染⽅向⽬前只⽀持两种,横向(horizontal)和竖向(vertical)3. 在 vue 中使⽤的时候建议⽤ npm 安装⽅式,并且在 mounted ⽣命周期中实例化4. 其他⽅式直接引⼊对应的 js ⽂件,然后直接调⽤实例化⽅法就可以5. ⽬前尚存在⼀些问题,空闲时间会想办法解决,浏览器兼容性未测试,主流皆可以6. 写这个只是⾃⼰的项⽬⽤到了,然后⾃⼰就想着封装了⼀个,欢迎⼤家提建议完善

2023年6月21日发(作者:)

【javascript】纯原⽣js的轻便组织结构图,树状图,⽀持⾃定义样式前⾔写这个插件呢,只是⼀时兴起,公司的项⽬中使⽤到了组织结构图,然后本着⾯向百度、⾕歌编程的思想,我去摸索了半天。结果⼀⽆所获,可能这个词⽤的有点重了,但是就是没有符合我公司项⽬要求的,然后我⼜去了全球最⼤的同性社交⽹站(github)还是没有找到⾃⼰满意的插件。但是整个过程借鉴下来也有了⾃⼰的⼀些⼩思路,⼲脆⾃⼰封装⼀个得了(本⽂的插件⾮常简单,⼤佬勿喷)效果图没图没真相,先放效果图1.竖向渲染效果图2.横向渲染效果图在此就不放 gif 图了,节点皆可动态显⽰和隐藏,也⽀持⾃定义样式。思路和实现思路呢,⼤概是这样的,先定数据结构,因为有了结构才好拿着去定 dom 的结构。因为是结构图嘛,所以⽗⼦关系肯定是跑不掉了,那基本的关系就如下了:{ body: {}, //这个代表当前节点 children: [], //这个代表⼦节点}有⼈问那如果还有孙⼦节点怎么办?诶,问的好!那就开始套娃了(刚好⽅便后期递归渲染),所以结构如下:{ //这个代表当前节点 body: {}, //这个代表⼦节点 children: [ { //这个代表孙⼦节点 body: {}, ... } ],}ok,结构搞定以后,就去拿着⽣成 dom 吧,这⾥我简单写个了⽅法⽤来创建元素,省的每次都写⼀堆...// 创建元素的⽅法function createEl(tag, domStyle, domClass) { let _dom = Element(tag); (_, domStyle); if (domClass) _ame = domClass; return _dom;}是不是简单明了,传标签名、标签的内联样式、标签的类名就可以直接⽣成 dom 元素了。搞定了创建元素的⽅法,在此基础上再去写⼀个创建节点的⽅法,把 body ⾥⾯的新增两个字段t 代表当前节点的内容,为了让节点更丰富化所以这⾥⽀持富⽂本格式。ame 代表当前节点的类名,⽀持多个类名,⽤空格隔开就⾏。有了这两个字段,基本上节点就具备基础的内容和类名了,创建节点⽅法如下:// 创建节点⽅法function createNode(body){ let _body = body; let _node = createEl("div", { margin: "20px", padding: "10px", border: "1px solid #2288ff" boxSizing: "border-box", position: "relative", flexShrink: 0 }, _ame); _TML = _t; return _node;}ok,现在创建元素和创建节点的⽅法都搞定了,下⾯就是要根据结构去渲染出来节点了,这⾥为了更直观的渲染出来结构,我使⽤了 flex布局。为了省事,这⾥直接贴递归渲染节点⽅法的思路,如下:// 递归创建节点的⽅法// data 是数据源、wrap是挂载的容器、id是后⾯⽤来表名⽗⼦关系的标识let nodeNum = 0;function renderNode(data,wrap,id){ // 1.创建⽗元素节点 let parentNode = createEl("div", { display: "flex", alignItems: "center", userSelect: "none" }); // 2.创建当前元素节点 let currentNode = createNode(); // 注意这⾥每个节点上⾯都有属性 id 和 fid 就是为了后⾯表名⽗⼦关系的标识 ribute("data-id", ++nodeNum); ribute("data-fid", id ? id : 0); // 添加公共类名,这⾥防⽌覆盖原有的类名,所以使⽤ ⽅法 ("tree-map-node"); // 3.是否给当前元素节点创建伸缩符 if (!! && !!en && > 0){ // 符合这个条件就渲染,然后⽗相⼦绝放到当前元素上⾯(记得绑定点击事件) ...... } // 4.创建⼦元素节点 if (!!en && > 0 && !) { // 有⼦节点就⾛这个⽅法 let childrenNode = createEl("div"); Child(currentNode); Child(childrenNode); // 注意:因为是使⽤的递归(深度遍历优先)所以parentId需要根据DOM结构去取出来! let parentId = ribute("data-id"); for (let index = 0; index < ; index++) { renderNode(en[index], childrenNode, parentId); } } else { // 没有就直接不创建⼦节点 Child(currentNode); }

// 5.最后挂载到外部容器中 Child(parentNode);}ok,到此节点就全部渲染出来了,渲染出来后,就根据之前说的 id 和 fid 去绘制两点之间的连线,⽅法如下:// 绘制节点之间的连线function drawline() { // 此处写你给每个节点起的公共类名 let selector = ".tree-map-node"; // 获取所有渲染出来的节点 let treeNodes = electorAll(selector); h(function (currentNode) { // 根据 fid 去选中他的⽗元素节点 let parentNode = elector(".tree-map-node[data-id='" + ribute("data-fid") + "']"); if (parentNode) drawLineBetweenNode(parentNode, currentNode); })}// 连接节点的⽅法function drawLineBetweenNode(parentNode,childNode){ // 这⾥根据offsetWidth、offsetHeight、offsetLeft、offsetTop // 找到两点之间的中⼼点和关系就可以连线了 // 具体代码就省略了,可以看源码 ......}到此,插件主要的思路和实现⽅法都介绍完了,剩下的就是把他们组合起来,并且⽀持⾃定义样式了,具体的就不在此展开了。插件已经上传 和 可以点击传送门查看。总结1. ⽬前只定义了⽂本的节点,如果想新增可以在 calssName 上新增类名,根据类名⾃定义样式2. 渲染⽅向⽬前只⽀持两种,横向(horizontal)和竖向(vertical)3. 在 vue 中使⽤的时候建议⽤ npm 安装⽅式,并且在 mounted ⽣命周期中实例化4. 其他⽅式直接引⼊对应的 js ⽂件,然后直接调⽤实例化⽅法就可以5. ⽬前尚存在⼀些问题,空闲时间会想办法解决,浏览器兼容性未测试,主流皆可以6. 写这个只是⾃⼰的项⽬⽤到了,然后⾃⼰就想着封装了⼀个,欢迎⼤家提建议完善