Element-Plus的el-table表格树形结构多选框选中父级时会选中子级(递归多级)

从树形element中(tree-table)表格上做的改变

业务需求:

需要一个对象对应一个或者多个模块

最终点击确认选择后的获取的数据结构为 例:

 [
   {
     "group_id": 99,
     "module_id": [30]
    },
   {
     "group_id": 97,
     "module_id": [23,30]
    },
   {
     "group_id": 96,
     "module_id": [3,5]
    }
]

最终效果

示例demo:vue-table-tree: 基于element-plus的树形表格

git clone https://gitee.com/a__hang/vue-table-tree.git

可呈现效果实现一行的半选状态 一行全选状态和全表格数据的全选状态

逻辑代码:

HTML:

<!-- oneToMany -->
<template>
   <div> 
      <el-dialog v-model="dialogVisibleTask" title="关联任务对象" width="70%" draggable top="5vh" @close="closeDialog" :destroy-on-close="destroyOnClose">
         <el-card shadow="never">
            <template #header>
               <!-- 此处组件是自己封装的搜索组件 可以忽略 -->
               <GlobalSearch @search="dialogHandleSearch" :showOnBack="false" shadow="never" :showReset1="true" :showReset="false"></GlobalSearch>
            </template>
            <el-table border :data="tableData" ref="multipleTableRefDialog" :row-class-name="rowClassNameFun" :header-row-class-name="headerRowClassName" row-key="id" class="mt-1" max-height="500" style="width: 100%" :header-cell-style="{ background: '#fafafa' }" @select="selectFun" size="small" @selection-change="dialogSelectChange" @select-all="selectAllFun">
               <el-table-column type="selection" align="center" :reserve-selection="true"></el-table-column>
               <el-table-column label="序号" type="index" width="50" align="center"></el-table-column>
               <el-table-column align="center" property="serial_no" label="任务对象编号"></el-table-column>
               <el-table-column align="center" property="description" label="任务对象描述"></el-table-column>
               <el-table-column align="center" property="name" label="任务客体名称">
                  <template #default="scope">
                     <el-check-tag checked :type="scope.row.module ? 'primary' : 'info'">
                        {{ scope.row.name }}
                     </el-check-tag>
                  </template>
               </el-table-column>
               <el-table-column align="center" property="module.name" label="任务客体模块">
                  <template #="{ row }">
                     <el-tag v-for="item in row.module" :key="item.id" :type="item.type" :effect="item.type == 'info' ? 'plain' : 'dark'" class="pointer" style="margin: 5px 5px" @click="changeColor(row, item)">
                        {{ item.name }}
                     </el-tag>
                  </template>
               </el-table-column>
            </el-table>
            <el-pagination style="margin-top: 10px" v-model:current-page="dialogPageNo" v-model:page-size="dialogPageSize" :page-sizes="[5, 10, 15, 20]" :background="true" layout="prev, pager, next,->,total" :total="dialogTotal" @size-change="handleSizeChange" @current-change="getObjData" />
            <template #footer>
               <div class="float-r mb-2">
                  <el-button @click="dialogVisibleTask = false">取消</el-button>
                  <el-button type="primary" @click="confirmTask">确定</el-button>
               </div>
            </template>
         </el-card>
      </el-dialog>
   </div>
</template>

tableData数据:

