el-tree半选回显问题;el-tree获取半选节点id

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

场景 :el-tree有全选和半选模式:之前总结的另一篇是,el-tree传递子级id或父级加子级id;但是现在又多出来一种传递"父级加子级id加半选id "
问题: 那么数据回显时候,el-tree会将半选的id下所有子节点都勾选上(这不是我们想要的,我们依旧想要回显出半选状态),故有此篇;
注意:不能设置default-checked-keys属性

直接复制使用

javascript 复制代码
<template>
  <div>
    <el-scrollbar>
      <div class="ball mb radius overflow">
        <div class="bb div_bgc" style="background: rgba(124, 162, 121, 0.1); padding: 4px 16px">
          <el-checkbox v-model="allFlag" @change="selectCheckBox($event)">手动全选</el-checkbox>
        </div>
        <!--
        default-checked-keys:默认展开值(正常来说需要包含父级id的 但是我们后端不要后端id )
        show-checkbox:多选框
        node-key:每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
        default-expand-all:是否默认展开所有节点
        expand-on-click-node:是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点
        default-checked-keys:默认勾选的节点的 key 的数组
        check-on-click-node:是否在点击节点的时候选中节点,默认值为 false,即只有在点击复选框时才会选中节点
        props:配置选项,具体看下表
        -->
        <!-- {{ submitData }} -->
        <div style="padding: 4px 20px">
          <el-tree
            ref="treeRef"
            class="tree_ref"
            style="max-width: 100%"
            :data="tree"
            show-checkbox
            node-key="id"
            :default-expand-all="true"
            :expand-on-click-node="false"
            :check-on-click-node="true"
            :props="defaultProps"
            @check-change="checkChange"
          >
            <template #default="{ node, data }">
              <span class="custom-tree-node">
                <span>{{ node.label }}</span>
                <span style="color: red; margin-left: 10px">id:{{ data.id }}</span>
              </span>
            </template>
          </el-tree>
          <span>{{ submitData }}</span>
        </div>
      </div>
    </el-scrollbar>
  </div>
</template>

<script setup>
import { ref, onMounted, watch } from 'vue';

let allFlag = ref(false) // 仅做回显勾选
const tree = ref([
  {
    id: 1,
    label: '一级 1',
    children: [
      {
        id: 2,
        label: '二级 2',
        children: [
          { id: 3, label: '三级 3' },
          { id: 4, label: '三级 4' },
        ],
      },
    ],
  },
  {
    id: 5,
    label: '一级 5',
    children: [
      { id: 6, label: '二级 6' },
      { id: 7, label: '二级 7' },
    ],
  },
  {
    id: 8,
    label: '一级 8',
    children: [
      { id: 9, label: '二级 9' },
      {
        id: 10,
        label: '二级 10',
        children: [
          { id: 11, label: '三级 11' },
          { id: 12, label: '三级 12' },
        ],
      },
    ],
  },
]);
// 树组件
const treeRef = ref(null);
const defaultProps = ref({ children: 'children', label: 'label' });
// 回显数据
const dataPlayback = ref([1, 2, 4, 5, 6]);
// 提交数据
const submitData = ref([]);

// 提取含有 children 的所有节点id
const getContainChildrenNode = (data) => {
  let ids = [];
  const recurse = (item) => {
    if (Array.isArray(item)) {
      item.forEach((node) => {
        if (node.children && node.children.length) {
          // 含有子项的节点id
          ids.push(node.id);
          recurse(node.children);
        }
      });
    }
  };
  // 调用递归函数
  recurse(data);
  // 返回含有 children 的所有节点id
  return ids;
};

// 选择
const checkChange = () => {
  // 文档提供半选获取的方法
  submitData.value = treeRef.value?.getCheckedNodes(false, true)?.map(node => node.id) //得到 所有选中的节点id [ 1, 2, 4, 5, 6, 7, 8, 10, 12 ]
}

// 手动全选
const selectCheckBox = value => {
  // 结果1:获取包含父节点的id
  if (value) {
    submitData.value = getAllNodeIds(tree.value)
    // console.log("所有层级id", getAllNodeIds(tree.value))
  } else {
    // 取消勾选所有节点
    submitData.value = []
  }
  treeRef.value?.setCheckedKeys(submitData.value)
}

onMounted(() => {
  // 收集所有顶级节点的值
  const nodeIds = getContainChildrenNode(tree.value); // 得到 含有 children 的所有节点id [1, 2, 5, 8, 10]

  // 过滤掉 顶级节点的值
  const treeVal = dataPlayback.value.filter((item) => !nodeIds.includes(item)); // 得到 回显数据 [4, 6, 7, 12]

  // 回显数据 赋值
  treeRef.value.setCheckedKeys(treeVal);
});


// 递归函数获取所有节点的 ID - 父级和子级
const getAllNodeIds = nodes => {
  let ids = []
  nodes.forEach(node => {
    ids.push(node.id) // 添加当前节点的 ID
    if (node.children) {
      ids = ids.concat(getAllNodeIds(node.children)) // 递归调用以获取子节点的 ID
    }
  })

  return ids
}

watch(
  () => submitData.value,
  newOptions => {
    // 根据监听的值,判断是否全选
    allFlag.value = newOptions.length === getAllNodeIds(tree.value).length
  },
  { deep: true }
)
</script>

<style lang="scss" scoped>
:deep(.tree_ref) {
  margin-left: 12px;
  .el-tree-node__expand-icon {
    display: none;
  }
}

.dark {
  .div_bgc {
    background: var(--my-onlyRead-color) !important;
  }
}
</style>
相关推荐
用户658681803384013 分钟前
Vue3 项目编码规范:基于Composable的清晰架构实践
vue.js
小酒星小杜14 分钟前
在AI时代,技术人应该每天都要花两小时来构建一个自身的构建系统 - Build 篇
前端·vue.js·架构
zengyufei16 分钟前
2.4 watch 监听变化
vue.js
奔跑的web.17 分钟前
TypeScript 全面详解:对象类型的语法规则
开发语言·前端·javascript·typescript·vue
byzh_rc32 分钟前
[微机原理与系统设计-从入门到入土] 微型计算机基础
开发语言·javascript·ecmascript
m0_4711996332 分钟前
【小程序】订单数据缓存 以及针对海量库存数据的 懒加载+数据分片 的具体实现方式
前端·vue.js·小程序
Murrays35 分钟前
【React】01 初识 React
前端·javascript·react.js
helloCat39 分钟前
你的前端代码应该怎么写
前端·javascript·架构
貂蝉空大1 小时前
vue-pdf-embed分页预览解决文字丢失问题
前端·vue.js·pdf
ss2731 小时前
RuoYi-App 本地启动教程
前端·javascript·vue.js