vue table 懒加载树形数据时,子节点数据刷新处理

树形数据加载很常用的功能,而且使用场景非常多,但子节点刷新确是个麻烦事

在这里插入图片描述

#树形数据分两种,后端接口天然支持树形。这种非常简单。

<template>
    <div>
      <el-table :data="tableData" style="width: 100%;margin-bottom: 20px;" row-key="id" border default-expand-all
        :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
        <el-table-column prop="date" label="日期" sortable width="180">
        </el-table-column>
        <el-table-column prop="name" label="姓名" sortable width="180">
        </el-table-column>
        <el-table-column prop="address" label="地址">
        </el-table-column>
      </el-table>
  </template>
  <script>
    export default {
      data() {
        return {
          tableData: [{
            id: 1,
            date: '2016-05-02',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1518 弄'
          }, {
            id: 2,
            date: '2016-05-04',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1517 弄'
          }, {
            id: 3,
            date: '2016-05-01',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1519 弄',
            children: [{
                id: 31,
                date: '2016-05-01',
                name: '王小虎',
                address: '上海市普陀区金沙江路 1519 弄'
              }, {
                id: 32,
                date: '2016-05-01',
                name: '王小虎',
                address: '上海市普陀区金沙江路 1519 弄'
            }]
          }, {
            id: 4,
            date: '2016-05-03',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1516 弄'
          }],
      },
    }
}
</script>

正常数据量不大,直接接口就能把树形数据放回,万事大吉,刷新接口,即可完成子节点的刷新

前端页面需要懒加载,接口不支持

有些时候,接口是不可能把所有子节点的数据返回的,那么只能点击一个父级加载一个,而且懒加载,比较省资源。那么就必须要解决刷新的问题。

<template>
    <div>
        <el-table :data="tableData1" style="width: 100%" row-key="id" border lazy :load="load" ref="table"
            :tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
            <el-table-column prop="date" label="日期" width="180">
            </el-table-column>
            <el-table-column prop="name" label="姓名" width="180">
            </el-table-column>
            <el-table-column prop="address" label="地址">
            </el-table-column>
        </el-table>
    </div>
</template>
<script>
export default {
    data() {
        return {
            tableData1: [{
                id: 1,
                date: '2016-05-02',
                name: '王小虎',
                address: '上海市普陀区金沙江路 1518 弄'
            }, {
                id: 2,
                date: '2016-05-04',
                name: '王小虎',
                address: '上海市普陀区金沙江路 1517 弄'
            }, {
                id: 3,
                date: '2016-05-01',
                name: '王小虎',
                address: '上海市普陀区金沙江路 1519 弄',
                hasChildren: true
            }, {
                id: 4,
                date: '2016-05-03',
                name: '王小虎',
                address: '上海市普陀区金沙江路 1516 弄'
            }],
            maps: new Map()
        }
    },
    methods: {
        load(tree, treeNode, resolve) {
            getProjectWork({
                page: this.pageParam.page,
                size: this.pageParam.size,
                fid: tree.id,
            }).then((res) => {
                if (res.code == 0) {
                    if (!res.data.list.length) {
                        /*
                            element-ui中table懒加载数据时,如果data是空数组,则不会刷新
                            lazyTreeNodeMap中记录了懒加载节点的子列表数据
                            通过tree.id作为key,将数据存入lazyTreeNodeMap中,因此手动清除缓存数据即可
                        */
                        // 注意:要在el-table组件上绑定ref='table'
                        this.$set(this.$refs.table.store.states.lazyTreeNodeMap, tree.id, [])
                    } else {
                        resolve(res.data.list);
                    }
                    this.map.set(tree.id, { tree, treeNode, resolve });

                }
            });
        },
        // 触发刷新节点方法
        refresh(parentId) {
            // 根据父级id取出对应节点数据
            if (this.maps.get(parentId)) {
                const { tree, treeNode, resolve } = this.maps.get(parentId)
                if (tree) {
                    this.load(tree, treeNode, resolve)
                }
            }
        },
    },
}
</script>

正常配置

  1. 设置 Table 的 lazy 属性为 true
  2. 加载函数 load
  3. 指定 row 中的 hasChildren字段来指定哪些行是包含子节点

以上懒加载必备属性。

