开发需求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>
相关推荐
哆啦A梦15881 小时前
[前台小程序] 01 项目初始化
前端·vue.js·uni-app
智码看视界2 小时前
老梁聊全栈系列:(阶段一)架构思维与全局观
java·javascript·架构
小周同学@4 小时前
谈谈对this的理解
开发语言·前端·javascript
Wiktok4 小时前
Pyside6加载本地html文件并实现与Javascript进行通信
前端·javascript·html·pyside6
@AfeiyuO4 小时前
分类别柱状图(Vue3)
typescript·vue·echarts
一只小风华~4 小时前
Vue:条件渲染 (Conditional Rendering)
前端·javascript·vue.js·typescript·前端框架
柯南二号4 小时前
【大前端】前端生成二维码
前端·二维码
程序员码歌5 小时前
明年35岁了,如何破局?说说心里话
android·前端·后端
博客zhu虎康5 小时前
React Hooks 报错?一招解决useState问题
前端·javascript·react.js
灰海6 小时前
vue中通过heatmap.js实现热力图(多个热力点)热区展示(带鼠标移入弹窗)
前端·javascript·vue.js·heatmap·heatmapjs