Vue2手搓级联组件

news2024/11/16 1:19:44

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

      <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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1545352.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

洁净环境监测相关法规指南汇总

一 洁净级别确认 1. 用于生产无菌药品的洁净室和洁净空气设备如单向流系统&#xff08;UDAF&#xff09;、限制进入屏障系统&#xff08;RABS&#xff09;和隔离器&#xff0c;应根据所需环境特性进行确认。生产操作需要在适当洁净度级别的环境中进行&#xff0c;以降低粒子或…

【漏洞复现】通天星CMSV6-inspect_file-upload文件上传漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

Android实现一周时间早中晚排班表

我们要做一个可以动态添加,修改一周早中晚时间排班表&#xff0c;需求图如下&#xff1a; one two 过程具体在这里不描述了&#xff0c;具体查看&#xff0c;https://github.com/yangxiansheng123/WorkingSchedule 上传数据格式&#xff1a; {"friday_plan":"…

个人周总结

个人周总结&#xff1a; 对于总体方向目标的完成&#xff0c;完成的不是很好&#xff0c;这周内的很多天都在游离&#xff0c;就是事情可能有需要做的&#xff0c;但是动力不很足&#xff0c;期间就是有点摆烂了。后面及时调整调整吧&#xff0c;有这种情况&#xff0c;一个原…

无人驾驶(移动机器人)路径规划之A star(Tie Breaker)算法及其matlab实现

在自动驾驶与移动机器人路径规划时&#xff0c;必定会用到经典的算法A star。下面是我未加入与加入Tie Breaker 的matlab实现效果。可以发现加入Tie Breaker之后效果明显改善。 目录 一、效果比较 1.未加入Tie Breaker&#xff08;黑色为障碍物&#xff0c;菱形绿色为目标点…

婴儿洗衣机有必要买吗?四大满分婴儿洗衣机入围榜单

宝宝衣服的清洗对父母来说都很重要&#xff0c;所以挑选一款适合宝宝的波轮洗衣机显得尤为重要。也许有许多人认为&#xff0c;为婴儿购买独立的洗衣机是不必要的&#xff0c;但是你是否了解呢&#xff1f;新生婴儿的肌肤要比成人更脆弱&#xff0c;更易受到感染而受到伤害&…

vue3.0 + ts + eslint报错:error Parsing error: ‘>‘ expected

eslint报错 这里加上对应的 eslint配置即可&#xff1a; parser: vue-eslint-parser, parserOptions: {parser: "typescript-eslint/parser",ecmaVersion: 2020,sourceType: module, }具体如下&#xff1a; module.exports {parser: vue-eslint-parser,parserOpti…

浏览器输入框自动填充默认样式移除

文章目录 浏览器输入框自动填充默认样式移除问题现象以及探索过程尝试代码有效关键代码&#xff08;解决方案&#xff09; 浏览器输入框自动填充默认样式移除 问题现象以及探索过程 &#xff08;在 uniapp 语法下&#xff09;本文的写法在 Edge 119.0.2151.58 (正式版本) (64 …

第九届蓝桥杯大赛个人赛省赛(软件类)真题C 语言 A 组-乘积尾零

solution 找末尾0的个数&#xff0c;即找有多少对2和5 >问题等价于寻找所给数据中&#xff0c;有多少个2和5的因子&#xff0c;较少出现的因子次数即为0的个数 #include <iostream> using namespace std; int main() {// 请在此输入您的代码printf("31");…

docker配置镜像加速后容器和镜像消失

一、问题描述 根据阿里云给docker配置镜像加速器 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://gt6j98xi.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl rest…

大模型落地实战指南:从选择到训练,深度解析显卡选型、模型训练技、模型选择巧及AI未来展望---打造AI应用新篇章

