开发需求15-使用el-checkbox组件实现el-tree组件的父子关联关系(非全选/全不选)

需求描述:

大家都知道el-tree可以很明显的通过选中来体现上下节点的父子选中状态,那么如果要求把后端把el-tree的数据结构,通过一个展开的list返回给你,使用el-checkbox组件渲染每一个节点,同时要求选中某一个节点,同时可以选中其父节点和子节点;取消也是一样。

思路:

首先el-checkbox是没有el-tree的check-strictly来严格遵循父子相关联的属性,那么想实现就需要

  1. 向下递归查询点击节点的子节点。

  2. 向上递归查询点击节点的父节点。

  3. 通过indeterminate 属性用以表示 checkbox 的不确定状态,用来表示父节点的选中效果

实现效果:

使用el-checkbox实现el-tree父子关系选中效果

代码实现:

html部分:

html 复制代码
<template>
  <div>
      <el-checkbox
        v-for="(item, key) in labelList"
        :label="item.labelName"
        :key="key"
        v-model="item.checked"
        :indeterminate="item.isIndeterminate"
        @change="changeCheck(item)"
      ></el-checkbox>
  </div>
</template>

JavaScript部分:

javascript 复制代码
<script>
export default {
  data() {
    return {
      listQuery: {
        labelValue: [],
      },
      labelList: [
        // {
        //     labelName: '根目录',
        //     id: 1,
        //     parentId: -1,
        //     checked: false
        // },
        {
          labelName: '一级 1',
          id: 2,
          parentId: 1,
          checked: false,
        },
        {
          labelName: '一级 2',
          id: 3,
          parentId: 1,
          checked: false,
        },
        {
          labelName: '一级 3',
          id: 4,
          parentId: 1,
          checked: false,
        },
        {
          labelName: '二级 1-1',
          id: 5,
          parentId: 2,
          checked: false,
        },
        {
          labelName: '三级 1-1-1',
          id: 9,
          parentId: 5,
          checked: false,
        },
        {
          labelName: '三级 1-1-2',
          id: 10,
          parentId: 5,
          checked: false,
        },
        {
          labelName: '二级 2-1',
          id: 6,
          parentId: 3,
          checked: false,
        },
        {
          labelName: '二级 2-2',
          id: 7,
          parentId: 3,
          checked: false,
        },
        {
          labelName: '二级 3-1',
          id: 8,
          parentId: 4,
          checked: false,
        },
        {
          labelName: '二级 3-2',
          id: 11,
          parentId: 4,
          checked: false,
        },
        {
          labelName: '三级 3-2-1',
          id: 12,
          parentId: 11,
          checked: false,
        },
        {
          labelName: '三级 3-2-2',
          id: 13,
          parentId: 11,
          checked: false,
        },
        {
          labelName: '三级 3-2-3',
          id: 14,
          parentId: 11,
          checked: false,
        }
      ]
    }
  },
 methods: {
    changeCheck(row) {
      // 向下选中子级
      this.downRecursiveChildren(row)

      // 每次添加前先清空选中的标签的name数组
      this.listQuery.labelValue = []
      this.labelList.map((i) => {
        if (i.checked) {
          this.listQuery.labelValue.push(i.labelName)
        }
      })
      console.log('a', this.listQuery.labelValue)
    },
    downRecursiveChildren(row, isGrandChildren = false) {
      if (row.isIndeterminate) {
        row.isIndeterminate = false
      }
      this.labelList.forEach((item) => {
        // 判断点击的标签下,是否有子标签,如果有状态设置为true
        if (row.id === item.parentId) {
          item.checked = row.checked
          // 判断点击的标签下的子标签是否还有子级,如果有,递归调用,把所有子级全部选中
          if (this.labelList.some((v) => item.id === v.parentId)) {
            this.downRecursiveChildren(item, true)
          }
        }
      })
      // 如果没有了,return
      if (isGrandChildren) return
      this.upRecursiveParent(row)
    },
    // 向上寻找父级,添加状态
    upRecursiveParent(row) {
      // 获取点击标签的父标签
      let parentNode = this.labelList.find((v) => v.id == row.parentId)
      // 定义点击标签的兄弟数组
      let subing_list = []

      this.labelList.forEach((item) => {
        // 判断点击标签是否有相同的父级,如果有把所有的兄弟标签获取到
        if (item.parentId === row.parentId) {
          subing_list.push(item)
          console.log('2', subing_list)
        }
      })
      if (parentNode) {
        // 所有的兄弟节点全部选中且没有不确定状态, 需要选中父标签节点
        if (
          subing_list.every((item) => item.checked && !item.isIndeterminate)
        ) {
          // 全选中且没有不确定状态
          parentNode.checked = true
          parentNode.isIndeterminate = false
          console.log('3')
        } else if (
          // 所有的兄弟节点全部选中且没有不确定状态, 需要选中父标签节点
          subing_list.every((item) => !item.checked && !item.isIndeterminate)
        ) {
          // 全不选中并且没有不确定状态,不需要选中父标签节点
          parentNode.checked = false
          parentNode.isIndeterminate = false
          console.log('4')
        } else {
          // 有部分选中,父节点需要设置为半选状态
          parentNode.checked = false
          parentNode.isIndeterminate = true
          console.log('5', parentNode)
        }
        if (parentNode.parentId !== 1) {
          this.upRecursiveParent(parentNode)
        }
      }
    }
  },
}
</script>
相关推荐
并不会1 小时前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
悦涵仙子1 小时前
CSS中的变量应用——:root,Sass变量,JavaScript中使用Sass变量
javascript·css·sass
衣乌安、1 小时前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜1 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师1 小时前
CSS的三个重点
前端·css
耶啵奶膘2 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie4 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic5 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿5 小时前
webWorker基本用法
前端·javascript·vue.js