El-table 懒加载表格中新增、删除遇到的问题

前言

我是用的版本是:
在这里插入图片描述
官方给的例子中只是一个单纯的展示,但实际需求中可能会有一些其他需求,比如新增、修改。
然后遇到了各种问题,因此记录一下。

记录

:tree-props="{ children: 'children', hasChildren: 'hasChildren' }",先说一下配置
从下图可以看到,懒加载方法只执行了一次。当你手动闭合再重新展开后并没有重新执行懒加载方法。
懒加载的判断是:

  • hasChildren为true,有小箭头,有小箭头才有加载的前提
  • 有加载前提后,再判断children有没有值,无值则执行

最开始时由于子级是没有数据的,因此展开时执行了懒加载;当子数据有值后,就不会再执行懒加载。

注意:这里是手动闭合再展开,而不是执行懒加载代码,这个后面会用到。
在这里插入图片描述

问题1

const loadTreeData = (row, treeNode, resolve) => {
    console.log('执行懒加载了');
    // setTimeout 相当于执行查询接口
    setTimeout(() => {
        const data = [
            {
                id: 2,
                date: '2023-07-02',
                name: 'no_2',
                address: '上海',
                children: [],
                hasChildren: false
            }
        ];
        // 添加父级节点,如果后台返回了父级id(父级id正确),不需要下面的操作
        data.forEach(item => {
            item.parentId = row.id;
        });
        // resolve 必须执行
        resolve(data);
        console.log('数据是:', row);
    }, 1000);
};

这是懒加载方法,正常懒加载执行完,页面上已经显示了子级数据,这时数据也已经变化了,但是确实这样的:可以看到children里面是空的
在这里插入图片描述
解决

 resolve(data);
 row.children = data;
 console.log('数据是:', row);

在这里插入图片描述
这个有什么作用呢?
1、比如说层级,需要递归计算吧,没有数据怎么计算。这里不能后端给,比如你删除了一个数据,层级需要重新计算更新。
2、后面新增时会用到。

问题2

新增的数据不显示,如果没有 row.children = data; 会出现下面的问题
新增了一条数据:1是页面上根本没有显示出来;2是children里的数据只有新增加的这条
在这里插入图片描述
解决

加上 row.children = data;
在这里插入图片描述

问题3

删除后,tableData里的数据已经删除了,但是页面未更新
在这里插入图片描述
这个比较难处理,你需要在删除后执行一下懒加载方法页面才会更新

定义一个map,将懒加载方法执行时的参数都保存起来

// 定义一个map
const lazyTreeData = new Map();

const loadTreeData = (tree, treeNode, resolve) => {
    console.log('执行懒加载了');
    // 保存参数
    lazyTreeData.set(row.id, [tree, treeNode, resolve]);
    // setTimeout 相当于执行查询接口
    setTimeout(() => {
        const data = [
            {
                id: 2,
                date: '2023-07-02',
                name: 'no_2',
                address: '上海',
                children: [],
                hasChildren: false
            }
        ];
        // 添加父级节点,如果后台返回了父级id(父级id正确),不需要下面的操作
        data.forEach(item => {
            item.parentId = row.id;
        });
        // resolve 必须执行
        resolve(data);
        row.children = data;
        console.log('数据是:', row);
    }, 1000);
};
const delChild = row => {
    // 查找父级节点
    const parent = findParent(tableData.value, row.parentId);
    if (parent) {
        parent.children = parent.children.filter(e => e.id !== row.id);
        console.log('删除后的数据:', tableData.value);
        // 刷新界面
        const [tree, treeNode, resolve] = lazyTreeData.get(row.id);
        loadTreeData(tree, treeNode, resolve);
    }
};

这里存在另一个问题,就是执行懒加载方法时什么时候查询接口,什么时候不查询

// 删除
const delChild = row => {
    // 查找父级节点
    const parent = findParent(tableData.value, row.parentId);
    if (parent) {
        parent.children = parent.children.filter(e => e.id !== row.id);
        console.log('删除后的数据:', tableData.value);
        // 刷新界面
        const [tree, treeNode, resolve] = lazyTreeData.get(parent.id);
        // 记录一下子数据
        newChildren.value = _.cloneDeep(parent.children);
        if (newChildren.value.length == 0) {
            // 如果用户想要全部删除,这时hasChildren设置为false就不会执行懒加载方法
            tableData.value[0].hasChildren = false;
            // 这里要注意,hasChildren = false时只是无箭头了。如果执行loadTreeData,还是会执行的
        } else {
            loadTreeData(tree, treeNode, resolve);
        }
    }
};

// 懒加载方法
const loadTreeData = (row, treeNode, resolve) => {
    console.log('执行懒加载了');
    // 保存参数
    lazyTreeData.set(row.id, [row, treeNode, resolve]);
    // setTimeout 相当于执行查询接口
    if (newChildren.value.length == 0) {
        // 正常的加载数据
        setTimeout(() => {
            const data = [
                {
                    id: 2,
                    date: '2023-07-02',
                    name: 'no_2',
                    address: '上海',
                    children: [],
                    hasChildren: false
                }
            ];
            // 添加父级节点,如果后台返回了父级id(父级id正确),不需要下面的操作
            data.forEach(item => {
                item.parentId = row.id;
            });
            // resolve 必须执行
            resolve(data);
            row.children = data;
            console.log('数据是:', row);
        }, 1000);
    } else {
        // 删除后执行的,用于刷新界面
        resolve(newChildren.value);
        row.children = newChildren.value;
        // 清空newChildren,避免影响其他层级的懒加载
        newChildren.value = [];
    }
};

