Vue2手搓级联组件

在这里插入图片描述
本文的布局才用了叶落风尘大佬的一片文章,功能是自己加的 源代码
页面部分

      <div class="h-100vh grid place-items-center">
        <div>
          <div class="h-455px flex flex-col border-1px border-solid border-#eee w-885px">
            <div class="h-42px flex items-center bg-#F4F7FA pl-15px pr-25px">
              <div class="flex items-center">
                <el-checkbox v-model="checked" @change="changeAll">全选商品</el-checkbox>
                ({{getCheckAll}}/{{lastLevelTotalCount}})
              </div>

              <div class="ml-auto flex items-center cursor-pointer" @click="changeAll(false)">
                <i class="el-icon-delete"></i>
                <div class="text-14px ml-5px">清除</div>
              </div>
            </div>

            <div class="flex-1 h-0">
              <cascade-panel :datalist="dataList">
                <template #list="slotProps">
                  <div class="min-w-120px pl-15px h-32px cursor-pointer flex items-center">
                    <el-checkbox :indeterminate="getCheckStatus(slotProps.data)" v-model="slotProps.data.isChecked" @change="(e) => getData(e, slotProps.data)"></el-checkbox>
                    <div class="ml-10px">{{ slotProps.data.label }}</div>
                    <div v-if="slotProps.data.level && slotProps.data.level == 1">({{ getLastCheck(slotProps.index)}})</div>
                  </div>
                </template>
              </cascade-panel>
            </div>
          </div>
        </div>
      </div>

逻辑部分

<script>
      new Vue({
        el: '#app',
        components: {
          cascadePanel: httpVueLoader('./components/cascadePanel.vue'),
        },
        data() {
          return {
            checked: false,

            selectedItems: ['3', '4'],

            dataList: [
              {
                value: '1',
                label: '指南',
                level: 1,
                isChecked: false,
                children: [
                  {
                    value: '2',
                    label: '设计原则',
                    isChecked: false,
                    parent: null,
                    children: [
                      {
                        value: '3',
                        label: '一致',
                        isChecked: false,
                        parent: null,
                        children: [],
                      },
                      {
                        value: '4',
                        label: '反馈',
                        isChecked: false,
                        parent: null,
                        children: [],
                      },
                    ],
                  },
                  {
                    value: '5',
                    label: '导航',
                    isChecked: false,
                    parent: null,
                    children: [
                      {
                        value: '6',
                        label: '侧向导航',
                        isChecked: false,
                        parent: null,
                        children: [],
                      },
                    ],
                  },
                ],
              },

              {
                value: '10',
                label: '测试',
                level: 1,
                isChecked: false,
                children: [
                  {
                    value: '11',
                    label: '测试11',
                    isChecked: false,
                    parent: null,
                    children: [],
                  },
                  {
                    value: '12',
                    label: '测试22',
                    isChecked: false,
                    parent: null,
                    children: [],
                  },
                ],
              },
            ],
          }
        },
        created() {
          for (let i of this.dataList) {
            this.addParentRef(i)
            this.echoData(i)
          }
        },
        watch: {
          dataList: {
            deep: true,
            handler(newVal, oldVal) {
              this.selectedItems = []
              this.collectSelectedNodes(newVal)
              console.log(this.selectedItems, 'gouxun')
            },
          },
        },
        computed: {
          getLastCheck() {
            return (i) => {
              let total = 0

              function countLastLevelChecked(node) {
                if (node.children?.length > 0) {
                  node.children.forEach((child) => {
                    countLastLevelChecked(child)
                  })
                } else {
                  if (node.isChecked) {
                    total++
                  }
                }
              }
              countLastLevelChecked(this.dataList[i])

              return total
            }
          },
          getCheckAll() {
            let total = 0
            for (let i in this.dataList) {
              total += this.getLastCheck(i)
            }
            return total
          },
          lastLevelTotalCount() {
            let total = 0

            const countLastLevelNodes = (node, level) => {
              if (node.children?.length > 0) {
                node.children.forEach((child) => {
                  countLastLevelNodes(child, level + 1)
                })
              } else {
                total++
              }
            }

            this.dataList.forEach((node) => {
              countLastLevelNodes(node, 0)
            })

            return total
          },
        },

        methods: {
          getCheckStatus(tree) {
            if (tree.children && tree.children.length > 0) {
              if (!tree.children.every((child) => child.isChecked)) {
                for (const node of tree.children) {
                  if (node.isChecked) {
                    return true
                  }
                  if (node.children && node.children.length > 0) {
                    const childResult = this.getCheckStatus(node.children)
                    if (childResult) {
                      return true
                    }
                  }
                }
              } else {
                return false
              }
            }
            return false
          },

          getData(isChecked, data) {
            if (data.children?.length > 0) {
              data.isChecked = isChecked
              data.children.forEach((item) => {
                this.getData(isChecked, item)
              })
              if (data.parent) {
                this.updateParent(data)
              }
            } else {
              data.isChecked = isChecked
              if (data.parent) {
                this.updateParent(data)
              }
            }
          },
          updateParent(node) {
            if (node.parent) {
              const parent = node.parent
              if (parent.children.every((child) => child.isChecked)) {
                parent.isChecked = true
              } else {
                parent.isChecked = false
              }
              this.updateParent(parent) // 递归更新父节点的 isChecked 属性
            }
          },
          // 操作勾选的vlaue
          collectSelectedNodes(nodes) {
            nodes.forEach((node) => {
              if (node.isChecked && node.children.length === 0) {
                this.selectedItems.push(node.value)
              }
              if (node.children && node.children.length > 0) {
                this.collectSelectedNodes(node.children)
              }
            })
          },

          // 回显
          echoData(node) {
            if (this.selectedItems.includes(node.value)) {
              node.isChecked = true // 如果 selectedItems 包含当前节点的 value,则将 isChecked 设置为 true
            } else {
              node.isChecked = false
            }
            if (node.parent) {
              this.updateParent(node)
            }
            if (node.children && node.children.length > 0) {
              node.children.forEach((child) => this.echoData(child)) // 递归处理子节点
            }
          },

          // 添加父节点引用
          addParentRef(node, parent) {
            node.parent = parent
            if (node.children) {
              node.children.forEach((child) => this.addParentRef(child, node))
            }
          },

          // 全选
          changeAll(e) {
            for (let i of this.dataList) {
              this.getData(e, i)
            }
            if (!e) {
              this.checked = false
            }
          },
        },
      })
   </script>

