当前位置: 首页 > article >正文

uniapp自定义树型结构数据弹窗,给默认选中的节点,禁用所有子节点

兼容H5、安卓App、微信小程序

实现逻辑:给默认选中节点的所有子节点添加一个disabled属性,以此禁用子节点。

/components/sonTreeNode/sonTreeNode.vue 封装成组件

<template>
	<view>
		<view :class="['item',item.is_level==1?'pL1':item.is_level==2?'pL2':'pL3']" v-for="(item, index) in treeList"
			:key="index">
			<view class="item--row" @click.stop="handleOpenClose(item, index)">
				<view class="icon-box">
					<u-icon :name="item.isOpen?'arrow-down-fill':'arrow-up-fill'" size="12" color="#a8abb2"
						v-if="item.children && item.children.length"></u-icon>
				</view>
				<view class="checkbox-box">
					<u-checkbox-group>
						<u-checkbox :disabled="item.disabled" :activeColor="themeColor" :label="item.name"
							:name="item.id" :checked='item.checked' usedAlone @change="changeCheckbox($event,item)" />
					</u-checkbox-group>
				</view>
			</view>

			<!-- 使用组件本身渲染子项 -->
			<view v-if="item.isOpen && item.children && item.children.length">
				<treeItem :list="item.children">
				</treeItem>
			</view>
		</view>
	</view>
</template>

<script>
	// 引入当前组件
	import treeItem from '../sonTreeNode/sonTreeNode'
	let activeTreeList = []
	export default {
		name: 'treeItem',
		components: {
			treeItem
		},
		// 接收列表数据
		props: {
			list: {
				type: Array,
				default: () => []
			},
			checkedId: {
				type: Array,
				default: () => []
			},
		},
		data() {
			return {
				themeColor: this.$themeColor,
				treeList: [],
			}
		},
		mounted() {
			this.setListUpOpen(this.list)
			this.treeList = this.list
			if (activeTreeList.length == 0) {
				activeTreeList = this.list
			}
		},
		methods: {
			// 全部展开
			setListUpOpen(list, isOpen = true) {
				list.forEach(item => {
					item.isOpen = isOpen
					// 数据回显,选中当前checked和禁用子节点 Start
					if (this.checkedId.includes(item.id)) {
						item.checked = true
						function setSonDisabled(son) {
							son.forEach(v => {
								v.disabled = true
								if (v?.children?.length > 0) {
									setSonDisabled(v.children)
								}
							})
						}
						if (item?.children?.length > 0) {
							setSonDisabled(item.children)
						}
					}
					// End
					if (item?.children?.length > 0) {
						this.setListUpOpen(item.children)
					}
				})
				return list
			},

			// 处理展开或收起
			handleOpenClose(item, index) {
				// 如果不存在isOpen属性就添加该属性。
				if (!item.hasOwnProperty('isOpen')) {
					item.isOpen = false
				}
				item.isOpen = !item.isOpen
				this.$forceUpdate()
			},

			// 禁用子节点
			disableNode(node, disabled) {
				node.forEach(item => {
					item.checked = false
					item.disabled = disabled
					if (item?.children?.length > 0) {
						this.disableNode(item.children, disabled)
					}
				})
				return node
			},

			setAssign(node, child) {
				node.forEach(item => {
					child.forEach(v => {
						if (item.id == v.id) {
							if (v.hasOwnProperty('checked')) {
								item.checked = v.checked
							}
							item.children = v.children
						}
					})
					if (item?.children?.length > 0) {
						this.setAssign(item.children, child)
					}
				})
				return node
			},

			changeCheckbox(isChecked, item) {
				let isHasChild = item?.children?.length > 0
				let oldTreeList = this.treeList
				if (isChecked) {
					item.checked = true
					if (isHasChild) {
						this.disableNode(item.children, true)
					}
				} else {
					item.checked = false
					if (isHasChild) {
						this.disableNode(item.children, false)
					}
				}
				activeTreeList = this.setAssign(activeTreeList, oldTreeList)
				if (isHasChild) {
					// #ifdef H5 ||APP-PLUS
					this.treeList = []
					this.$nextTick(() => {
						this.treeList = oldTreeList
					})
					// #endif

					// #ifdef MP-WEIXIN
					this.loadTreeList()
					// #endif
				}
			},
			getActiveTreeList() {
				return activeTreeList
			},
			cleatActiveTreeList() {
				activeTreeList = []
			},
		}
	}
</script>

<style scoped lang="scss">
	.pL1 {
		padding-left: 10rpx;
	}

	.pL2 {
		padding-left: 20rpx;
	}

	.pL3 {
		padding-left: 30rpx;
	}

	.item {
		margin-bottom: 15rpx;

		.item--row {
			display: flex;
			align-items: center;
			margin-bottom: 20rpx;

			.icon-box {
				width: 30rpx;
			}

			.checkbox-box {}
		}
	}
</style>

data.js 定义树形结构数据

