微信小程序自用Tree树形控件
使用有赞的vant组件库开发微信小程序过程中,使用到了tree树形控件,但vant组件库无此组件,所以手撸了一个简陋二级tree树形控件
功能包含
全选按钮功能、反选按钮功能
父级列表前的开关icon
子级列表的选中的禁止或启用
父级列表显示子级列表可选数量
父级下所有可选子级选中则父选中(禁用状态不算)
使用了van-collapse组件带有折叠关闭动画效果
…
效果展示
微信小程序自Tree树形控件 WXML代码部分
<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>
微信小程序自Tree树形控件 JS部分
/*
* @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() {},
});