[
        {
                "id": 99,
                "created_at": "2024-05-11 16:12:19",
                "updated_at": "2024-05-11 16:12:19",
                "serial_no": "DX10003",
                "name": "测试对象3",
                "description": "123456",
                "create_user__id": 2,
                "create_user__name": "admins",
                "module": [
                        {
                                "created_at": "2024-04-23T11:44:00+08:00",
                                "serial_no": "mk001",
                                "id": 23,
                                "updated_at": "2024-04-23T11:44:00+08:00",
                                "name": "基本信息",
                                "create_user_id": 37,
                                "delete_flag": 0,
                                "description": "基本信息",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-03-12T10:27:14+08:00",
                                "serial_no": "mk0002",
                                "id": 2,
                                "updated_at": "2024-03-12T10:27:14+08:00",
                                "name": "工艺",
                                "create_user_id": 2,
                                "delete_flag": 0,
                                "description": "洗面奶工艺",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-26T18:45:41+08:00",
                                "serial_no": "mk003",
                                "id": 30,
                                "updated_at": "2024-04-26T18:45:41+08:00",
                                "name": "第三课",
                                "create_user_id": 40,
                                "delete_flag": 0,
                                "description": "第三课",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-24T10:11:33+08:00",
                                "serial_no": "mk004",
                                "id": 26,
                                "updated_at": "2024-04-24T10:11:33+08:00",
                                "name": "产品名称",
                                "create_user_id": 37,
                                "delete_flag": 0,
                                "description": "产品名称",
                                "is_finished": 0,
                                "daily": []
                        }
                ]
        },
        {
                "id": 97,
                "created_at": "2024-05-07 12:27:33",
                "updated_at": "2024-05-09 15:09:29",
                "serial_no": "DX10002",
                "name": "测试对象2",
                "description": "123456",
                "create_user__id": 43,
                "create_user__name": "test003",
                "module": [
                        {
                                "created_at": "2024-03-12T10:26:50+08:00",
                                "serial_no": "mk0001",
                                "id": 1,
                                "updated_at": "2024-05-10T09:05:08+08:00",
                                "name": "流程",
                                "create_user_id": 2,
                                "delete_flag": 0,
                                "description": "洗面奶流程",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-03-12T10:27:14+08:00",
                                "serial_no": "mk0002",
                                "id": 2,
                                "updated_at": "2024-03-12T10:27:14+08:00",
                                "name": "工艺",
                                "create_user_id": 2,
                                "delete_flag": 0,
                                "description": "洗面奶工艺",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-03-13T17:07:49+08:00",
                                "serial_no": "mk0003",
                                "id": 3,
                                "updated_at": "2024-03-20T09:21:58+08:00",
                                "name": "尺寸",
                                "create_user_id": 1,
                                "delete_flag": 0,
                                "description": "尺寸200*100",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-03-13T17:08:01+08:00",
                                "serial_no": "mk0004",
                                "id": 4,
                                "updated_at": "2024-03-13T17:08:01+08:00",
                                "name": "颜色",
                                "create_user_id": 1,
                                "delete_flag": 0,
                                "description": "蓝色",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-03-13T17:08:33+08:00",
                                "serial_no": "mk0005",
                                "id": 5,
                                "updated_at": "2024-03-25T13:07:18+08:00",
                                "name": "牙膏",
                                "create_user_id": 1,
                                "delete_flag": 0,
                                "description": "竹炭清洁",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-03-13T17:08:49+08:00",
                                "serial_no": "mk0006",
                                "id": 6,
                                "updated_at": "2024-03-27T17:10:35+08:00",
                                "name": "类型",
                                "create_user_id": 1,
                                "delete_flag": 0,
                                "description": "日常",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-23T11:44:00+08:00",
                                "serial_no": "mk001",
                                "id": 23,
                                "updated_at": "2024-04-23T11:44:00+08:00",
                                "name": "基本信息",
                                "create_user_id": 37,
                                "delete_flag": 0,
                                "description": "基本信息",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-23T11:44:24+08:00",
                                "serial_no": "mk002",
                                "id": 24,
                                "updated_at": "2024-04-23T11:44:39+08:00",
                                "name": "产品配方",
                                "create_user_id": 37,
                                "delete_flag": 0,
                                "description": "产品配方",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-23T11:45:07+08:00",
                                "serial_no": "mk003",
                                "id": 25,
                                "updated_at": "2024-04-23T11:45:07+08:00",
                                "name": "生产工艺",
                                "create_user_id": 37,
                                "delete_flag": 0,
                                "description": "生产工艺",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-24T10:11:33+08:00",
                                "serial_no": "mk004",
                                "id": 26,
                                "updated_at": "2024-04-24T10:11:33+08:00",
                                "name": "产品名称",
                                "create_user_id": 37,
                                "delete_flag": 0,
                                "description": "产品名称",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-24T10:12:01+08:00",
                                "serial_no": "mk005",
                                "id": 27,
                                "updated_at": "2024-04-24T10:12:01+08:00",
                                "name": "配方相关信息",
                                "create_user_id": 37,
                                "delete_flag": 0,
                                "description": "配方相关信息",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-25T17:54:57+08:00",
                                "serial_no": "mk001",
                                "id": 28,
                                "updated_at": "2024-04-25T17:54:57+08:00",
                                "name": "第一课",
                                "create_user_id": 40,
                                "delete_flag": 0,
                                "description": "第一课",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-25T17:55:17+08:00",
                                "serial_no": "mk002",
                                "id": 29,
                                "updated_at": "2024-04-25T17:55:17+08:00",
                                "name": "第二课",
                                "create_user_id": 40,
                                "delete_flag": 0,
                                "description": "第二课",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-26T18:45:41+08:00",
                                "serial_no": "mk003",
                                "id": 30,
                                "updated_at": "2024-04-26T18:45:41+08:00",
                                "name": "第三课",
                                "create_user_id": 40,
                                "delete_flag": 0,
                                "description": "第三课",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-04-26T18:46:01+08:00",
                                "serial_no": "mk004",
                                "id": 31,
                                "updated_at": "2024-04-26T18:46:01+08:00",
                                "name": "第四课",
                                "create_user_id": 40,
                                "delete_flag": 0,
                                "description": "第四课",
                                "is_finished": 0,
                                "daily": []
                        }
                ]
        },
        {
                "id": 96,
                "created_at": "2024-05-07 12:27:13",
                "updated_at": "2024-05-11 16:09:28",
                "serial_no": "DX10001",
                "name": "测试对象1",
                "description": "123456",
                "create_user__id": 43,
                "create_user__name": "test003",
                "module": [
                        {
                                "created_at": "2024-03-13T17:07:49+08:00",
                                "serial_no": "mk0003",
                                "id": 3,
                                "updated_at": "2024-03-20T09:21:58+08:00",
                                "name": "尺寸",
                                "create_user_id": 1,
                                "delete_flag": 0,
                                "description": "尺寸200*100",
                                "is_finished": 0,
                                "daily": []
                        },
                        {
                                "created_at": "2024-03-13T17:08:33+08:00",
                                "serial_no": "mk0005",
                                "id": 5,
                                "updated_at": "2024-03-25T13:07:18+08:00",
                                "name": "牙膏",
                                "create_user_id": 1,
                                "delete_flag": 0,
                                "description": "竹炭清洁",
                                "is_finished": 0,
                                "daily": []
                        }
                ]
        }
]
<script setup lang="ts">
import { ref, onMounted, watchEffect, nextTick, reactive, watch, onBeforeUpdate } from 'vue';
import { ElMessage } from 'element-plus';
import type { ElTable, CheckboxValueType } from 'element-plus';
import { reqObjInfo } from '@/api/home/index';

