今天有空整理了之前项目中用到的树形结构外加多选框,并实现一定的逻辑,比如全选,单选,全选和单选之间的联动

之前也在网上搜到过有关此功能的实现,于是我也就参考着写了一个,放在了自己的博客里,就当是给自己做了一个笔记,

嘿嘿嘿~~~

下面我直接贴代码

下面是menu.vue的代码

<template>
  <div style="width: 600px;">
    <Tree :menus = "menus" :depth = "depth" :actId = "actId" :showCheckbox="showCheckbox" @selectItem = "selectItem"  @checkItem = "checkItem"></Tree>
  </div>
</template>
<script>
import Tree from '@/components/menuTree'
import data from './data.json'

export default {
  components: {
    Tree
  },
  data () {
    return {
      depth: 0,
      menus: [],
      actId: '',
      showCheckbox: true // 是否显示多选的框,默认不显示
    }
  },
  created () {
    this.getData()
  },
  methods: {
    // 获取数据
    getData () {
      this.menus = data
      // 在每一项中添加show
      this.addShow(this.menus)
    },
    // 递归函数在每一项中添加show
    addShow (arr) {
      for (var i = 0; i < arr.length; i++) {
        this.$set(arr[i], 'show', false)
        if (arr[i].childrenMenus && arr[i].childrenMenus.length > 0) {
          this.addShow(arr[i].childrenMenus)
        }
      }
    },
    // 点击箭头使树展开收缩
    selectItem (data) {
      if (data.childrenMenus && data.childrenMenus.length > 0) {
        // 如果此项下有childrenMenus且length大于0,则切换展开与折叠状态
        data.show = !data.show
      }
      // 则将选中的menuId赋值给actId
      this.actId = data.menuId
    },
    // 进行多选勾选
    checkItem (data) {
      if (data.selected) {
        // 如果这一项的selected有值,说明是被勾选状态,要把selected置为false,清空勾选
        data.selected = false
        // 如果此选项清空勾选后,如果下面有childrenMenus的话,那么也同时要清空
        if (data.childrenMenus && data.childrenMenus.length > 0) {
          this.clearChild(data.childrenMenus)
        }
      } else {
        // 如果这一项的selected为false,说明是未被勾选状态,把selected置为true,添加勾选
        data.selected = true
        // 如果此选项勾选后,如果下面有childrenMenus的话,那么也同时勾选下面所有的孩子
        if (data.childrenMenus && data.childrenMenus.length > 0) {
          this.addChild(data.childrenMenus)
        }
        // 如果此选项勾选后,要判断所有的上级元素是不是应该全部打勾
        this.selectFather(this.menus, data)
      }
    },
    // 定义函数清空所有孩子的勾选
    clearChild (arr) {
      for (var i = 0; i < arr.length; i++) {
        arr[i].selected = false
        if (arr[i].childrenMenus && arr[i].childrenMenus.length > 0) {
          this.clearChild(arr[i].childrenMenus)
        }
      }
    },
    // 定义函数添加所有孩子的勾选
    addChild (arr) {
      for (var i = 0; i < arr.length; i++) {
        arr[i].selected = true
        if (arr[i].childrenMenus && arr[i].childrenMenus.length > 0) {
          this.addChild(arr[i].childrenMenus)
        }
      }
    },
    // 定义函数一层一层的往上寻找父元素的childrenMenus
    clearFather (father, data) {
      for (var i = 0; i < father.length; i++) {
        if (father[i].menuId === data.menuId) {
          // 找到data所在的childrenMenus为father,然后再通过这个childrenMenus找到拥有这个childrenMenus的父元素
          this.clearRealFather(this.menus, father)
        } else if (father[i].childrenMenus && father[i].childrenMenus.length > 0) {
          this.clearFather(father[i].childrenMenus, data)
        }
      }
    },
    // 定义函数根据找到的上层父元素的childrenMenus来寻找父元素,并将他们清除勾选
    clearRealFather (menus, arr) {
      for (var i = 0; i < menus.length; i++) {
        if (menus[i].childrenMenus === arr) {
          // 找到这个拥有childrenMenus的父元素后,将此selected置为false
          menus[i].selected = false
          // 找到这个拥有childrenMenus的父元素后,再调用clearFather,再进行向上寻找父元素,知道没有父元素为止
          this.clearFather(this.menus, menus[i])
        } else if (menus[i].childrenMenus && menus[i].childrenMenus.length > 0) {
          this.clearRealFather(menus[i].childrenMenus, arr)
        }
      }
    },
    // 定义函数一层一层的往上寻找父元素的childrenMenus
    selectFather (father, data) {
      for (var i = 0; i < father.length; i++) {
        if (father[i].menuId === data.menuId) {
          // 执行selectRealFather,将上层父元素也勾选
          this.selectRealFather(this.menus, father[i])
        } else if (father[i].childrenMenus && father[i].childrenMenus.length > 0) {
          this.selectFather(father[i].childrenMenus, data)
        }
      }
    },
    // 定义函数根据找到的上层父元素的childrenMenus来寻找父元素,并将他们勾选
    selectRealFather (menus, obj) {
      for (var i = 0; i < menus.length; i++) {
        if (menus[i].menuId === obj.parentMenuId) {
          // 找到这个拥有childrenMenus的父元素后,给selected赋值,使其勾选
          menus[i].selected = true
          // 找到这个拥有childrenMenus的父元素后,再调用selectRealFather,再进行向上寻找父元素,知道没有父元素为止
          this.selectRealFather(this.menus, menus[i])
        } else if (menus[i].childrenMenus && menus[i].childrenMenus.length > 0) {
          this.selectRealFather(menus[i].childrenMenus, obj)
        }
      }
    }
  }
}