解决懒加载刷新

  1. 定义maps字段
this.map.set(tree.id, { tree, treeNode, resolve });
  1. 每次点击打开父节点时,把参数存储下来。

直接在加载子节点属性的方法内补充

 this.map.set(tree.id, { tree, treeNode, resolve });
  1. 重点,当数据为空时,需要手动处理
this.$set(this.$refs.table.store.states.lazyTreeNodeMap, tree.id, [])
  1. 补充一个刷新的方法

此方法就是直接在请求一次加载子节点

 refresh(parentId) {}

后面的工作就简单了

  1. 删除数据了,直接访问一下 refresh 方法
  2. 数据修改了,直接访问一下 refresh 方法
  3. 批量数据删除了,那就一个个去请求 refresh 方法

注意点:

maps 存储的是以父节点id为key的对象,触发的时候也是用父节点去触发。

### 解决 Vue3 Element Plus el-table 树形结构数据刷新方法 在 Vue3 的开发环境中,当使用 `el-table` 屉组件展示树形数据,如果遇到子集数据无法正常显示或者刷新的问题,通常是因为以下几个原因: #### 1. **字段映射配置** 确保 `el-table` 的属性设置正确。特别是对于树形数据的支持,需要通过 `row-key` 和 `children` 属性来指定每一行的唯一键以及子节点数据字段名称。 ```javascript <el-table :data="tableData" row-key="id" // 设置每行唯一的 key :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"> // 配置 treeProps </el-table> ``` 上述代码片段中设置了 `row-key` 来定义唯一标识符,并通过 `tree-props` 映射了 `children` 和 `hasChildren` 字段[^1]。 --- #### 2. **动态更新数据** 当接口返回新的树形数据并希望表格能够实反映变化,可以通过重新赋值给 `tableData` 或者调用特定的方法触发视图更新。 以下是两种常见的解决方案: ##### (1) 使用响应式对象重写数据 由于 Vue3 默认支持 Proxy 实现的响应式机制,可以直接修改原始数组或替换整个数据源以实现自动更新。 ```javascript const tableData = ref([]); // 定义响应式变量 // 更新数据逻辑 function updateTable(newData) { tableData.value = newData; // 替换旧数据为新数据 } ``` 此方式适用于简单的场景,在大多数情况下可以满足需求。 ##### (2) 手动调用 `setCurrentRow` 或其他 API 某些复杂情况可能需要手动干预 DOM 渲染过程。此可利用 `el-table` 提供的相关实例方法完成操作。 例如: ```javascript nextTick(() => { const tableRef = ref(null); if (tableRef && tableRef.value) { tableRef.value.doLayout(); // 强制重新布局表格 } }); ``` 这里借助 `doLayout()` 方法强制让表格重新计算高度和位置关系,从而达到刷新效果。 --- #### 3. **注意事项** 除了以上提到的技术要点外,还需要注意以下几点事项以防潜在错误发生: - 确认服务器端返回的数据格式完全匹配前端预期; - 如果存在懒加载功能,则需额外处理 `load` 函数回调参数; - 对于大嵌套层次较多的数据集合考虑性能优化措施比如虚拟滚动技术应用等。 --- ### 示例代码 下面给出一个完整的例子演示如何正确初始化及刷新带有父子关联特性的列表项内容: ```html <template> <div> <el-button @click="refreshData()">Refresh Data</el-button> <el-table v-loading="loading" :data="tableData" style="width: 100%" row-key="id" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"> <el-table-column prop="name" label="Name"></el-table-column> </el-table> </div> </template> <script setup lang="ts"> import { ref, nextTick } from 'vue'; let loading = ref(false); let tableData = ref([ { id: 1, name: "Parent", children: [ { id: 2, name: "Child", hasChildren: false }, ], hasChildren: true, }, ]); async function refreshData() { try { loading.value = true; // Simulate fetching new data... await new Promise((resolve) => setTimeout(resolve, 1000)); const updatedData = [ { id: 1, name: "Updated Parent", children: [{ id: 3, name: "New Child", hasChildren: false }], hasChildren: true, }, ]; tableData.value = [...updatedData]; nextTick(() => { console.log('Table refreshed'); }); } finally { loading.value = false; } } </script> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值