小程序实现树形折叠列表并支持无限级

作者:dante_wd 发布时间:2020-01-09 21:25:11

先看下效果图:

image.png

主要是思路还是与同事共同讨论了好一会,发现出来的。

一开始按照常规思路,整嵌套循环来出,一方面数据的组装,样式的控制,都会很麻烦。

前端思路就是在某个父节点控制hidden,下边不用操心数据,直接hidden掉,其子集就都折起来了,但是还是嵌套,又是位置索引控制set一系列问题,于是算了~


于是想到用一维数组,相办法通过样式控制来进行树形展示。毕竟展示出来,谁也不知道后边是多维嵌套数组还是一维,用户不关心后边的数据结构是什么。

一维数组,按属性缩进,加图标,不在话下;

关键的字段:PID(父节点ID),ID,open(是否展开),sort(位置),end,paddingleft(缩进值)

这些下来基本样式就有了,差的是数据控制

不用嵌套,整去了多级索引位置的set,想想就麻烦。(之前做过多级评论就是~)

按位置放入子节点列表,带sort值,能在想要的位置展示出来,带缩进。

于是:(点某个节点,展开就插入节点,收起就删除节点)

image.png


插入什么节点?我做了一个demo,主要是sort值,定好在哪展示。

正常从接口原始数据里找到某个pid下的所有节点对象,然后一个一个push进去(这里我们用一维数组,最后走整体排序,可以直接在整个列表的最后直接push,这点很省心,不用想在哪个位置插入了,反正要重排,关键是sort值,看下代码就知道了~)

image.png

插入及排序:

image.png

指定以sort值排序:

image.png

完事set子节点进去,页面就出来了。


然后是收起,数据上进行删除:

image.png

思路是获取下一个兄弟节点位置,通过数组删除方法进行删除:

image.png

细心的可以看到,我在节点上都加了一个带end的节点,这个是补充节点,虚的,专门用来解决如果真实数据没有下一个兄弟节点拿不到删除到哪的问题。


这是个demo,具体用起来我们会从接口拿到数据,主要第一步先构建出顶级节点列表,pid为空或为0之类的节点,然后针对这个顶级的列表,增删节点就可以了。

注意原始接口拿到的全数据存到一个变量里,后边可以查pid的子集。删除直接在顶级列表里删就好了。


页面代码:

<view class="datalist">

<view wx:for="{{datalist}}" wx:for-item="item" wx:for-index="index">

<view class="item" style="padding-left:{{item.paddingleft}}rpx;" bindtap="itemclick" data-pid="{{item.pid}}" data-sort="{{item.sort}}" data-id="{{item.id}}" data-index="{{index}}" wx:if="{{item.end==0}}">{{item.sort}}<image src="{{fileurls.select_more}}" wx:if="{{item.open==1}}"></image></view>

</view>

</view>


后端js:

var app = getApp();

Page({


/**

  * 页面的初始数据

  */

data: {

datalist: [{

'name': '根1',

'paddingleft': 20,

'pid': 0,

'id': 1,

'open': 0,

'sort': '1',

'end':0

},

{

'name': '根2',

'paddingleft': 20,

'pid': 0,

'id': 2,

'open': 0,

'sort': '2',

'end': 0

},

{

'name': '根3',

'paddingleft': 20,

'pid': 0,

'id': 3,

'open': 0,

'sort': '3',

'end': 0

},

{

'name': '根4',

'paddingleft': 20,

'pid': 0,

'id': 4,

'open': 0,

'sort': '4',

'end': 0

},

{

'name': '根5',

'paddingleft': 20,

'pid': 0,

'id': 5,

'open': 0,

'sort': '5',

'end': 1

}

]

},


/**

  * 生命周期函数--监听页面加载

  */

onLoad: function(options) {

this.setData({

fileurls: app.globalData.fileurls

})

},


itemclick: function(e) {

var pid = e.currentTarget.dataset.pid;

var id = e.currentTarget.dataset.id;

var index = e.currentTarget.dataset.index;

var sort = e.currentTarget.dataset.sort;

var datalist = this.data.datalist;


var open = datalist[index]['open'];

if (open == 1) {

datalist[index]['open'] = 0;

var nexindex = this.getremovelength(datalist[index].sort);

datalist.splice(index + 1, nexindex - index - 1);

this.setData({

datalist: datalist

})

} else {

var sublist = this.getsublist(id, sort);

//console.log('插入子元素' + index);

for (let i in sublist) {

datalist.push(sublist[i]);

}

datalist.sort(this.sortBy('sort'));

datalist[index]['open'] = 1;

this.setData({

datalist: datalist

})

}


},


getsublist: function(id, sort) {

let num = 0;

sort = sort+'';

if (sort.indexOf('-') > 0) {

num = sort.split('-').length - 1

}

var arr = [{

'name': '子' + id + '_1',

'paddingleft': 50 + 30 * num,

'pid': id,

'id': id + 1,

'sort': sort + '-1',

'end': 0

}, {

'name': '子' + id + '_2',

'paddingleft': 50 + 30 * num,

'pid': id,

'id': id + 2,

'sort': sort + '-2',

'end': 0

}, {

'name': '子' + id + '_3',

'paddingleft': 50 + 30 * num,

'pid': id,

'id': id + 3,

'sort': sort + '-3',

'end': 1

}];

return arr;

},


sortBy: function(field) {

return function(a, b) {

if (a[field] < b[field]) {

return -1;

} else if (a[field] > b[field]) {

return 1;

} else {

return 0;

}

}

},


getremovelength: function(sort) {

var datalist = this.data.datalist;

if (sort.indexOf('-') > 0) {

var arr = sort.split('-');

var num = parseInt(arr[arr.length - 1]) + 1;

arr[arr.length - 1] = num;

var nextsort = arr.join('-');

for (let i in datalist) {

if (datalist[i].sort == nextsort) {

return i;

}

}

} else {

var nextsort = parseInt(sort) + 1;

for (let i in datalist) {

if (datalist[i].sort == nextsort) {

return i;

}

}

}

},


})



样式内容:

page{

background-color: #f2f2f2

}


.datalist{

display: grid;

}


.item{

display: flex;

background-color: #fff;

margin-top: 3rpx;

color: #888;

font-size: 24rpx;

padding-top: 20rpx;

padding-bottom: 20rpx;

align-items: center;

}


.item image{

width: 20rpx;

height: 15rpx;

}


转载请注明来源:梦幻岛 http://dreamisland.wang/article/3383p1.html


关于我 |  合作伙伴 |  用户注册 |  帮助中心 |  版权声明