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

server/2024/12/23 4:57:31/

兼容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.listif (activeTreeList.length == 0) {activeTreeList = this.list}},methods: {// 全部展开setListUpOpen(list, isOpen = true) {list.forEach(item => {item.isOpen = isOpen// 数据回显,选中当前checked和禁用子节点 Startif (this.checkedId.includes(item.id)) {item.checked = truefunction setSonDisabled(son) {son.forEach(v => {v.disabled = trueif (v?.children?.length > 0) {setSonDisabled(v.children)}})}if (item?.children?.length > 0) {setSonDisabled(item.children)}}// Endif (item?.children?.length > 0) {this.setListUpOpen(item.children)}})return list},// 处理展开或收起handleOpenClose(item, index) {// 如果不存在isOpen属性就添加该属性。if (!item.hasOwnProperty('isOpen')) {item.isOpen = false}item.isOpen = !item.isOpenthis.$forceUpdate()},// 禁用子节点disableNode(node, disabled) {node.forEach(item => {item.checked = falseitem.disabled = disabledif (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 > 0let oldTreeList = this.treeListif (isChecked) {item.checked = trueif (isHasChild) {this.disableNode(item.children, true)}} else {item.checked = falseif (isHasChild) {this.disableNode(item.children, false)}}activeTreeList = this.setAssign(activeTreeList, oldTreeList)if (isHasChild) {// #ifdef H5 ||APP-PLUSthis.treeList = []this.$nextTick(() => {this.treeList = oldTreeList})// #endif// #ifdef MP-WEIXINthis.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-WEIXINthis.clearInstance()// #endif},mounted() {// #ifdef MP-WEIXINVue.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 = treeListthis.showPopup = true},confirmPopup() {let treeList = this.$refs.sonTreeNodeRef.treeListconsole.log("选中的id=", this.getCheckedIdArr(treeList));this.checkedId = this.getCheckedIdArr(treeList)this.closePopup()},closePopup() {this.$refs.sonTreeNodeRef.cleatActiveTreeList()this.showPopup = falsethis.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.ppmy.cn/server/152408.html

相关文章

Linux docker-20.10.9安装

Linux Docker20.10.9安装 解压文件 tar -xvf docker-20.10.9.tgz 给docker执行文件赋予可执行权限 chmod 755 -R docker/复制docker到/usr/bin/目录下,使docker命令可以执行 cp docker/* /usr/bin/将Docker注册为service&#xff0c;创建docker.service文件 vim /etc/syst…

SQL注入的那些面试题总结

一、知识储备类 1.SQL与NoSQL的区别&#xff1f; SQL&#xff1a;关系型数据库 NoSQL&#xff1a;非关系型数据库 存储方式&#xff1a;SQL具有特定的结构表&#xff0c;NoSQL存储方式灵活 性能&#xff1a;NoSQL较优于SQL 数据类型&#xff1a;SQL适用结构化数据&#xff0c;…

在 Spark 上实现 Graph Embedding

在 Spark 上实现 Graph Embedding 主要涉及利用大规模图数据来训练模型&#xff0c;以学习节点的低维表示&#xff08;嵌入&#xff09;。这些嵌入能够捕捉和反映图中的节点间关系&#xff0c;如社交网络的朋友关系或者物品之间的相似性。在 Spark 上进行这一任务&#xff0c;可…

在 Spring Boot 3 中实现基于角色的访问控制

基于角色的访问控制 (RBAC) 是一种有价值的访问控制模型,可增强安全性、简化访问管理并提高效率。它在管理资源访问对安全和运营至关重要的复杂环境中尤其有益。 我们将做什么 我们有一个包含公共路由和受限路由的 Web API。受限路由需要数据库中用户的有效 JWT。 现在用户…

智慧商城:点击“加入购物车”判断是否登录来进行跳转到登录页登录并回跳 + 发请求渲染加入购物车数量的角标

点击“加入购物车”判断是否登录来进行跳转到登录页登录并回跳 按需引入需要的 Dialog 组件并进行全局注册 Vue.use( )仅仅在Vue组件的上下文中起作用&#xff0c;所以在Vue组件中通过 this.$ 来使用 在 js 文件中则还要导入&#xff0c;然后直接使用&#xff0c;并不需要 this…

【ETCD】【Linearizable Read OR Serializable Read】ETCD 数据读取:强一致性 vs 高性能,选择最适合的读取模式

ETCD 提供了两种不同类型的读取操作方式&#xff0c;分别是 Linearizable Read&#xff08;线性化读取&#xff09;和 Serializable Read&#xff08;可串行化读取&#xff09;。这两种方式主要区分在读取数据时对一致性的要求不同。 目录 1. Linearizable Read&#xff08;线…

Sui 基金会任命 Christian Thompson 为新任负责人

Sui 基金会是专注于推动 Sui 蓬勃发展的生态增长与采用的机构。近日&#xff0c;基金会宣布任命 Christian Thompson 为新任负责人。在 Sui 主网发布的开创性一年里&#xff0c;Sui 凭借其无与伦比的速度、可扩展性和效率&#xff0c;迅速崛起为领先的 Layer 1 区块链之一&…

微信小程序支付/微信小程序+node服务 支付爬坑 v2

一、前端 小程序登录及支付请求和唤起支付界面 // app.js const {request} require(./assets/js/utils) // app.js App({onLaunch() {// 展示本地存储能力const logs wx.getStorageSync(logs) || []logs.unshift(Date.now())wx.setStorageSync(logs, logs)// 登录wx.login({s…