惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Archives - TechRepublic
Security Archives - TechRepublic
罗磊的独立博客
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
Apple Machine Learning Research
Apple Machine Learning Research
The Register - Security
The Register - Security
J
Java Code Geeks
V2EX - 技术
V2EX - 技术
Vercel News
Vercel News
N
News and Events Feed by Topic
腾讯CDC
P
Proofpoint News Feed
N
News | PayPal Newsroom
www.infosecurity-magazine.com
www.infosecurity-magazine.com
爱范儿
爱范儿
O
OpenAI News
酷 壳 – CoolShell
酷 壳 – CoolShell
月光博客
月光博客
Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
D
Docker
Y
Y Combinator Blog
博客园 - 聂微东
G
Google Developers Blog
S
Security @ Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
S
Schneier on Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
S
SegmentFault 最新的问题
云风的 BLOG
云风的 BLOG
阮一峰的网络日志
阮一峰的网络日志
C
CXSECURITY Database RSS Feed - CXSecurity.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
CERT Recently Published Vulnerability Notes
I
Intezer
G
GRAHAM CLULEY
有赞技术团队
有赞技术团队
Attack and Defense Labs
Attack and Defense Labs
V
Visual Studio Blog
博客园 - Franky
博客园 - 三生石上(FineUI控件)
W
WeLiveSecurity
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hugging Face - Blog
Hugging Face - Blog
Scott Helme
Scott Helme
T
Troy Hunt's Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
LINUX DO - 最新话题
C
Cybersecurity and Infrastructure Security Agency CISA

韩小韩博客