const tableData = ref<any>();
const dialogVisibleTask = ref<boolean>(false);
const destroyOnClose=ref<boolean>(false)
const dialogKeyword = ref<any>('');
const dialogPageNo = ref<any>(1);
const dialogPageSize = ref<any>(9999999);
const dialogTotal = ref<any>();
const multipleTableRefDialog = ref<InstanceType<typeof ElTable>>();
const selectDataArr = ref<any>();

const props = defineProps({
   isShowDialog: {
      type: Boolean,
      default: false,
   },
   row: {
      type: Object as () => { module: Array<{ id: string; name: string; type: string; isSelect: boolean }> },
      default: () => ({ module: [] }),
   },
   paramsDataDialog: {
      type: [Array, Object],
      default: () => {
         return [];
      },
   },
   paramsDataDialogId:{
      type:Number,
      default: () => {
         return 0;
      },
   },
   drawerState:{
      type:Boolean,
      default: () => {
         return false;
      },
   }
});
const isShow=ref(true)
onBeforeUpdate(() => {
   if (props.paramsDataDialogId!==0) {
      setTimeout(() => {
         props.paramsDataDialog.forEach((item: any) => {
            tableData.value.forEach((row: any) => {
               if (item.id == row.id) {
                  row.isSelect = true;
                  // 根据 selectImpowerIdArr 中的数组筛选 tableData 中的行,并将其标记为选中状态
                  multipleTableRefDialog.value!.toggleRowSelection(row, true);
                  item.module.forEach((itemItems: any) => {
                     itemItems.isSelect = true;
                     row.module.forEach((rowItems: any) => {
                        if (itemItems.id == rowItems.id) {
                           rowItems.isSelect = true;
                           rowItems.type = 'success';
                           if (row.module.every((item: any) => item.type === 'success')) {
                              row.isSelect = true;
                           } else if (row.module.every((item: any) => item.type === 'info')) {
                              row.isSelect = false;
                           } else {
                              row.isSelect = '';
                           }
                           multipleTableRefDialog.value!.toggleRowSelection(rowItems, true);
                        }
                     });
                  });
               }
            });
         });
      }, 150);
   } else if (props.paramsDataDialogId==0 && groups.length == 0) {
      if (isShow.value) {
         initData();
      if (multipleTableRefDialog.value!==undefined) {
         // destroyOnClose.value=true
         multipleTableRefDialog.value!.clearSelection();
      } 
      isShow.value = false;
   }
   }
});   

