SimpleAdmin手摸手教学之:基于Ant Design Tree组件实现树形结构数据的异步加载

一、说明

当有一个树形结构的数据有非常多个节点的时候,一次性加载所有节点会显得过于臃肿,可能会对性能造成影响,正好Ant Design 的树(Tree)组件支持异步加载,于是我就想把异步加载封装为一个组件,可以减少接口数据返回,点击展开节点,动态加载数据。非常好用!

二、前端实现

需要接收一些值用来数据的初始化和格式化

const props = defineProps({
		//替换treeNode 中 children
		fieldNamesChildren: { type: String, default: 'children' },
		//替换treeNode 中 title
		fieldNamesTitle: { type: String, default: 'title' },
		//替换treeNode 中 key
		fieldNamesKey: { type: String, default: 'id' },
		//初始数据
		treeData: { type: Function, required: true },
		//父Id字段
		parentIdColumn: { type: String, default: 'parentId' },
		//默认顶级父Id值
		topValue: { default: 0 }
	})

以组织树为例,需要异步加载的时候,由tree组件换成lazyTree组件就行

<lazy-tree field-names-title="name" :treeData="loadTreeData" @select="treeSelect"></lazy-tree>

默认需要传treeData属性,也就是去请求后端去获取数据的方法,这个方法需要有一个参数parameter,当展开节点的时候会请求这个方法并带上父ID去查询。

	const loadTreeData = (parameter) => {
		return genTestApi.orgTree(parameter).then((res) => {
			return res
		})
	}

首次加载组件会调用一次获取节点数据方法。

	onMounted(() => {
		let parameter = {} //查询参数
		parameter[props.parentIdColumn] = props.topValue //默认从0开始
		loadTreeData(parameter) //获取数据
	})

点击某个节点会根据节点的key对应的字段,获取下级节点。并添加到节点数据中。

			let parameter = {} //查询参数
			parameter[props.parentIdColumn] = treeNode[props.fieldNamesKey] //获取当前节点的id
			const result = props.treeData(parameter) //调用父组件传递的方法
			if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') {
				result.then((data) => {
					setTimeout(() => {
						treeNode.dataRef[props.fieldNamesChildren] = data
						treeData.value = [...treeData.value]
						resolve()
					}, 500)
				})
			}

三、后端实现

以组织树为例,原来的tree方法需要增加父ID参数来根据父ID获取下级节点

/// <summary>
/// 组织树查询参数
/// 懒加载用
/// </summary>
public class SysOrgTreeInput
{
    /// <summary>
    /// 父Id
    /// </summary>
    public long? ParentId { get; set; }
}

原来的tree方法也要改一改,如果选择器ID不为空则表示是懒加载,只加载子节点。


    /// <inheritdoc />
    public async Task<List<SysOrg>> Tree(List<long> orgIds = null, SysOrgTreeInput treeInput = null)
    {
        long parentId = SimpleAdminConst.Zero;//父级ID
        //获取所有组织
        var sysOrgs = await GetListAsync();
        if (orgIds != null)
            sysOrgs = GetParentListByIds(sysOrgs, orgIds);//如果组织ID不为空则获取组织ID列表的所有父节点
        //如果选择器ID不为空则表示是懒加载,只加载子节点
        if (treeInput != null && treeInput.ParentId != null)
        {
            parentId = treeInput.ParentId.Value;
            sysOrgs = GetSysOrgChildenLazy(sysOrgs, treeInput.ParentId.Value);//获取懒加载下级
        }
        sysOrgs = sysOrgs.OrderBy(it => it.SortCode).ToList();//排序
        //构建组织树
        var result = ConstrucOrgTrees(sysOrgs, parentId);
        return result;
    }
GetSysOrgChildenLazy方法会去根据父ID找到对应的子节点并判断子节点是否有下级节点。
    /// <summary>
    /// 获取组织下级(懒加载)
    /// </summary>
    /// <param name="orgList"></param>
    /// <param name="parentId"></param>
    /// <returns></returns>
    public List<SysOrg> GetSysOrgChildenLazy(List<SysOrg> orgList, long parentId)
    {
        //找下级组织ID列表
        var orgs = orgList.Where(it => it.ParentId == parentId).ToList();
        if (orgs.Count > 0)//如果数量大于0
        {
            var data = new List<SysOrg>();
            foreach (var item in orgs)//遍历组织
            {
                var childen = orgList.Where(it => it.ParentId == item.Id).ToList();//获取子节点
                //遍历子节点
                childen.ForEach(it =>
                {
                    if (!orgList.Any(org => org.ParentId == it.Id)) it.IsLeaf = true;//如果没有下级,则设置为叶子节点
                });
                data.AddRange(childen);//添加子节点);
                data.Add(item);//添加到列表
            }
            return data;//返回结果
        }
        return new List<SysOrg>();
    }

需要在组织实体中加个IsLeaf字段判断是不是叶子节点,如果IsLeaf是true就表示没有子节点了,前端树控件也不会显示小箭头。


    /// <summary>
    /// 设置为叶子节点(设置了loadData时有效)
    /// </summary>
    [SugarColumn(IsIgnore = true)]
    public bool? IsLeaf { get; set; }

四、效果

最后实现效果如下,这里一次请求加载2级节点。

 

posted @ 2023-05-31 13:30  HuTiger  阅读(2117)  评论(1编辑  收藏  举报