业务需求不复杂,就是 —— 做一个和电脑文件夹类似的组件。
很明显,这要的就是树形组件,但这颗树是个还没定型的树,也就是树的层级数量和每个层级的节点数量是可以随时变化的。
这就说明,我们很难用for循环去实现将这棵树的每个节点展示出来。
像这种一层下面套着一层的组件,一般需要考虑到用递归去实现。
由于我的小程序用的是colorUI的样式框架,且该框架没有提供树形组件,那就只好在这个基础上自己去写一个树形组件了。
先直接上展示效果吧
可见,该组件实现的功能是
1.可以无限地新增下一级目录(子信息集)
2.删除当前目录(信息集)
3.展开/收起下一级目录(子信息集)
当要使用该组件时,需要熟悉树形组件组件(mytree)的代码,也需要熟悉使用该树形组件的页面(useMyTree)的代码
树形组件的代码如下
mytree.wxml
class= class= class= class= class= class= class= class= if= class= if= class= if= class= 'padding-left: 10rpx;' for=
mytree.js
Component({ properties: { //调用页面传进来的参数 model: Object, }, options: { //组件需要该参数才能使用colorUI的class的css样式 addGlobalClass: true }, data: { }, methods: { //展开或收起子信息集 toggle: function (e) { var itemid = this.data.model.id; var open = !this.data.model.open; //将该方法冒泡到调用方处理 this.triggerEvent('toggle', { itemid,open }, { bubbles: true, composed: true }); }, //添加子信息集 addSubCollection: function(e){ console.log('添加子信息集'); //创建子信息集唯一ID,由父ID+子序号组成,如"1-1" var fatherId = this.data.model.id; var sonNumber = this.data.model.nodes.length + 1 var sonId = fatherId + '-' + sonNumber //将该方法冒泡到调用方处理 this.triggerEvent('addsubcollection', { fatherId,sonId }, { bubbles: true, composed: true }); }, //移除当前信息集 removecollection: function(e){ console.log('移除信息集') var itemid = e.currentTarget.dataset.itemid; //将该方法冒泡到调用方处理 this.triggerEvent('removecollection', { itemid: itemid }, { bubbles: true, composed: true }); }, },})
mytree.json
{ "component": true, "usingComponents": { "mytree": "../mytree/mytree" }}
mytree.wxss
/* pages/mine/mytree/mytree.wxss 或者 空白*/
myTree.js中的三个方法,都将该事件冒泡到使用该组件的页面去处理。原因是,在组件中对该数据的处理结果在全局的数据中不可见,所以需要冒泡到使用该组件的页面去进行处理,所以使用该组件的页面需要对这三个事件进行监听,详见下面的useMyTree.wxml和useMyTree.js的代码。
以上是组件的代码,还需在使用该组件页面编写相应的代码,才能正确的使用该组件
使用myTree树形组件的页面代码如下
useMyTree.wxml
<cu-custom bgColor="bg-gradual-blue" isBack="{{true}}"> <view slot="backText">返回view> <view slot="content">创建新集合view>cu-custom><scroll-view style="height:430px;" scroll-y> <mytree wx:for='{{ treeData }}' wx:key='id' model='{{ item }}' bind:addsubcollection="addSubCollection" bind:removecollection="deleteCollection" bind:toggle="toggle"> mytree>scroll-view><button wx:if='{{ !allIsOpened}}' class="cu-btn block bg-green lg margin-tb-sm" bindtap="unfoldAll"> <text class="cuIcon-unfold" >text>全部展开button><button wx:if='{{ allIsOpened}}' class="cu-btn block bg-green lg margin-tb-sm" bindtap="foldAll"> <text class="cuIcon-fold" >text>全部收起button>
useMyTree.js
Page({ /** * 页面的初始数据 */ data: { //是否已全部展开 allIsOpened: false, //集合树 treeData: [{ id: '1', title: '集合名称', open: true, //子信息集节点 nodes: [] }] }, //新增子信息集 addSubCollection: function (e) { var sonId = e.detail.sonId; //截取id成数组 var idArray = e.detail.fatherId.split('-') var treeData = this.data.treeData; for (var i = 0; i //找到本次操作的数组数据 treeData = treeData[parseInt(idArray[i]) - 1].nodes if (i == (idArray.length - 1)) { treeData.push({ id: sonId, title: '子信息集名称', open: true, //子信息集节点 nodes: [] }) } } this.setData({ treeData: this.data.treeData }) }, //删除信息集 deleteCollection: function (e) { var itemid = e.detail.itemid; var idArray = itemid.split('-') var treeData = this.data.treeData; for (var i = 1; i < idArray.length; i++) { treeData = treeData[parseInt(idArray[i - 1]) - 1].nodes //当i等于id数组长度减1,说明已经遍历到需要删除的集合的层级 if (i == (idArray.length - 1)) { treeData.splice(parseInt(idArray[i]) - 1, 1) //根据旧ID给ID重新编序号 for (var j = 0; j < treeData.length; j++) { var oldId = treeData[j].id; var fatherId = oldId.substr(0, oldId.lastIndexOf('-')) var newId = fatherId + '-' + (j + 1) treeData[j].id = newId } break } } this.setData({ treeData: this.data.treeData }) }, //折叠或展开 toggle: function (e) { console.log(e) //需要将open参数设置成的值 var open = e.detail.open; //截取id成数组 var idArray = e.detail.itemid.split('-') var treeData = this.data.treeData; for (var i = 0; i < idArray.length; i++) { //如果i是最后一个数了,那么说明已经循环到所要找的这层了 if (i == idArray.length - 1) { var node = treeData[parseInt(idArray[i]) - 1] //设置open值 node.open = open; //重新设置一下treeData this.setData({ treeData: this.data.treeData }) } treeData = treeData[parseInt(idArray[i]) - 1].nodes } }, //全部收起 foldAll: function (e) { console.log('全部收起') var item = this.data.treeData[0]; this.setOpen(item, false) this.setData({ treeData: this.data.treeData, allIsOpened: false }) }, //全部展开 unfoldAll: function (e) { var item = this.data.treeData[0]; this.setOpen(item, true) this.setData({ treeData: this.data.treeData, allIsOpened: true }) }, //递归设置open值 setOpen(item, openValue) { item.open = openValue; if (item.nodes != undefined) { for (var node of item.nodes) { this.setOpen(node, openValue) } } },})
useMyTree.json
{ "usingComponents": { "mytree": "../../../components/mytree/mytree" }}
备注:mytree的文件所在需要由自己确认,我的是在components目录下的
useMyTree.wxss
/* pages/mine/createNew/createNew.wxss 或者是 空白*/
由useMyTree.js代码可知,该树形结构能够实现无限级的新增和删除操作,核心在于 id字段 的构成样式。该字段根据addSubCollection(新增子目录)方法,假设每个目录下面有两层,则最终生成 id 的样式是
第一层: 1
第二层: 1-1 1-2
第三层: 1-1-1 1-1-2 1-2-1 1-2-2
第四层: 1-1-1-1 1-1-1-2 1-1-2-1 1-1-2-2
1-2-1-1 1-2-1-2 1-2-2-1 1-2-2-2
........(后面层级不再列出)
正是因为这种既可以看出层级,又可以得到当前属于第几个节点的结构,所以可以用来做节点的新增和删除的查找线索
以上,就是基于colorUI实现的树形组件,以及该树形组件的使用方法。
实现思路讲得不多,基本都是使用方法。
有缘用到的朋友,如果有不懂的或者有更好的建议的,欢迎留言讨论。