const treeList = [{
		"id": 8,
		"name": "2栋",
		"pid": 0,
		"children": [{
				"id": 31,
				"name": "C单元",
				"pid": 8,
				"children": []
			},
			{
				"id": 30,
				"name": "B单元",
				"pid": 8,
				"children": []
			},
			{
				"id": 13,
				"name": "A单元",
				"pid": 8,
				"children": []
			}
		]
	},
	{
		"id": 9,
		"name": "3栋",
		"pid": 0,
		"children": [{
				"id": 27,
				"name": "B单元",
				"pid": 9,
				"children": [{
					"id": 28,
					"name": "6楼",
					"pid": 27,
				}]
			},
			{
				"id": 14,
				"name": "A单元",
				"pid": 9,
				"children": []
			}
		]
	},
	{
		"id": 11,
		"name": "4栋",
		"pid": 0,
		"children": [{
				"id": 29,
				"name": "B单元",
				"pid": 11,
				"children": []
			},
			{
				"id": 18,
				"name": "A单元",
				"pid": 11,
				"children": [{
					"id": 53,
					"name": "22222",
					"pid": 18,
				}]
			}
		]
	},
	{
		"id": 7,
		"name": "1栋",
		"pid": 0,
		"children": [{
				"id": 67,
				"name": "A单元",
				"pid": 7,
				"children": []
			},
			{
				"id": 66,
				"name": "B单元",
				"pid": 7,
				"children": []
			},
			{
				"id": 65,
				"name": "C单元",
				"pid": 7,
				"children": []
			},
		]
	}
]

export default treeList

页面文件

<template>
	<view class="">
		<u-button type="primary" @click="openPopup()">打开弹窗</u-button>
		<u-popup :show="showPopup" mode="bottom" :round="20" closeable @close="closePopup" :closeOnClickOverlay="false">
			<view class="popup-wrap">
				<view class="popup-title">
					选择子项目
				</view>
				<view class="popup-content">
					<sonTreeNode :list="treeList" ref="sonTreeNodeRef" :checkedId="checkedId"
						v-if="treeList.length>0" />
				</view>
				<view class="popup-footer">
					<view class="btn-box1">
						<u-button @click="closePopup()">取消</u-button>
					</view>
					<view class="btn-box2">
						<u-button type="primary" @click="confirmPopup()">确定</u-button>
					</view>
				</view>
			</view>
		</u-popup>
	</view>
</template>

<script>
	import Vue from 'vue'
	import sonTreeNode from '@/packageD/components/sonTreeNode/sonTreeNode.vue'
	import treeList from "./data.js"
	export default {
		components: {
			sonTreeNode
		},
		data() {
			return {
				treeList: [],
				showPopup: false,
				checkedId: [13, 18, 7, 28]
			};
		},
		onLoad() {},
		onUnload() {
			// #ifdef MP-WEIXIN
			this.clearInstance()
			// #endif
		},
		mounted() {
			// #ifdef MP-WEIXIN
			Vue.prototype.loadTreeList = this.loadTreeList;
			// #endif
		},
		methods: {
			clearInstance() {
				// 清除实例的逻辑
				this.$delete(Vue.prototype, 'loadTreeList');
			},
			loadTreeList() {
				this.$refs.sonTreeNodeRef.treeList = []
				this.$nextTick(() => {
					this.$refs.sonTreeNodeRef.treeList = this.$refs.sonTreeNodeRef.getActiveTreeList()
				})
			},
			openPopup(item, index) {
				this.treeList = treeList
				this.showPopup = true
			},
			confirmPopup() {
				let treeList = this.$refs.sonTreeNodeRef.treeList
				console.log("选中的id=", this.getCheckedIdArr(treeList));
				this.checkedId = this.getCheckedIdArr(treeList)
				this.closePopup()
			},
			closePopup() {
				this.$refs.sonTreeNodeRef.cleatActiveTreeList()
				this.showPopup = false
				this.treeList = []
			},
			getCheckedIdArr(node, arr = []) {
				node.forEach(item => {
					if (item.checked) {
						arr.push(item.id)
					}
					if (item?.children?.length > 0) {
						this.getCheckedIdArr(item.children, arr)
					}
				})
				return arr
			},

		},
	}
</script>

<style lang="scss" scoped>
	.popup-wrap {
		padding: 20rpx 40rpx;

		.popup-title {
			font-size: 36rpx;
			text-align: center;
		}

		.popup-content {
			margin-top: 20rpx;
			height: 800rpx;
			overflow-y: auto;
		}

		.popup-footer {
			display: flex;
			justify-content: space-between;

			.btn-box1,
			.btn-box2 {
				width: 48%;
			}
		}
	}
</style>

效果图


http://www.kler.cn/a/445009.html

相关文章:

  • docker springboot 运维部署详细实例
  • 案例分享|企查查的数据降本增效之路
  • 【Apache Paimon】-- 10 -- Paimon 0.9.0 集成 Hive 3.1.3
  • docker(wsl)命令 帮助文档
  • 卡尔曼网络 针对部分已知动力学的神经网络辅助卡尔曼滤波法
  • devops-部署Harbor实现私有Docker镜像仓库
  • electron 顶部的元素点不中,点击事件不生效
  • 模组 RG500Q入网问题分析
  • 用python写一个接口
  • 【中间件介绍及案例分析】
  • 回归预测 | MATLAB实现CNN-BiLSTM卷积神经网络结合双向长短期记忆神经网络多输入单输出回归预测
  • 探索 AnythingLLM:借助开源 AI 打造私有化智能知识库
  • 计算机工作流程
  • Linux dnf 包管理工具使用教程
  • 在linux系统的docker中安装GitLab
  • 三维引擎cesium学习经验
  • 增强现实(AR)和虚拟现实(VR)的应用
  • 使用 esrally race 测试 Elasticsearch 性能:实践指南
  • halcon单相机+机器人*眼在手外标定心得
  • Maven 插件详解
  • 将3D模型转换为Babylon格式
  • SSM 架构中 JAVA 网络直播带货查询系统设计与 JSP 有效实现方法
  • 2025.01.15python商业数据分析top2
  • BlueLM:以2.6万亿token铸就7B参数超大规模语言模型
  • 【C++】sophus : sim3.hpp 描述了在 3D 空间中的缩放、旋转和平移 (十九)
  • how to write 述职pptx as a tech manager