</script>

然后是树形组件components文件夹中menuTree.vue的代码

<template>
  <ul class = "menu-tree">
    <li v-for = "(item,index) in menus" :key = "index">
      <!-- 遍历menus-->
      <div :class = "{'itemTree':true,'active':actId == item.menuId}" @click = "selectItem(item)">
        <div :style = "transform">
          <!-- 如果item没有孩子 -->
          <i class = "el-icon-caret-right" v-if = "item.childrenMenus && item.childrenMenus.length === 0" style="opacity:0"></i>
          <!-- 如果item有孩子且item.show为false,那么图标为折叠图标 -->
          <i class = "el-icon-caret-right" v-if = "item.childrenMenus && item.childrenMenus.length > 0 && !item.show" ></i>
          <!-- 如果item有孩子且item.show为true,那么图标为展开图标 -->
          <i class = "el-icon-caret-bottom" v-if = "item.childrenMenus && item.childrenMenus.length > 0 && item.show"></i>
          <!-- 如果item的selected为true,也就是里面有值的话就是勾选状态,否则就是不勾选状态 -->
          <i class = "selectBox" :class = "{'checkName ':item.selected}" v-if="showCheckbox" @click.stop = "checkItem(item)">
            <i></i>
          </i>
          {{item.menuName}}
        </div>
      </div>
      <el-collapse-transition>
        <!-- 递归组件就是自己调用自己,这里是在自己的组件内再次调用自己,但是务必要和调用使用的一模一样才可以,否则树不会生效 -->
        <Tree v-if = "item.childrenMenus && item.childrenMenus.length > 0 && item.show" :menus = "item.childrenMenus" :depth = "depth+2" :actId = "actId" :showCheckbox="showCheckbox" @selectItem = "selectItem" @checkItem = "checkItem"></Tree>
      </el-collapse-transition>
    </li>
  </ul>
</template>
<script>
export default {
  name: 'Tree',
  props: {
    menus: {type: Array, default () { return [] }},
    depth: {type: [Number, String], default: 0},
    actId: {type: [Number, String], default: ''},
    showCheckbox: {type: Boolean, default: false}
  },
  data () {
    return {
    }
  },
  methods: {
    //  将selectItem方法暴露出去
    selectItem (item) {
      this.$emit('selectItem', item)
    },
    //  将checkItem方法暴露出去
    checkItem (item) {
      this.$emit('checkItem', item)
    }
  },
  computed: {
    // 通过传过来的depth计算下级目录的偏移量,这里我用的transform
    transform () {
      return 'transform:translateX(' + this.depth * 10 + 'px)'
    }
  }
}
</script>
<style lang = "scss" scoped>
  .menu-tree{
    li{
      .itemTree{
        height: 40px;
        line-height: 40px;
        width: 100%;
        padding-left:10px;
        position: relative;
        font-size: 14px;
        &:hover{
          background:#6eb2eb;
          color:#fff;
        }
        .selectBox{
          display: inline-block;
          width: 16px;
          height:16px;
          border:1px solid #ccc;
          border-radius: 3px;
          position: relative;
          background: #fff;
          top:2px;
        }
        .checkName{
          background: #6FD202;
          border-color: #6FD202;
          i{
            position: absolute;
            left: 0;
            top: -1px;
            display: inline-block;
            width: 14px;
            height:10px;
            border:2px solid #ffffff;
            border-right: none;
            border-top: none;
            transform: rotate(-50deg);
          }

        }
      }
      .active{
        background:#4E8EFF;
        color:#fff;
      }
    }
  }
</style>

最后就是模拟的数据