大模型落地实战指南&#xff1a;从选择到训练&#xff0c;深度解析显卡选型、模型训练技、模型选择巧及AI未来展望—打造AI应用新篇章 0.前言大模型发展史 早期阶段&#xff08;1950s~1980s&#xff09; 在1950年代初期&#xff0c;人们开始尝试使用计算机处理自然语言文本。…

C语言:给结构体取别名的4种方法

0 前言 在进行嵌入式开发的过程中&#xff0c;我们经常会见到typedef这个关键字&#xff0c;这个关键字的作用是给现有的类型取别名&#xff0c;在实际使用过程中往往是将一个复杂的类型名取一个简单的名字&#xff0c;便于我们的使用。就像我们给很熟的人取外号一样&#xff…

对标开源3D建模软件blender,基于web提供元宇宙3D建模能力的dtns.network德塔世界是否更胜一筹?

对标开源3D建模软件blender&#xff0c;基于web提供元宇宙3D建模能力的dtns.network德塔世界是否更胜一筹&#xff1f; blender是一款优秀的3D建模开源软件&#xff0c;拥有免费开源、功能强大、渲染速度优秀的优点。而开源的dtns.network德塔世界&#xff0c;亦是专业级的元宇…

计算机网络——27路由选择算法

路由选择算法 路由协议 路由协议的目标&#xff1a;确定从发送主机到接收主机之间&#xff0c;通过路由器的网络“较好”的路径&#xff08;等价于路由器的序列&#xff09; 路径&#xff1a;路由器的序列&#xff0c;分组将会沿着该序列从源主机到达最后的目标主机“较好”…

vue 中实现下载后端返回的流式数据

验证是否是blob /*** Event 验证是否为blob格式* */export async function blobValidate(data) {try {const text await data.text();JSON.parse(text);return false;} catch (error) {return true;}}get请求 /*** Event: get请求下载后端返回的数据流* description: url[Stri…

【No.17】蓝桥杯图论上|最短路问题|Floyd算法|Dijkstra算法|蓝桥公园|蓝桥王国(C++)

图的基本概念 图&#xff1a; 由点(node&#xff0c;或者 vertex)和连接点的边(edge)组成。图是点和边构成的网。 树&#xff1a;特殊的图树&#xff0c;即连通无环图树的结点从根开始&#xff0c;层层扩展子树&#xff0c;是一种层次关系&#xff0c;这种层次关系&#xff0…

Multimodal Chain-of-Thought Reasoning in Language Models阅读笔记

论文&#xff08;2023年&#xff09;链接&#xff1a;https://arxiv.org/pdf/2302.00923.pdf GitHub项目链接&#xff1a;GitHub - amazon-science/mm-cot: Official implementation for "Multimodal Chain-of-Thought Reasoning in Language Models" (stay tuned a…

美国socks5动态IP代理如何提升网络效率?

在探讨美国socks5代理动态IP的奥秘之前&#xff0c;我们需要先深入理解其背后的基本概念和原理。Socks5代理是一种先进的网络协议&#xff0c;它像一位中转站&#xff0c;默默地帮用户转发网络请求。它让网络流量得以通过代理服务器传输&#xff0c;进而隐藏用户的真实IP地址。…

独立游戏《星尘异变》UE5 C++程序开发日志3——UEC++特供的数据类型

本篇日志将介绍FString&#xff0c;FText、FName的用法和相互转换&#xff0c;以及容器TMap&#xff0c;TArray的增删查改 一、字符串相关数据类型&#xff1a;FString、FText、FName FString是最接近std::string的类型&#xff0c;字符串本身可以看做一个存储char型的动态数…

Spire.PDF for .NET【文档操作】演示:查找并删除 PDF 中的空白页

PDF 中的空白页并不罕见&#xff0c;因为它们可能是作者故意留下的或在操作文档时意外添加的。当您阅读或打印文档时&#xff0c;这些空白页可能会很烦人&#xff0c;因此可能非常有必要将其删除。在本文中&#xff0c;您将了解如何使用Spire.PDF for .NET以编程方式查找和删除…