组件部分

<template>
   <div class="flex h-full">
       <div :class="['level_' + propsIndex]" class="border-1px border-r-solid border-#eee overflow-y-auto min-w-180px">
           <div v-for="(item, index) in datalist" :key="index" @click="change(index)"
               :class="{ 'bg-#eff7ff text-#0FA3FF': Number(index) == childActiveId }"
               class="flex items-center pr-10px">
               <slot name="list" :data="item" :index="index"></slot>
               <div v-if="Number(index) == childActiveId" class="el-icon-arrow-right text-14px ml-auto text-#2fafff"></div>
           </div>
       </div>
       <div :class="['out_level_' + (propsIndex + 1)]"
           v-if="datalist[childActiveId] && datalist[childActiveId].children != 0">
           <cascade-panel ref="cascadeRef" :datalist="datalist[childActiveId].children" :propsIndex="propsIndex + 1">
               <template #list="slotProps">
                   <slot name="list" :data="slotProps.data"></slot>
               </template>
           </cascade-panel>
       </div>
   </div>
</template>

<script>
module.exports = {
   name: 'cascadePanel',
   props: {
       datalist: {
           type: Array,
           default: () => [],
       },
       propsIndex: {
           default: 1,
           type: Number
       }
   },
   data() {
       return {
           childActiveId: 0,
       };
   },
   methods: {
       init() {
           this.childActiveId = 0;
           if (this.$refs.cascadeRef) {
               this.$refs.cascadeRef.init()
           }
       },
       change(index) {
           this.init();
           //点击之后下一个组件显示,activeId初始化0
           this.childActiveId = index
       },
   }
};
</script>
  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值