开发需求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>
相关推荐
Lyuing8 分钟前
el-input数字类型禁止+-符号输入
vue.js
nvvas11 分钟前
npm : 无法加载文件 D:\nvm\nodejs\npm.ps1,因为在此系统上禁止运行脚本问题解决
前端·npm·node.js
拉不动的猪36 分钟前
浏览器之内置四大多线程API
前端·javascript·浏览器
拉不动的猪41 分钟前
Token无感刷新全流程(Vue + Axios + Node.js(Express))
java·javascript·vue.js
再吃一颗苹果要不要41 分钟前
Vue.js 源码解读:从 new Vue() 到 DOM 更新的完整追踪
vue.js
一雨方知深秋44 分钟前
AJAX学习 ---- axios体验
javascript·http·ajax·axios·url·catch·then
林太白44 分钟前
5大排序算法&2大搜索&4大算法思想
前端
摇滚侠1 小时前
浏览器的打印功能,如果通过HTML5,控制样式
前端·html·html5
喵喵侠w1 小时前
uni-app微信小程序相机组件二次拍照白屏问题的排查与解决
前端·数码相机·微信小程序·小程序·uni-app
超大只番薯1 小时前
在Next.js中实现页面级别KeepAlive
前端