使用有赞的vant组件库开发微信小程序过程中,使用到了tree树形控件,但vant组件库无此组件,所以手撸了一个简陋二级tree树形控件
全选按钮功能、反选按钮功能 父级列表前的开关icon 子级列表的选中的禁止或启用 父级列表显示子级列表可选数量 父级下所有可选子级选中则父选中(禁用状态不算) 使用了van-collapse组件带有折叠关闭动画效果 ...
<van-collapse value="{{ activeNames }}" bind:change="onChange">
<block wx:for="{{wrongList}}" wx:for-item="itm" wx:key="index">
<van-collapse-item name="{{itm.code}}" data-hans="itm.code">
<view slot="title">
<image src="https://xxxx/{{KG[itm.code]!=true ?'open':'close'}}.png"
style="width:20rpx" mode="widthFix" />
{{itm.name}}
<view catchtap="catchtap">
<van-checkbox class="fuCheck" disabled="{{tempCodeArr[itm.code].length==0}}"
value="{{ checkedAll[itm.code] }}" data-hans="{{itm.code}}" bind:change="checkcheck" />
<view class="counts" style="right:106rpx">({{itm.fallibleCount}})</view>
</view>
</view>
<view class="items">
<van-checkbox-group value="{{ choisObj[itm.code] }}" data-hanscode="{{itm.code}}" bind:change="checkChange">
<van-cell-group>
<block wx:if="{{!_itm.hansFu}}" wx:for="{{ itm.children }}" wx:for-index="_index" wx:for-item="_itm"
wx:key="code">
<van-cell title="{{ _itm.name }}" value-class="value-class" clickable>
<van-checkbox name="{{ _itm.code }}" disabled="{{_itm.fallibleCount=='0'?true:false}}" />
<view class="counts">({{_itm.fallibleCount}})</view>
</van-cell>
</block>
</van-cell-group>
</van-checkbox-group>
</view>
</van-collapse-item>
</block>
</van-collapse>
/*
* @Author: Han
* @Date: 2021-01-04 14:18:09
* @LastEditors: Han
* @LastEditTime: 2021-01-04 15:07:09
* @FilePath: \wechat-app\tree.js
*/
import {
get
} from 'api'
Page({
data: {
// 父级按钮合集
checkedAll: [],
// 面板状态合集
activeNames: [],
// 章节List
wrongList: [],
// 选中的子节点合集
choisObj: {},
// 临时 父 子 数组
tempCodeArr: {},
// 全选按钮状态
selectAllStatus: true
},
// 全选事件
selectAll() {
const _this = this
const status = this.data.selectAllStatus
const okTempCodeArr = JSON.parse(JSON.stringify(_this.data.tempCodeArr))
Object.keys(okTempCodeArr).forEach(itm => {
okTempCodeArr[itm].length == 0 && delete okTempCodeArr[itm]
})
// 模拟点击
Object.keys(okTempCodeArr).forEach(itm => {
_this.checkChange({
currentTarget: {
dataset: {
hanscode: itm
}
},
detail: status ? okTempCodeArr[itm] : []
})
})
this.setData({
selectAllStatus: !status,
})
},
// 父级按钮
checkcheck(e) {
const codes = e.currentTarget.dataset.hans
// 判断父级按钮状态
this.setData({
checkedAll: {
...this.data.checkedAll,
[codes]: e.detail
},
choisObj: {
...this.data.choisObj,
[codes]: e.detail ? this.data.tempCodeArr[codes] : []
}
});
// 去除空对象,并设置按钮状态
const tempObj = this.data.choisObj
Object.keys(tempObj).forEach(itm => {
tempObj[itm].length == 0 && delete tempObj[itm]
})
this.setData({
choisObj: tempObj,
btnStatus: Object.keys(tempObj).length > 0
})
},
// 子级按钮点击选中或非事件
checkChange(e) {
const codes = e.currentTarget.dataset.hanscode
// 可选中的是否全选
const status = e.detail.length == this.data.tempCodeArr[codes].length
this.setData({
choisObj: {
...this.data.choisObj,
[codes]: e.detail
},
checkedAll: {
...this.data.checkedAll,
[codes]: status
}
});
const tempObj = this.data.choisObj
Object.keys(tempObj).forEach(itm => {
tempObj[itm].length == 0 && delete tempObj[itm]
})
this.setData({
choisObj: tempObj,
btnStatus: Object.keys(tempObj).length > 0
})
},
// 折叠面板切换事件
onChange(event) {
let tempArr = []
// 当前面板折叠状态 临时变量
let key = false
// 由于面板可以多个同时展开,所以 👇
// 控制面板标题前 图片的 + 或 -
if (this.data.activeNames.length > event.detail.length) {
// 深拷贝
tempArr = JSON.parse(JSON.stringify(this.data.activeNames))
event.detail.forEach(itm => {
const n = tempArr.indexOf(itm);
n != -1 && tempArr.splice(n, 1)
});
key = false
} else {
tempArr = JSON.parse(JSON.stringify(event.detail))
this.data.activeNames.forEach(itm => {
const n = tempArr.indexOf(itm);
n != -1 && tempArr.splice(n, 1)
});
key = true
}
this.setData({
activeNames: event.detail,
KG: {
...this.data.KG,
[tempArr[0]]: key
}
});
},
// 切换事件
onSwitchChange(e) {
// 切换时,清空除额外所有数据
this.setData({
xx: [],
xx: {},
...xx
})
// 之后重新获取列表
this.XXX();
},
// 获取书本信息
async getBookArr() {
wx.showLoading({
title: '获取数据中',
})
let tempArr = [];
const _this = this
const {
ret: {
bookList: _res
}
} = await get('api');
wx.hideLoading()
// 书本信息赋给下拉框
Array.isArray(_res) && _res.forEach(itm => {
tempArr.push({
'text': itm.name,
'value': itm.id
})
})
tempArr.length > 0 && _this.setData({
bookDataArr: tempArr
})
},
// 获取章节列表
async getWrongList() {
const _this = this
const _res = await get(`api`)
let _tempArr = _res.ret.bookCatalogs;
// 章节数据处理
Array.isArray(_tempArr) && _tempArr.length > 0 && _tempArr.forEach((itm, idx) => {
let tempArrs = []
itm.fallibleCount = Number(itm.fallibleCount)
itm.children.length > 0 ? itm.children.forEach(_itm => {
itm.fallibleCount += Number(_itm.fallibleCount)
_itm.fallibleCount != '0' && tempArrs.push(_itm.code)
}) : _tempArr[idx].children.push({
name: itm.name,
code: itm.code,
fallibleCount: itm.fallibleCount,
hansFu: true
})
_this.setData({
tempCodeArr: {
..._this.data.tempCodeArr,
[itm.code]: tempArrs
}
})
})
_res.ret && this.setData({
wrongList: _tempArr
})
},
// 防止父级点击事件冒泡空事件
catchtap() {}
})