[
  {
    "menuId": 11000000000297,
    "parentMenuId": null,
    "menuName": "Call车",
    "menuTitle": "Call车",
    "childrenMenus": [
      {
        "menuId": 11000000000299,
        "parentMenuId": 11000000000297,
        "menuName": "需求管理",
        "menuTitle": "需求管理",
        "childrenMenus": [
          {
            "menuId": 11000000000300,
            "parentMenuId": 11000000000299,
            "menuName": "查看",
            "menuTitle": "查看",
            "childrenMenus": [],
            "selected": true
          },
          {
            "menuId": 11000000000301,
            "parentMenuId": 11000000000299,
            "menuName": "需求Call车",
            "menuTitle": "需求Call车",
            "childrenMenus": [],
            "selected": true
          }
        ],
        "selected": true
      },
      {
        "menuId": 11000000000304,
        "parentMenuId": 11000000000297,
        "menuName": "需求分配",
        "menuTitle": "需求分配",
        "childrenMenus": [],
        "selected": true
      }
    ],
    "selected": true
  },
  {
    "menuId": 11000000000312,
    "parentMenuId": null,
    "menuName": "财务相关",
    "menuTitle": "财务相关",
    "childrenMenus": [
      {
        "menuId": 11000000000313,
        "parentMenuId": 11000000000312,
        "menuName": "奖金",
        "menuTitle": "奖金",
        "childrenMenus": [
          {
            "menuId": 11000000000314,
            "parentMenuId": 11000000000313,
            "menuName": "奖金查询",
            "menuTitle": "奖金查询",
            "childrenMenus": [],
            "selected": true
          },
          {
            "menuId": 11000000000315,
            "parentMenuId": 11000000000313,
            "menuName": "奖金上传",
            "menuTitle": "奖金上传",
            "childrenMenus": [],
            "selected": false
          },
          {
            "menuId": 11000000000316,
            "parentMenuId": 11000000000313,
            "menuName": "奖金审核",
            "menuTitle": "奖金审核",
            "childrenMenus": [],
            "selected": true
          }
        ],
        "selected": true
      },
      {
        "menuId": 11000000000317,
        "parentMenuId": 11000000000312,
        "menuName": "资金",
        "menuTitle": "资金",
        "childrenMenus": [
          {
            "menuId": 11000000000318,
            "parentMenuId": 11000000000317,
            "menuName": "资金查询",
            "menuTitle": "资金查询",
            "childrenMenus": [],
            "selected": true
          },
          {
            "menuId": 11000000000319,
            "parentMenuId": 11000000000317,
            "menuName": "延期付款申请/提交",
            "menuTitle": "延期付款申请/提交",
            "childrenMenus": [],
            "selected": true
          },
          {
            "menuId": 11000000000321,
            "parentMenuId": 11000000000317,
            "menuName": "延期付款查询",
            "menuTitle": "延期付款查询",
            "childrenMenus": [],
            "selected": true
          },
          {
            "menuId": 11000000000322,
            "parentMenuId": 11000000000317,
            "menuName": "延期付款备案",
            "menuTitle": "延期付款备案",
            "childrenMenus": [],
            "selected": true
          }
        ],
        "selected": true
      },
      {
        "menuId": 11000000000323,
        "parentMenuId": 11000000000312,
        "menuName": "折扣",
        "menuTitle": "折扣",
        "childrenMenus": [
          {
            "menuId": 11000000000324,
            "parentMenuId": 11000000000323,
            "menuName": "折扣录入",
            "menuTitle": "折扣录入",
            "childrenMenus": [],
            "selected": true
          },
          {
            "menuId": 11000000000325,
            "parentMenuId": 11000000000323,
            "menuName": "折扣提交",
            "menuTitle": "折扣提交",
            "childrenMenus": [],
            "selected": true
          },
          {
            "menuId": 11000000000328,
            "parentMenuId": 11000000000323,
            "menuName": "折扣申请查询",
            "menuTitle": "折扣申请查询",
            "childrenMenus": [],
            "selected": true
          }
        ],
        "selected": true
      }
    ],
    "selected": true
  },
  {
    "menuId": 11000000000342,
    "parentMenuId": null,
    "menuName": "信息上传",
    "menuTitle": "信息上传",
    "childrenMenus": [
      {
        "menuId": 11000000000343,
        "parentMenuId": 11000000000342,
        "menuName": "PDI验收",
        "menuTitle": "PDI验收",
        "childrenMenus": [],
        "selected": false
      },
      {
        "menuId": 11000000000344,
        "parentMenuId": 11000000000342,
        "menuName": "终端销售提报",
        "menuTitle": "终端销售提报",
        "childrenMenus": [],
        "selected": false
      }
    ],
    "selected": false
  }
]

至此,一个树形组件外加多选框就做好了
下面看下效果图

第一次写博客,不足之处还望大家见谅,嘿嘿嘿~~~

Logo

前往低代码交流专区

更多推荐