前言背景阐明
当初有很多的插件来实现树图的需要。然而对于特定的需要,插件多多少少都有点小问题没法满足。
于是我查看了一些插件,并相熟了其外面的原理,就筹备着手本人封装一个树图组件
原理阐明
其实树图组件很好了解,就是通过递归本身调用本身来实现树图。再说明确一点,最好在头脑中有一个画面,更加便于了解和开发。
1、就是咱们先定义一个组件,在这个组件外面把第一个节点画进去
2、而后再这第一个节点上面进行递归调用本身组件。这样就能够实现像糖葫芦一样一串节点
3、但这只是一串,并不是树,所以还须要在这个根底上,画节点的中央加上循环的画节点。这样就成了树了。
总的来说先易后难,先把骨干了解分明,而后缓缓的往这个树干下面加树枝,这样一棵大树就画好了
效果图展现
具体设计步骤
(我集体不太喜爱间接贴代码上来,所以我就尽量用文字和简要代码来写分明整个的设计流程)
1、数据的格局
[{ label: '显示文字', pictype: '图标类型', children: [ { label: '显示文字', pictype: '图标类型', children: [ { label: '显示文字', pictype: '图标类型', }, { label: '显示文字', pictype: '图标类型', }, ] }, { label: '显示文字', pictype: '图标类型', children: [ { label: '显示文字', pictype: '图标类型', } ] }, ]}]
2、数据格式解析
这是获取的数据格式,个别由后端返回给前端,然而这样间接传给组件是不够的,因为须要思考到节点开展的高度,我封装的时候,为了让组件外部更加通俗易懂,就把高度这个属性在传进组件前就增加进去。计算格局如下:
1、遍历数组,对于节点对象中的children属性的"所有叶子节点"数有多少来乘以节点的高度
2、假如节点高度为70,以上图的数据格式为例,一个根节点对象中的children有两个节点对象,第一个子节点对象有2个叶子节点,第二个根节点对象有1个叶子节点,所以根节点的高度就是703,第一个子节点的高度就是702,第二个子节点的高度就是701,所有叶子结点的高度也是701
3、函数补充
// 计算高度,并增加height属性, nodeInfo是根节点
traveTree(nodeInfo) { let childrenInfo = nodeInfo.children; if (!childrenInfo || childrenInfo.length == 0) { nodeInfo.height = 77; } else { // 循环叶子节点,给每个叶子节点都赋值高度 childrenInfo.map((item) => { this.traveTree(item); }); // 每个节点的高度都由子节点的高度相加 nodeInfo.height = childrenInfo.reduce((preV, n) => { return preV + n.height; }, 0); } return nodeInfo;}
3、组件外部代码
<div v-for="item in data"> // 这是节点的循环,上面就是一个节点的外部组成 // 这是后面的竖线,竖线的高度由通过节点的高度和以及data的长度和data的index <span class="v-line" :style="computerHeight(item.height,data.length,index)"> </span> // 这是后面的横线 <span class="v-line" ></span> // 这是节点,包含图标、文字、和开展膨胀图标 <div> <img :src="#"/> // 图标 // 开展膨胀按钮图标 在这里减少一个属性,用来管制以后节点的递归调用,这样就能达到开展和膨胀的成果了 <span @click="toggleChildren(item)"> <i class="open"> </i> <i class="close"> </i> </span> // 显示文字 <span>{{itemlabel}}</span> </div> // 这是前面的横线 <span class="b-line"></span> // 这是递归调用 ,当children为空或者为图标为膨胀的时候都不展现 <tree-node data="data.children" v-if="item.children != 0 && item.expend"></tree-node></div>
4、下面的函数补充(计算高度的函数)
computerHeight(item.height,data.length,index) {// 以后节点是惟一的一个子节点或者是叶子节点,后面竖线为0if (length == 1 || length == 0) { return { height: '0px', display: 'none' }; } else { // 以后节点是多个子节点之一时,通过以后节点的index,进行判断后面竖线的高度 let height = 0; let marginTop = 0; let marginB = 0;// 当是第一个子节点时,去除一半的高度,并往下调一半的边距 if (index == 0) { height = pheight / 2; marginTop = height; return { height: height + 'px', 'margin-top': marginTop + 'px' }; }// 当是最初一个子节点时,去除一半的高度,并往上调一半的边距 if (index == length - 1) { height = pheight / 2; marginB = height; return { height: height + 'px', 'margin-bottom': marginB + 'px' }; } else { height = pheight; return { height: height + 'px' }; } }}
扩大
1、在需要中必然要退出的就是通过点击图像须要将节点信息层层回调进去。
2、在其中我并没有将根节点的和叶子结点的非凡中央表明,在这里补充一下,根节点是不须要节点后面的竖线和横线的,叶子结点是不须要前面的横线的,只须要在其中加一些判断就行了
3、开展和膨胀图标那里在叶子节点是不须要展现的。开展膨胀按钮的函数,次要就是进行图标的切换和新增一个节点管制属性将管制开展和膨胀的字段值赋值给这个节点管制属性,用来进行递归组件处的显隐判断。这就能够达到以后节点的开展和膨胀的成果了
内容有点多,代码没有贴全,因为有些我感觉不须要展现进去,码字不容易,敬请斧正!