基于Vue的一个树形全选与反选

2019-06-12 admin

文章先发布于我的个人博客站点上,戳这里

最近,由于公司后台管理系统重构,需要一个用到如图所示的一个功能:

项目使用的Vue和elementUI

treebox.gif

一共有4级菜单,要实现全选和反选功能,当下级有一个被选中时,上级也要被选中;当下级全部未被选中时,上级也不能被选中。

网上搜了一圈也没有找到合适的,elementUI的tree组件虽然功能能实现,但是改样式又不方便,于是,只好自己撸一个了。。。。不写不知道自己有多菜!这个东西居然耗时一天。。

这个功能被抽离出来,做成了一个单独的组件。

下面记录下主要的代码: 后台返回的菜单数据格式

let menuData = [
    {
        "id": 1,
        "menName": "管理模式",
        "path": "manageMode",
        "businessCode": "manageMode",
        "parentId": 0,
        "isChecked": null,
        "menLevel": 1,
        "subMenuPermissionsVO": [
            {
                "id": 105,
                "menName": "首页",
                "path": "/index",
                "businessCode": "index",
                "parentId": 1,
                "isChecked": null,
                "menLevel": 2,
                "subMenuPermissionsVO": []
            },
            {
                "id": 106,
                "menName": "工作报表",
                "path": "/report",
                "businessCode": "report",
                "parentId": 1,
                "isChecked": null,
                "menLevel": 2,
                "subMenuPermissionsVO": [
                    {
                        "id": 107,
                        "menName": "数据总揽",
                        "path": "/reportOverView",
                        "businessCode": "reportOverView",
                        "parentId": 106,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": []
                    },
                    {
                        "id": 109,
                        "menName": "客服",
                        "path": "/reportService",
                        "businessCode": "客服",
                        "parentId": 106,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": [
                            {
                                "id": 110,
                                "menName": "工作报表",
                                "path": "/report-service-workreport",
                                "businessCode": "工作报表",
                                "parentId": 109,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            },
                            {
                                "id": 111,
                                "menName": "工作质量报表",
                                "path": "/report-service-qualityreport",
                                "businessCode": "工作质量报表",
                                "parentId": 109,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            }
                        ]
                    },
                    {
                        "id": 112,
                        "menName": "留言报表",
                        "path": "/reportLeaveWords",
                        "businessCode": "留言报表",
                        "parentId": 106,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": []
                    },
                    {
                        "id": 113,
                        "menName": "访问轨迹",
                        "path": "/reportWebsite",
                        "businessCode": "访问轨迹",
                        "parentId": 106,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": []
                    }
                ]
            },
            {
                "id": 114,
                "menName": "历史会话",
                "path": "/history",
                "businessCode": "历史会话",
                "parentId": 1,
                "isChecked": null,
                "menLevel": 2,
                "subMenuPermissionsVO": []
            },
            {
                "id": 115,
                "menName": "客服管理",
                "path": "/service",
                "businessCode": "客服管理",
                "parentId": 1,
                "isChecked": null,
                "menLevel": 2,
                "subMenuPermissionsVO": [
                    {
                        "id": 116,
                        "menName": "所有客服",
                        "path": "/service-all",
                        "businessCode": "所有客服",
                        "parentId": 115,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": []
                    },
                    {
                        "id": 117,
                        "menName": "角色设置",
                        "path": "/service-role-setting",
                        "businessCode": "角色设置",
                        "parentId": 115,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": []
                    }
                ]
            },
            {
                "id": 118,
                "menName": "企业账户",
                "path": "/business",
                "businessCode": "企业账户",
                "parentId": 1,
                "isChecked": null,
                "menLevel": 2,
                "subMenuPermissionsVO": [
                    {
                        "id": 119,
                        "menName": "团队信息",
                        "path": "/business-team",
                        "businessCode": "团队信息",
                        "parentId": 118,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": []
                    },
                    {
                        "id": 120,
                        "menName": "当前服务详情",
                        "path": "/business-service",
                        "businessCode": "当前服务详情",
                        "parentId": 118,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": []
                    },
                    {
                        "id": 121,
                        "menName": "团队联系人",
                        "path": "/business-contacts",
                        "businessCode": "团队联系人",
                        "parentId": 118,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": []
                    }
                ]
            },
            {
                "id": 122,
                "menName": "设置",
                "path": "/setting",
                "businessCode": "设置",
                "parentId": 1,
                "isChecked": null,
                "menLevel": 2,
                "subMenuPermissionsVO": [
                    {
                        "id": 123,
                        "menName": "系统设置",
                        "path": "/setting-system",
                        "businessCode": "系统设置",
                        "parentId": 122,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": [
                            {
                                "id": 124,
                                "menName": "个人信息",
                                "path": "/setting-userinfo",
                                "businessCode": "个人信息",
                                "parentId": 123,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            },
                            {
                                "id": 125,
                                "menName": "修改密码",
                                "path": "/setting-change-pwd",
                                "businessCode": "修改密码",
                                "parentId": 123,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            },
                            {
                                "id": 126,
                                "menName": "通知中心",
                                "path": "/setting-notice",
                                "businessCode": "通知中心",
                                "parentId": 123,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            }
                        ]
                    },
                    {
                        "id": 127,
                        "menName": "在线服务",
                        "path": "/setting-online",
                        "businessCode": "在线服务",
                        "parentId": 122,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": [
                            {
                                "id": 128,
                                "menName": "基础设置",
                                "path": "/setting-online-base",
                                "businessCode": "基础设置",
                                "parentId": 127,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            }
                        ]
                    },
                    {
                        "id": 129,
                        "menName": "接入设置",
                        "path": "/setting-join",
                        "businessCode": "接入设置",
                        "parentId": 122,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": [
                            {
                                "id": 130,
                                "menName": "网站接入",
                                "path": "/setting-join-website",
                                "businessCode": "网站接入",
                                "parentId": 129,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            }
                        ]
                    },
                    {
                        "id": 131,
                        "menName": "高级设置",
                        "path": "/setting-advanced",
                        "businessCode": "高级设置",
                        "parentId": 122,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": [
                            {
                                "id": 132,
                                "menName": "短信服务",
                                "path": "/setting-advanced-msg",
                                "businessCode": "短信服务",
                                "parentId": 131,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            },
                            {
                                "id": 133,
                                "menName": "二维码名片",
                                "path": "/setting-advanced-qrcode",
                                "businessCode": "二维码名片",
                                "parentId": 131,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "id": 2,
        "menName": "客服模式",
        "path": "customerMode",
        "businessCode": "customer",
        "parentId": 0,
        "isChecked": null,
        "menLevel": 1,
        "subMenuPermissionsVO": [
            {
                "id": 102,
                "menName": "留言",
                "path": "儿",
                "businessCode": "分隔符",
                "parentId": 2,
                "isChecked": null,
                "menLevel": 2,
                "subMenuPermissionsVO": [
                    {
                        "id": 103,
                        "menName": "小计成",
                        "path": "34",
                        "businessCode": "大幅度",
                        "parentId": 102,
                        "isChecked": null,
                        "menLevel": 3,
                        "subMenuPermissionsVO": [
                            {
                                "id": 104,
                                "menName": "76657",
                                "path": "76868",
                                "businessCode": "658568",
                                "parentId": 103,
                                "isChecked": null,
                                "menLevel": 4,
                                "subMenuPermissionsVO": []
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

父组件主要代码


<tree-table :menuData="menuData" :level="1"></tree-table>

// 其中menuData为后台返回的数据,level为菜单层级,在menuData中有返回,这里主要是用来写样式用的。。

子组件组件代码(一个递归组件):

子组件全部代码(说明都在代中有注释):

<template>
  <ul class="tree-container" :class="'level'+level">
    <li class="" v-for="(item, Index) in menuData" :key="item.id" :class="'level'+item.menLevel">
      <div class="tree-node-title" :class="'level'+item.menLevel"><label>
        <input type="checkbox" @click.stop="nodeClick(item,Index)" name="menuSelected" :checked="item.isChecked == 1 ? true : false" :value="item.id">
        {{item.menName}}-level{{item.menLevel}}
      </label></div>
      <div class="tree-childnode-container " :class="'level'+item.menLevel">
        <CheckBox :menuData="item.subMenuPermissionsVO" :level="item.menLevel"></CheckBox>
      </div>
    </li>
  </ul>

</template>

<script>
  export default {
    name: 'CheckBox',
    props: ["menuData", "level"],
    data() {
      return {
        checkedVal:[]
      }
    },
    created() {

    },
    mounted() {

    },
    methods: {
      nodeClick(node, index) {
      // 通过isChecked判断是否为选中状态:1-选中;0-未选中。这个字段是后端接口返回的
        if (node.isChecked == 1) {
          this.$set(node, "isChecked", 0)
        } else {
          this.$set(node, "isChecked", 1)
        }
        // 个人理解:组件每次递归调用会生成一个实例,this指向这个实例,这些实例相互独立的,所以每次的this都不一样,具体可以控制台打印看下。
        this.refreshAllParentNodes(this) // 设置父级状态
        this.refreshAllSonNodes(this.$children[index], node.isChecked);// 根据当前点击层级的状态设置自己所有子级的状态
      },
      refreshAllSonNodes(node, status) {

        if (node && node.$children.length) {
          node.menuData.map((meunItem, j) => {
            this.$set(meunItem, 'isChecked', status);
            this.refreshAllSonNodes(node.$children[j], status);
          })
        }
      },
      refreshAllParentNodes(node) {
        if (node) {
          var status = 0;
          var nullCount = 0;
          var fullCount = 0;

          if (node.menuData && node.$parent.menuData) {
            node.menuData.map((meunItem, j) => {
              if (typeof meunItem.isChecked == 'undefined') {
                nullCount++
              } else if (meunItem.isChecked == 0) {
                nullCount++
              } else if (meunItem.isChecked == 1) {
                fullCount++
              }
            })
            if (nullCount === node.$children.length) {
            // 该状态说明当前点击层级和兄弟层级都没选中,所以父级也是未选中状态
              status = 0;
            } else {
            //该状态说明当前点击层级和兄弟层级只要有一个选中,父级也是选中状态
              status = 1;
            }
            node.$parent.menuData.map(child => {
              node.menuData.map((meunItem, j) => {
                if (child.id == meunItem.parentId) {
                // 根据父级id和子级的parentId是否相等,来确定当前点击的层级的父级是哪一个
                  this.$set(child, 'isChecked', status);
                }
              })

            })
          }
          // 递归计算父级
          this.refreshAllParentNodes(node.$parent);
        }
      },
    }
  }
</script>

<style lang="scss">
  .tree-container {
    $borderColor: #ebeef5;
    width: 100%;
    padding: 0;

    &.level3 {
      display: flex;
      flex-wrap: wrap;

      & > .level4 {
        width: 25%;
        padding: 0 20px 0 40px;
      }
    }

    & > .level2 {
      display: flex;
      align-items: center;
      border: 1px solid $borderColor;
      line-height: 45px;

      .tree-node-title {
        &.level2 {
          width: 160px;
          text-align: center;
        }

      }
    }

    .level3 {
      .level3 + .level3 {
        border-top: 1px solid $borderColor;
      }
    }

    .tree-node-title {
      &.level3 {
        background-color: #f2f2f2;
        width: 100%;
        padding: 0 20px;
      }

      &.level1 {
        padding: 20px 0;
      }

    }

    .level2 + .level2 {
      border-top: none;
    }

    .tree-childnode-container {
      width: 100%;

      &.level2 {
        border-left: 1px solid $borderColor;
      }
    }

    input {
      margin-right: 5px;
    }

    label {
      cursor: pointer;
    }

  }
</style>

注意 在当前组件中使用组件本身(递归),注意图中圈出的地方,上面有两种写法

0700DC7EBB9A450C8504982D46B291E3.png

[转载]原文链接:https://segmentfault.com/a/1190000019450852

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-67112.html

文章标题:基于Vue的一个树形全选与反选

相关文章
vue 数组遍历方法forEach和map的原理解析和实际应用
一、前言 forEach和map是数组的两个方法,作用都是遍历数组。在vue项目的处理数据中经常会用到,这里介绍一下两者的区别和具体用法示例。 二、代码 1. 相同点 都是数组的方法 都用来遍历数组 两个函数都有4个参数:匿名函数中可传3...
2018-11-15
为什么要选择Nodejs?Nodejs有什么好处?
什么?JavaScript还能用作服务器编程! Caleb Madrigal是来自美国密尔沃基市的一名软件顾问。四年前,他在听说“将JavaScript用作服务器端语言”这样的说法时,认为那是一个荒唐的想法。有那么多服务器端语言可供选择,为...
2015-11-12
js性能优化 如何更快速加载你的JavaScript页面
确保代码尽量简洁 不要什么都依赖JavaScript。不要编写重复性的脚本。要把JavaScript当作糖果工具,只是起到美化作用。别给你的网站添加大量的JavaScript代码。只有必要的时候用一下。只有确实能改善用户体验的时候用一下。 ...
2015-11-12
10个强大的纯CSS3动画案例分享
我们的网页外观主要由CSS控制,编写CSS代码可以任意改变我们的网页布局以及网页内容的样式。CSS3的出现,更是可以让网页增添了不少动画元素,让我们的网页变得更加生动有趣,并且更易于交互。本文分享了10个非常炫酷的CSS3动画案例,希望大家...
2015-11-16
v-charts | 饿了么团队开源的基于 Vue 和 ECharts 的图表工具
在使用echarts生成图表时,经常需要做繁琐的数据类型转化、修改复杂的配置项,v-charts的出现正是为了解决这个 痛点。基于Vue2.0和echarts封装的v-charts图表组件,只需要统一提供一种对前后端都友好的数据格式 设置简...
2018-05-24
Vue获取DOM元素样式和样式更改示例
在 vue 中用 document 获取 dom 节点进行节点样式更改的时候有可能会出现 ‘style’ is not definde的错误,这时候可以在 mounted 里用 $refs 来获取样式,并进行更改: &lt;template...
2017-03-13
Vue.js组件tab实现选项卡切换
本文实例为大家分享了vue插件tab选项卡的具体代码,供大家参考,具体内容如下 效果图: 代码如下: &lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt; ...
2017-03-13
从2014年的发展来展望JS的未来将会如何
&lt;font face=&quot;寰�杞�闆呴粦, Arial, sans-serif &quot;&gt;2014骞达紝杞�浠惰�屼笟鍙戝睍杩呴€燂紝鍚勭�嶈��瑷€灞傚嚭涓嶇┓锛屼互婊¤冻鐢ㄦ埛涓嶆柇鍙樺寲鐨勯渶姹傘€傝繖浜涜��...
2015-11-12
12个你未必知道的CSS小知识
虽然CSS并不是一种很复杂的技术,但就算你是一个使用CSS多年的高手,仍然会有很多CSS用法/属性/属性值你从来没使用过,甚至从来没听说过。 1.CSS的color属性并非只能用于文本显示 对于CSS的color属性,相信所有Web开发人员...
2015-11-12
ajax为什么令人惊异?ajax的优缺点
使用Ajax的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变的信息。 Ajax不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。就像DHT...
2015-11-12
回到顶部