三级复选框实现全选

一、实现的功能


1.支持用户点击父复选框进行勾选并勾选底下多有子复选框,取消勾选时取消所有子复选框。
2.当没有全选子复选框时,父复选框将会取消勾选状态。
3.用户完成选择后,可以保存所有被勾选的最后一层复选框。比如有勾选两层复选框,就保存第二级内容,有勾选三层复选框,就只保存第三层复选框。
4.在保存之前,对选中的复选框进行判重处理。


二、数据结构定义


有一个form数组,每个元素代表一个复选框项,其结构如下:

//数据需要的字段
{
  id: Number,
  ffunName: String,
  isChecked: Boolean,
  isExpanded: Boolean,
  children: Array // 子复选框数组
}
                  selectList: [], //要保存的数据
                  //数据格式
                  form: [{
                    ffunName: "商品1",
                    isExpanded: false, // 判断是否需要展开
                    isChecked: false, //判断是否全被勾选
                    children: [{
                        ffunName: "商品1.1",
                        isExpanded: false,
                        isChecked: false,
                        children: [{
                            ffunName: "商品1.1.1",
                            isExpanded: false,
                            isChecked: false,
                            children: [{}],
                        }],
                    }, {
                        ffunName: "商品1.2",
                        isExpanded: false,
                        isChecked: false,
                        children: [{
                            ffunName: "商品1.2.1",
                            isExpanded: false,
                            isChecked: false,
                            children: [{}],

                        }, {
                            ffunName: "商品1.2.2",
                            isExpanded: false,
                            isChecked: false,
                            children: [{}],
                        }],
                    }],
                }, {
                    ffunName: "商品2",
                    isExpanded: false, // 判断是否需要展开
                    isChecked: false, //判断是否全被勾选
                    children: [{
                        ffunName: "商品2.1",
                        isExpanded: false,
                        isChecked: false,
                        children: [{
                            ffunName: "商品2.1.1",
                            isExpanded: false,
                            isChecked: false,
                            children: [{}],
                        }],
                    }],
                }],



三、核心逻辑实现


1. 展开/收起父复选框

javascript
methods: {
  getClick(index) {
    this.form[index].isExpanded = !this.form[index].isExpanded;
  },
  // ... 其他方法
}


getClick方法用于切换复选框的展开/收起状态。

2. 父复选框勾选状态变化,并自动勾选全部子复选框


handleParentChange(parentIndex) {
  const parent = this.form[parentIndex];
  const isChecked = !parent.isChecked;
  const isExpanded = isChecked;
 
  this.$set(this.form, parentIndex, {
    ...parent,
    isChecked: isChecked,
    isExpanded: true,// 勾选父复选框时自动展开
  });
 // 更新所有子复选框的勾选状态,当调用此方法时,所有底下的子复选框全部被勾选
  this.updateChildrenCheckedStatus(parent.children, isChecked, isExpanded);
},
 
updateChildrenCheckedStatus(children, isChecked, isExpanded) {
  if (children && children.length > 0) {
    children.forEach(child => {
      this.$set(child, 'isChecked', isChecked);
      this.$set(child, 'isExpanded', isExpanded);
      if (child.children) {
        //递归,展开并勾选所有复选框
        this.updateChildrenCheckedStatus(child.children, isChecked, isExpanded);
      }
    });
  }
},


handleParentChange方法用于处理父复选框的勾选状态变化,并递归更新其子复选框的勾选状态和展开状态。

3. 子复选框勾选状态变化处理


handleChildChange(parentIndex, childIndex) {
  const parent = this.form[parentIndex];
  let child = parent.children[childIndex];
 // 更新子复选框的勾选状态和展开状态
  this.$set(parent.children, childIndex, {
    ...child,
    isChecked: !child.isChecked,
    isExpanded: true,
  });
 // 重新获取更新后的 child 对象
  const cc = parent.children[childIndex];
// 如果当前子复选框有子复选框,则更新它们的状态
  if (child.children && child.children.length > 0) {
    cc.children.forEach((subChild, subIndex) => {
      this.$set(cc.children, subIndex, {
        ...subChild,
        isChecked: cc.isChecked,
      });
    });
  }
 
  this.sent(parentIndex, childIndex);
},
 
sent(index1, index2) {
  const parent = this.form[index1];
  const child = parent.children[index2];
 // 更新上一级选框
// every方法:每一个 item 的 isChecked 属性是否都为 false。如果所有直接子项的 isChecked 属性都为 false,
// 则 noDirectChildrenChecked 的值为 true;否则,为 false
  const allChildrenChecked = parent.children.every(item => item.isChecked);
  // some方法:是否至少有一个 item 的 isChecked 属性为 true。则 anyChildChecked 的值为 true;
  // 所有子项的复选框都未被选中,则 anyChildChecked 的值为 false。
  const anyChildChecked = parent.children.some(item => item.isChecked);
 // 如果所有子项都勾选,则勾选父级复选框;如果都没有勾选,则取消勾选父级复选框
 // 如果部分子项勾选,就取消勾选父级复选框
  if (allChildrenChecked) {
    this.$set(this.form, index1, {
      ...parent,
      isChecked: true
    });
  } else if (!anyChildChecked) {
    this.$set(this.form, index1, {
      ...parent,
      isChecked: false
    });
  } else {
    this.$set(this.form, index1, {
      ...parent,
      isChecked: false
    });
  }
},