完整代码及效果

效果
在这里插入图片描述
代码

<template>
    <div>
        <!-- 这里默认不展开全部,如果数据量多的话会有问题 -->
        <el-table :data="tableData" style="width: 100%" row-key="id" border lazy :default-expand-all="false"
            :load="loadTreeData" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
            <el-table-column prop="date" label="Date" />
            <el-table-column prop="name" label="Name" />
            <el-table-column prop="address" label="Address" />
            <el-table-column label="操作">
                <template #default="{ row, $index }">
                    <div>
                        <el-button type="primary" ="addChild(row)">新增</el-button>
                        <el-button type="primary" :disabled="$index == 0" ="delChild(row)">删除</el-button>
                    </div>
                </template>
            </el-table-column>
        </el-table>
    </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import _ from 'lodash';
const tableData = ref([
    {
        id: 1,
        date: '2023-07-01',
        name: 'no_1',
        address: '北京',
        children: [],
        hasChildren: true,
        parentId: -1
    }
]);
// 用于存储懒加载的入参
const lazyTreeData = new Map();
// 用于存储子级数据
const newChildren = ref([]);

// 懒加载方法
const loadTreeData = (row, treeNode, resolve) => {
    console.log('执行懒加载了');
    // 保存参数
    lazyTreeData.set(row.id, [row, treeNode, resolve]);
    // setTimeout 相当于执行查询接口
    if (newChildren.value.length == 0) {
        // 正常的加载数据
        setTimeout(() => {
            const data = [
                {
                    id: 2,
                    date: '2023-07-02',
                    name: 'no_2',
                    address: '上海',
                    children: [],
                    hasChildren: false
                }
            ];
            // 添加父级节点,如果后台返回了父级id(父级id正确),不需要下面的操作
            data.forEach(item => {
                item.parentId = row.id;
            });
            // resolve 必须执行
            resolve(data);
            row.children = data;
            console.log('数据是:', row);
        }, 1000);
    } else {
        // 删除后执行的,用于刷新界面
        resolve(newChildren.value);
        row.children = newChildren.value;
        // 清空newChildren,避免影响其他层级的懒加载
        newChildren.value = [];
    }
};

// 新增方法
const addChild = row => {
    let id = new Date().getTime();
    row.children.push({
        id: id,
        date: new Date().toLocaleString(),
        name: 'no_' + id,
        address: '北京',
        children: [],
        hasChildren: false,
        parentId: row.id
    });
    console.log('新增后的数据:', tableData.value);
};
// 删除
const delChild = row => {
    // 查找父级节点
    const parent = findParent(tableData.value, row.parentId);
    if (parent) {
        parent.children = parent.children.filter(e => e.id !== row.id);
        console.log('删除后的数据:', tableData.value);
        // 刷新界面
        const [tree, treeNode, resolve] = lazyTreeData.get(parent.id);
        // 记录一下子数据
        newChildren.value = _.cloneDeep(parent.children);
        if (newChildren.value.length == 0) {
            // 如果用户想要全部删除,这时hasChildren设置为false就不会执行懒加载方法
            tableData.value[0].hasChildren = false;
        } else {
            loadTreeData(tree, treeNode, resolve);
        }
    }
};

// 递归查找父级
const findParent = (tableData, parentId) => {
    for (let i = 0; i < tableData.length; i++) {
        if (tableData[i].id == parentId) {
            return tableData[i];
        } else {
            if (tableData[i].children) {
                return findParent(tableData[i].children, parentId);
            }
        }
    }
    return undefined;
};
</script>

<style lang="scss" scoped></style>
Element UI的`el-table`组件,如果你想在已有表格的基础上添加新的数据行,你可以使用`rowspan`和`expanded-row-keys`属性来动态渲染。这里是一个简单的步骤说明: 1. 首先,确保你已经初始化了一个`el-table`实例,并且它有一个`data`属性来存储原始数据。 ```html <template> <el-table :data="tableData" ref="table"> <!-- 表头部分 --> <el-table-column type="index"></el-table-column> <!-- 其他列 --> </el-table> </template> <script> export default { data() { return { tableData: [] // 初始的数据数组 }; }, methods: { addNewRow(newData) { // 添加新数据 this.tableData.push(newData); // 如果你想让新添加的行默认展开,可以这样做: this.$refs.table.setCurrentKey(newData.key || newData.id); // 假设你有key或id字段 // 或者使用 `expanded-row-keys` 来控制展开状态 // 这里假设`expandedRowKeys`已经在data或方法定义过 if (!this.expandedRowKeys.includes(newData.key)) { this.expandedRowKeys.push(newData.key); } } } }; </script> ``` 在`methods`,`addNewRow`方法接收新的数据对象`newData`,然后将其追加到`tableData`数组。如果希望新添加的行立即展开,可以通过`setCurrentKey`方法设置当前展开的行。 如果你需要在表格的特定位置插入新行,或者有更多的数据操作需求,你可能需要根据具体业务场景调整代码。记得`el-table`的更新是异步的,所以在添加数据后,可能需要手动触发一次表格的更新,例如: ```javascript this.$nextTick(() => { this.$refs.table.doLayout(); }); ``` 如果你想要详细了解如何监听数据变化后自动刷新表格,或者如何处理分页、懒加载等情况,可以继续提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无知的小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值