微信小程序自用Tree树形控件
25-04-07
slbcun
657℃
0
功能包含
全选按钮功能、反选按钮功能 父级列表前的开关 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 }); }, // 子级按钮点击选中或非事件 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 }); }, // 折叠面板切换事件 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 && _this.setData({ bookDataArr: tempArr }); }, // 获取章节列表 async getWrongList() { const _this = this; const _res = await get(`api`); let _tempArr = _res.ret.bookCatalogs; // 章节数据处理 Array.isArray(_tempArr) && _tempArr.length && _tempArr.forEach((itm, idx) => { let tempArrs = []; itm.fallibleCount = Number(itm.fallibleCount); itm.children.length ? 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() {} });