onMounted(() => {
   getObjData();
});
const getObjData = async () => {
   let resObj: any = await reqObjInfo(1, 9999999, dialogKeyword.value);
   if (resObj.code == 0) {
      tableData.value = resObj.data;
      dialogTotal.value = resObj.total;
      initData();
   } else {
      ElMessage({
         message: '获取错误!',
         type: 'error',
      });
   }
};
const initData = () => {
   tableData.value.forEach((item: any) => {
      item.isSelect = false; //默认为不选中
      item.parentId = 0;
      item.module.forEach((moduleItem: any) => {
         moduleItem.isSelect = false;
         moduleItem.parentId = item.id;
         moduleItem.type = 'info';   
      });
   });
};

// 组合搜索按钮的回调
const dialogHandleSearch = (search: string) => {
   dialogKeyword.value = search;
   getObjData();
   multipleTableRefDialog.value!.clearSelection();
   initData();
};

const changeColor = (row: any, item: { id: string; name: string; type: string; isSelect: boolean }) => {
   if (item.type == 'info') {
      item.type = 'success';
      item.isSelect = true;
   } else {
      item.type = 'info';
      item.isSelect = false;
   }
   if (row.module.every((item: any) => item.type === 'success')) {
      row.isSelect = true;
      multipleTableRefDialog.value!.toggleRowSelection(row, row.isSelect);
   } else if (row.module.every((item: any) => item.type === 'info')) {
      row.isSelect = false;
      multipleTableRefDialog.value!.toggleRowSelection(row, row.isSelect);
   } else if (row.module.some((item: any) => item.type === 'info')) {
      row.isSelect = '';
   }
};
const selectFun = (selection: any, row: any) => {
   setRowIsSelect(row);
};
const setRowIsSelect = (row: any) => {
   //当点击父级复选框时,当前的状态可能为未知状态,所以当前行状态设为false并选中,即可实现子级点全选效果
   if (row.isSelect == '') {
      row.isSelect = false;
      row.module.forEach((item: any) => {
         item.type = 'success';
      });
      multipleTableRefDialog.value!.toggleRowSelection(row, true);
   }
   row.isSelect = !row.isSelect;
   if (row.module && row.module.length > 0) {
      row.module.forEach((item: any) => {
         item.isSelect = row.isSelect;
         if (row.isSelect) {
            item.type = 'success';
         } else {
            item.type = 'info';
         }
      });
   }
};

// 检测表格数据是否全选
const oneProductIsSelect = ref();
const checkIsAllSelect = () => {
   oneProductIsSelect.value = [];
   tableData.value.forEach((item: any) => {
      oneProductIsSelect.value.push(item.isSelect);
   });
   //判断一级是否是全选.如果一级全为true,则设置为取消全选,否则全选
   let isAllSelect = oneProductIsSelect.value.every((selectStatusItem: any) => {
      return true == selectStatusItem;
   });
   return isAllSelect;
};
const selectAllFun = (selection: any) => {
   let isAllSelect = checkIsAllSelect();
   tableData.value.forEach((item: any) => {
      item.isSelect = isAllSelect;
      multipleTableRefDialog.value!.toggleRowSelection(item, !isAllSelect);
      selectFun(selection, item);
   });
};
// 表格行样式 当当前行的状态为不明确状态时,添加样式,使其复选框为不明确状态样式
const rowClassNameFun = ({ row }: { row: any }) => {
   if (row.isSelect === '') {
      return 'indeterminate';
   }
};