你还在用真实邮箱注册网站?等等,你真的想清楚了吗? IPFS星际文件系统 最新二合一收款码 - 物理合并版 从Hexo到Astro博客1分钟迁移指南 Astro 添加 Waline 评论组件 腾讯云 EdgeOne Pages 实测对比:能否成为国内开发者的 Cloudflare Pages 最佳平替? Astro 中使用 Lenis 增加鼠标滚动阻尼感 一组手机和电脑动态壁纸分享【分享】 Astro 添加 Twikoo 评论组件 Astro主题-优雅的vhAstro-Theme【使用文档】 Fetch的GET、POST简单HTTP请求封装 一些实拍的手机壁纸 大理And威海【图】 很喜欢西湖的水【转自:狮子狮子鱼】 Tarot-塔罗牌占卜 Web Watermark 图片添加水印在线小助手 HanAnalytics访问分析Web统计托管于(Cloudflare Pages) 基于AI的微博动态心情分析 阿里云免费用9年ecs教程【适合轻量化服务如frp】 Cloudflare优选IP➕DnsPod的DDNS自动切换 混沌神器Clash全家桶 卷王都在用的变态休息法 NodeJs文本相似度去重脚本 骤雨重山无限存储图床托管于(Cloudflare Pages) 分享好看的天空和云(长期更新) Typecho转到Hexo(主题由Typecho-Joe-Theme转Butterfly主题) Typecho评论导出为Hexo的Valine、Twikoo等评论所支持的JSON文件 Safari浏览器内容被地址栏、菜单栏或工具栏遮挡导致的兼容问题 拼夕夕快速提现100元攻略 2024 平安喜乐 通义灵码:重塑编程的未来,引领技术革新 亚马逊CloudFront免费CDN配置教程 树莓派在Docker中部署Samba 树莓派4B(Raspberry Pi OS Lite 64-bit)安装Docker 变相跳出forEach循环 Vue3项目Build后部署在Nginx上F5刷新页面空白或404 Ant Design Vue 4.0 侧边导航栏Menu组件封装 Ant Design Vue 4.0 a-modal弹窗组件封装 Vue3 + Vite + Vue Router 4后端返回路由配置动态路由权限管理 手撸call apply bind class中函数的this指向 Vue 2与Vue 3在自定义组件v-model上的区别 Vue.set与this.$set源码 Vue底层判断标签的性能优化方法 Linux系统下使用iftop结合iptables服务解决带宽被恶意请求的问题 JS压缩图片并保留图片元信息 蓝奏云盘解析API接口 开源 原型继承和 Class 继承 DOM同级传递事件 2023年有哪些良心的流量卡推荐?爆肝给大家整理好了最新的流量卡合集 火爆全球的ChatGPT,最全的使用方法! 最实用的JavaScript一行代码 AWS教程——解决WordPress网站加载缓慢的大难题 今日热榜HotList-Web前端开源Vue - (聚合热榜) 在Fly.io上部署Alist网盘程序 利用CloudFlare的Workers和Pages反代Github并缓存实现Github文件加速访问 简单逆向某色情网站图片加密(原创) 骚扰电话API接口 开源 知乎热榜API、百度热点API、微博热搜API(开源)- 聚合热榜API开源 韩小韩API上架腾讯云HiFlow 羊了个羊在线刷通关数999999 斐讯N1盒子刷OpenWrt做主路由/旁路由(详细付配置) Adobe After Effects 2022 最新免激活版 FFMPEG视频切片TS文件添加PNG文件头伪图片上传 分享我喜欢的风景图~ 微信小程序调用摄像头实现拍照功能 烈日炎炎的夏天想要一场雨 王者荣耀、和平精英、腾讯手游扫码登录工具如何实现? 摸鱼人日历-每天60秒读懂世界-每日美女-IP签名档-API接口 按照图片尺寸自动分类 手机分辨率 电脑分辨率 python脚本 JS正则常用校验大全(精华篇) Vue项目element组件遇到的坑(记录篇持续更新) 微信小程序原生wx.request简单封装(自用版) 微信小程序登陆封装(自用版)欢迎指正 GitHub技巧之五大隐藏技巧 WPS2019中石油专用版v11.8.2.10972 JS正则判断校验姓名、手机号及身份证号码(笔记) 记个笔记 纯CSS简单图 鼠标拖拽移动DIV 记录一下 Coding免费图床方案 白嫖破解Typora1.1.5最新版 在CloudFlare workers部署你的Hexo静态博客 胎教级搭建Hexo静态博客安装Fluid主题 2022年5个好用的 BT/ 磁力链接下载工具推荐 |Windows 、安卓系统 CloudFlare Argo Tunnel配置 - 实现内网穿透 分享9个可免费使用的网站CDN加速服务 利用免费oss对象存储实现域名防红 情侣要做的好多件事 2022年2月20日 周末·天气晴朗·心情超好·南京浦口码头 2022年2月7号 冬·雪·南京 腾讯云2022新年特惠活动 树莓派ubuntu64位系统安装宝塔 植物大战僵尸 MAC M1 版本 Mac应用程序无法打开或文件损坏的处理方法 Vue项目Element-UI表格el-table的分页el-pagination功能简单封装 前端存储之indexDB 宝塔LNMP搭建Cloudreve进程守护添加SSL证书Nginx代理 2022你好 (白嫖觉)永久免费的虚拟主机合集 Typecho-Joe-Theme主题帮助文档
微信小程序自用Tree树形控件
.𝙃𝙖𝙣 · 2026-04-11 · via 韩小韩博客

avatar

.𝙃𝙖𝙣

875 4.4分钟

Code

使用有赞的 vant 组件库开发微信小程序过程中,使用到了 tree 树形控件,但 vant 组件库无此组件,所以手撸了一个简陋二级 tree 树形控件

功能包含

全选按钮功能、反选按钮功能 父级列表前的开关 icon 子级列表的选中的禁止或启用 父级列表显示子级列表可选数量 父级下所有可选子级选中则父选中(禁用状态不算) 使用了 van-collapse 组件带有折叠关闭动画效果 …

效果展示

微信小程序自用Tree树形控件

微信小程序自 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() {}
});
微信小程序 Vant