前言
我是用的版本是:
官方给的例子中只是一个单纯的展示,但实际需求中可能会有一些其他需求,比如新增、修改。
然后遇到了各种问题,因此记录一下。
记录
: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>