// 表格标题样式 当一级目录有为不明确状态时,添加样式,使其全选复选框为不明确状态样式
const headerRowClassName = ({ row }: { row: any }) => {
   let oneProductIsSelect: any = [];
   tableData.value.forEach((item: any) => {
      oneProductIsSelect.push(item.isSelect);
   });
   if (oneProductIsSelect.includes('')) {
      return 'indeterminate';
   }
   return '';
};

const dialogSelectChange = (value: any) => {
   selectDataArr.value = value;
};
const handleSizeChange = (val: number) => {
   dialogPageSize.value = val;
   getObjData();
};

// 定义组件发出的事件
const emit = defineEmits(['taskObj', 'closeDialog']);
let groups: any = [];
let groupName:any=[]
const confirmTask = () => {
   // groups = [];
   tableData.value.forEach((item: any) => {
      if (item.isSelect || item.isSelect === '') {
         let groupItems: { name: string; module: any[] } = {
            name: item.name,
            module: [],
         };
         let groupItem: { group_id: number; module_id: number[] } = {
            group_id: item.id,
            module_id: [],
         };
         item.module.forEach((moduleItem: any) => {
            if (moduleItem.isSelect) {
               groupItems.module.push({ name: moduleItem.name });
            }
         });
         item.module.forEach((moduleItem: any) => {
            if (moduleItem.isSelect) {
               groupItem.module_id.push(moduleItem.id);
            }
         });
         groups.push(groupItem);
         groupName.push(groupItems);

      }
   });
   if (groups.length > 0) {
      ElMessage({
         message: '关联成功!',
         type: 'success',
      });
      // console.log(props.paramsDataDialogId);
      
      emit('taskObj', groups,groupName);

      dialogVisibleTask.value = false;
      groups=[]
      groupName=[]
      
   } else {
      ElMessage({
         message: '请选择任务对象!',
         type: 'error',
      });
   }
};

watch(
   () => props.isShowDialog,
   (val) => {
      dialogVisibleTask.value = val;
   },
   { immediate: true },
);

watchEffect(()=>{
   if (props.drawerState==false) {
      isShow.value = true;
   }
   if (props.paramsDataDialogId!==0) {
   setTimeout(()=>{
      multipleTableRefDialog.value!.clearSelection();
      initData();
   },100)
  
}
})
const closeDialog = () => {
   emit('closeDialog', false);
};
</script>

以上代码是自己封装的一个子组件 是由父组件传的渲染数据

受到博客Element Table 表格树形结构多选框选中父级时会选中子级(递归多级)_element table tree 选择子级-CSDN博客的启发做出改变

学习共勉

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
二级表格树形结构可以通过以下步骤给el-table赋值: 1. 定义表格的列属性,包括树形结构的属性,例如节点ID和子节点ID。 2. 定义表格的数据源,包括树形结构的数据,例如节点ID和子节点ID对应的值。 3. 在el-table组件中使用scoped slot定义每个单元格的内容,根据树形结构的属性来渲染每个节点的内容。 4. 使用归的方式来渲染树形结构的节点,根据节点的层级关系来确定每个节点的缩进和样式。 以下是一个示例代码,演示如何给el-table赋值二级表格树形结构: ```html <template> <el-table :data="tableData" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"> <el-table-column label="名称" prop="name"> <template slot-scope="{ row }"> <span :style="{ 'padding-left': (row.level - 1) * 20 + 'px' }">{{ row.name }}</span> </template> </el-table-column> <el-table-column label="类型" prop="type"></el-table-column> <el-table-column label="大小" prop="size"></el-table-column> </el-table> </template> <script> export default { data() { return { tableData: [ { id: 1, name: '目录1', type: '目录', size: '', children: [ { id: 2, name: '文件1', type: '文件', size: '10KB', hasChildren: false }, { id: 3, name: '目录2', type: '目录', size: '', children: [ { id: 4, name: '文件2', type: '文件', size: '20KB', hasChildren: false } ], hasChildren: true } ], hasChildren: true } ] }; } }; </script> ``` 在上面的代码中,el-table组件的tree-props属性指定了树形结构的属性,即children表示子节点的数组,hasChildren表示是否有子节点。在el-table-column组件中,使用scoped slot定义了每个单元格的内容,并且根据节点的层级关系来确定每个节点的缩进和样式。最后,在data()函数中定义了表格的数据源,包括树形结构的数据。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值