Collapse 多级嵌套手风琴组件设计与实现

多级嵌套手风琴组件设计与实现

一个可复用的多级嵌套手风琴组件,实现层级独立控制,点击子级不影响父级,点击兄弟层级关闭其他兄弟的效果。

Collapse 折叠面板

无限层级嵌套实现方法,需求是在构建一个部门树,部门是后端一次性返回的,部门人员通过另外一个接口返回

一级二级图片

二级嵌套

引入组件

                     <member-node
                      :nodes="DeptTree"
                      :level="0"
                      :checkList="checkList"
                      :roleType="roleType"
                      @check-change="handleCheckChange"
                    />
    handleCheckChange(user, checked) {
      console.log("用户:", user);
      console.log("选中状态:", checked);
      if (user.checkeds) {
        // 添加到选中列表
        console.log("用户:", !this.checkList.some((u) => u.userId === user.userId))
        if (!this.checkList.some((u) => u.userId === user.userId)) {
          this.checkList.push({ ...user });
        }
      } else {
        // 从选中列表中移除
        const index = this.checkList.findIndex((u) => u.userId === user.userId);
        if (index !== -1) {
          this.checkList.splice(index, 1);
        }
      }
      console.log("选中用户:", this.checkList);
    },

组件代码

<template>
  <div>
    <el-collapse
      accordion
      v-model="activeName"
      v-for="item in nodes"
      :key="item.skillGroupId"
      @change="handleChange(item)"
    >
      <el-collapse-item :name="item.skillGroupId">
        <template slot="title">
          <div class="member_item">
            <div class="icon"></div>
            <div class="name">{{ item.skillGroupName }}</div>
          </div>
        </template>

        <div style="margin-left: 20px; min-height: 50px">
          <!-- 递归渲染子节点 -->
          <member-node
            v-if="item.children && item.children.length"
            :nodes="item.children"
            :level="level + 1"
            :checkList="checkList"
            :roleType="roleType"
            @item-change="handleChildChange"
            @check-change="$emit('check-change', $event)"
          ></member-node>
          <div
            style="margin-top: 10px; margin-left: 0px"
            class="user_list"
            v-for="(user, userIndex) in users || []"
            :key="'user_' + userIndex"
          >
            <el-checkbox
              style="display: flex; align-items: center"
              v-model="user.checkeds"
              @change="onChecked(user)"
              :disabled="user.isSysFlag === '0' || user.disable"
            >
              <div class="membersBox_content_right">
                <div class="user">
                  <span v-if="user.imgFlag == 1">{{
                    formatString(user.userName)
                  }}</span>
                  <img
                    style="display: inline-block"
                    v-else
                    :src="formatPhoto(user.userId)"
                    alt="后端图片"
                  />
                </div>

                <div class="userinfo">
                  <div class="userinfo_box">
                    <div class="username">
                      {{ user.userName }}
                    </div>
                  </div>
                  <div class="user_id">
                    <span style="margin-right: 10px" v-if="user.userPosition">{{
                      user.userPosition
                    }}</span>
                    <span
                      style="margin-right: 10px"
                      v-if="user.skillGroupName"
                      >{{ user.skillGroupName }}</span
                    >{{ user.userId }}
                  </div>
                </div>
              </div>
            </el-checkbox>
          </div>
          <!-- </div> -->
        </div>
      </el-collapse-item>
    </el-collapse>
  </div>
</template>

<script>
export default {
  name: "MemberNode",
  data() {
    return {
      activeName: "",
      // 当前节点的用户列表
      users: [],
    };
  },
  props: {
    nodes: {
      type: Array,
      default: () => [],
    },
    level: {
      type: Number,
      default: 0,
    },
    checkList: {
      type: Array,
      default: () => [],
    },
    roleType: String,
  },
  watch: {
    nodes() {
      this.activeName = "";
      this.users = [];
    },
    checkList: {
      handler(newVal, oldVal) {
        // console.log(newVal, oldVal);
        if (this.checkList.length > 0) {
          this.users.forEach((item) => {
            item.checkeds = false;
            this.checkList.forEach((checkItem) => {
              if (item.userId === checkItem.userId) {
                item.checkeds = true;
              }
            });
          });
        }
      },
      deep: true, // 开启深度监听
    },
  },

  methods: {
    handleChildChange(item) {
      console.log(item);
      this.$emit("item-change", item);
    },
    handleChange(data) {
      const isActive = this.activeName === data.skillGroupId;
      if (!isActive) {
        console.log("该项已展开,不会重复请求数据");
        return; // 如果已经展开,直接返回,避免重复请求
      } else {
        // this.localActiveName = data.skillGroupId;
        this.$emit("item-change", data.skillGroupId);
      }
      console.log("当前展开项:", this.localActiveName);
      console.log("请求数据checkList:", this.checkList);

    },
    onChecked(user) {
      console.log("用户选中状态变更:", user);
      console.log("当前选中用户:", user.checkeds);
      // this.logEvent(`用户选中状态变更: ${user.userName} - ${user.checkeds}`);
      this.$emit("check-change", user, user.checkeds);
    },
    formatString(name) {
      // 格式化用户名字逻辑
      return name.slice(-2);
    },
    formatPhoto(userId) {
      // 获取用户头像 URL 逻辑
    },
  },
};
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值