handleChildChange方法用于处理子复选框的勾选状态变化,并更新其父复选框的勾选状态。sent方法用于根据子复选框的勾选状态更新父复选框的勾选状态。

4. 子子复选框勾选状态变化处理


handleChildChanges(parentIndex, childIndex, index3) {
  const parent = this.form[parentIndex];
  const child = parent.children[childIndex];
  const children = child.children[index3];
 // 更新子子复选框的勾选状态
  this.$set(child.children, index3, {
    ...children,
    isChecked: !children.isChecked,
    isExpanded: !children.isExpanded,
  });
 
  this.sentCh(parentIndex, childIndex);
},
 // 更新父级复选框
sentCh(index1, index2) {
  const parent = this.form[index1];
  const child = parent.children[index2];
 // 更新上一级选框
  const allChildrenChecked = child.children.every(item => item.isChecked);
  const anyChildChecked = child.children.some(item => item.isChecked);
// 如果所有子项都勾选,则勾选父级复选框;如果都没有勾选,则取消勾选父级复选框
// 如果部分子项勾选,就取消勾选父级复选框
  if (allChildrenChecked) {
    this.$set(parent.children, index2, {
      ...child,
      isChecked: true,
    });
    const allDirectChildrenChecked = parent.children.every(item => item.isChecked);
    if (allDirectChildrenChecked) {
      this.$set(this.form, index1, {
        ...parent,
        isChecked: true
      });
    }
  } else if (!anyChildChecked) {
    this.$set(parent.children, index2, {
      ...child,
      isChecked: false,
    });
    const noDirectChildrenChecked = parent.children.every(item => !item.isChecked);
    if (noDirectChildrenChecked) {
      this.$set(this.form, index1, {
        ...parent,
        isChecked: false
      });
    }
  } else {
    this.$set(parent.children, index2, {
      ...child,
      isChecked: false,
    });
    this.$set(this.form, index1, {
      ...parent,
      isChecked: false
    });
  }
},


handleChildChanges方法用于处理子子复选框的勾选状态变化,并更新其父级复选框的勾选状态。sentCh方法用于根据子子复选框的勾选状态更新其父级复选框的勾选状态。

5. 保存功能实现


save() {
  this.selectList = [];
  let that = this;
  uni.showModal({
    title: '确定保存?',
    success: function(resu) {
      if (resu.confirm) {
        //这里因为我只是用了三级,所有就直接写固定了,这里实际可以改成递归的形式来完成
        // 获取所有被勾选的最后一级复选框
        that.form.forEach((item) => {
          item.children.forEach((item1) => {
            if (item1.children && item1.children.length > 0) {
              // 如果有子子复选框,则递归检查子子复选框
              item1.children.forEach((item2) => {
                if (item2.isChecked) {
                // 将对象添加到 selectList 数组中
                  that.selectList.push(item2);
                }
              });
            } else {
                // 如果没有子子复选框,则检查子复选框是否被勾选
              if (item1.isChecked) {
                that.selectList.push(item1);
              }
            }
          });
        });
         // 判重,添加
        that.heavySentencing();
      }
    }
  });
},
 
heavySentencing() {
  let valueList = [];
 
  this.selectList.forEach((item) => {
    const selectedItem = {
      fFunName: item.ffunName
    };
    valueList.push(selectedItem);
  });
 
  console.log("保存", valueList);
},


save方法用于弹出确认框,并在用户确认后遍历所有复选框,将被勾选的复选框对象添加到selectList数组中,然后调用heavySentencing方法进行判重处理。

四、页面样式

<template>
	<view class="">
		<view class="page-wraper">
			<view class="page-main">
				<u-checkbox-group placement="column">
					<view v-for="(item, index) in form" :key="index" class="boxs1" ref="form">
						<view class="boxs0" @click="getClick(index)">{{item.ffunName}}
						</view>
						<!-- 父多选框 -->
						<u-checkbox v-show="item.isExpanded" :label="item.ffunName" :size="25" :labelSize="20"
							:name="item.ffunName" :checked="item.isChecked" @change="handleParentChange(index)">
						</u-checkbox>

						<!-- 子多选框 -->
						<view v-show="item.isExpanded" v-for="(item1, index1) in item.children" :key="index1"
							class="boxs2">
							<u-checkbox :checked="item1.isChecked" :label="item1.ffunName" :name="item1.ffunName"
								:size="25" :labelSize="20" @change="handleChildChange(index, index1)">
							</u-checkbox>
							<!-- 子多选框的子多选框 -->
							<view v-show="item1.isExpanded" v-for="(item2, index2) in item1.children" :key="index2"
								class="boxs3">
								<u-checkbox :checked="item2.isChecked" :label="item2.ffunName" :name="item2.ffunName"
									:size="25" :labelSize="20" @change="handleChildChanges(index, index1,index2)">
								</u-checkbox>
							</view>
						</view>
					</view>

				</u-checkbox-group>
			</view>
			<view class="page-footer">
				<view style="display:flex">
					<u-button type="primary" @click="save()" text="保存">
					</u-button>
				</view>
			</view>
		</view>
	</view>
</template>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>