0


Naive UI 获取树tree完整选中树结构(通用方法,也适用于其他自定义组件)

截止文章记录前,Naive UI 并未提供直接获取,与选中叶子节点相关的完整树结构数据方法,记录一下前端实现方法。

数据准备:

数据准备:树结构初始数据,选中相关的数据

// 初始树结构数据
let dataSetData = [
    {
        id: '1',
        text: '节点1',
        nodeuuid: '1',
        pnodeId: null,
        children: []
    },
    {
        id: '2',
        text: '节点2',
        nodeuuid: '2',
        pnodeId: null,
        children: [
            {
                id: '2-1',
                text: '节点2-1',
                nodeuuid: '2-1',
                pnodeId: '2',
                children: []
            },
            {
                id: '2-2',
                text: '节点2-2',
                nodeuuid: '2-2',
                pnodeId: '2',
                children: [
                    {
                        id: '2-2-1',
                        text: '节点2-2-1',
                        nodeuuid: '2-2-1',
                        pnodeId: '2-2',
                        children: []
                    }
                ]
            },
            {
                id: '2-3',
                text: '节点2-3',
                nodeuuid: '2-3',
                pnodeId: '2',
                children: []
            }
        ]
    },
    {
        id: '3',
        text: '节点3',
        nodeuuid: '3',
        pnodeId: null,
        children: []
    },
    {
        id: '4',
        text: '节点4',
        nodeuuid: '4',
        pnodeId: null,
        children: []
    },
    {
        id: '5',
        text: '节点5',
        nodeuuid: '5',
        pnodeId: null,
        children: [
            {
                id: '5-1',
                text: '节点5-1',
                nodeuuid: '5-1',
                pnodeId: '5',
                children: []
            },
            {
                id: '5-2',
                text: '节点5-2',
                nodeuuid: '5-2',
                pnodeId: '5',
                children: []
            }
        ]
    }
]

// 选中相关的数据
let datasetCheckedNodes = [
    {
        id: '2',
        text: '节点2',
        nodeuuid: '2',
        pnodeId: null,
        children: [
            {
                id: '2-1',
                text: '节点2-1',
                nodeuuid: '2-1',
                pnodeId: '2',
                children: []
            },
            {
                id: '2-2',
                text: '节点2-2',
                nodeuuid: '2-2',
                pnodeId: '2',
                children: [
                    {
                        id: '2-2-1',
                        text: '节点2-2-1',
                        nodeuuid: '2-2-1',
                        pnodeId: '2-2',
                        children: []
                    }
                ]
            },
            {
                id: '2-3',
                text: '节点2-3',
                nodeuuid: '2-3',
                pnodeId: '2',
                children: []
            }
        ]
    },
    {
        id: '2-3',
        text: '节点2-3',
        nodeuuid: '2-3',
        pnodeId: '2',
        children: []
    },
    {
        id: '2-2',
        text: '节点2-2',
        nodeuuid: '2-2',
        pnodeId: '2',
        children: [
            {
                id: '2-2-1',
                text: '节点2-2-1',
                nodeuuid: '2-2-1',
                pnodeId: '2-2',
                children: []
            }
        ]
    },
    {
        id: '2-2-1',
        text: '节点2-2-1',
        nodeuuid: '2-2-1',
        pnodeId: '2-2',
        children: []
    },
    {
        id: '4',
        text: '节点4',
        nodeuuid: '4',
        pnodeId: null,
        children: []
    },
    {
        id: '5-2',
        text: '节点5-2',
        nodeuuid: '5-2',
        pnodeId: '5',
        children: []
    }
]

**实现步骤,一共四步,如下: **

// 0.设置每个节点唯一标识nodeuuid,相关父节点标识pnodeId(若初始树结构数据每个节点已有唯一标识,相关父节点标识,可跳过该步骤)
// dataSetData = addParentData(res, null)
// 1.设置相关树节点映射
const treeMap = setMap()
// 2.获取所有选中的叶子节点(目的是为了获取所有选中的叶子节点,可使用其他方法获得)
const leafNodes = datasetCheckedNodes.filter(v => v && (!v.children || v.children.length == 0))
// 3.获取所有和子节点相关,被勾选的根父节点集合(包含已勾选和未勾选数据,通过是否勾选标识区分)
const rootNodes = getAllCheckedRootNodes(leafNodes, treeMap)
// 4.删除未选中标识数据,获取重组后的完整树结构数据
const treeData = getCheckedTree(rootNodes, leafNodes)

console.log('重组后的完整树结构数据', treeData)

**实现函数方法如下: **

/**
 * 递归遍历赋值当前节点的父节点,设置每个节点唯一标识nodeuuid,相关父节点标识pnodeId
 * @param treeData 初始树结构数据
 * @param pnodeId 父节点Id
 * @returns treeData 处理后的树结构数据
 */
function addParentData(treeData, pnodeId) {
    for (var i in treeData) {
        treeData[i].scopedSlots = {
            title: 'custom'
        }
        treeData[i].nodeuuid = uuidv4()
        treeData[i].text = treeData[i].text ? treeData[i].text : treeData[i].name
        treeData[i].pnodeId = pnodeId

        if (treeData[i].children && treeData[i].children.length) {
            addParentData(treeData[i].children, treeData[i].nodeuuid)
        }
    }
    return treeData
}

/**
 * 设置相关树节点映射
 * 两种方式:
 * 其一,树组件有提供快捷获取选中和半选数据的方法,可直接调用方法,组装treeMap(推荐)
 * 其二,树组件没有提供快捷获取选中和半选数据的方法,则递归所有初始树结构数据,组装treeMap(较消耗内存,慎用)
 * @returns treeMap  树节点映射
 */
function setMap() {
    let treeMap = {} // 树节点映射
    // ----------------方法一(推荐)-------------------
    // 获取选中的数据
    // const checkedNodes = TreeRef.value.getCheckedData()
    // // 获取半选的数据
    // const indeterminateNodes = TreeRef.value.getIndeterminateData()

    // checkedNodes.options.forEach(node => {
    //     if (node) {
    //         treeMap[node.nodeuuid] = node
    //     }
    // })
    // indeterminateNodes.options.forEach(node => {
    //     if (node) {
    //         treeMap[node.nodeuuid] = node
    //     }
    // })

    // ------------------方法二(较消耗内存,慎用)-------------------
    treeMap = setMap2(dataSetData, treeMap)

    return treeMap
}

/**
 * 递归所有初始树结构数据,组装treeMap
 * @param {*} tree 初始树结构数据
 * @param {*} map 
 * @returns 
 */
function setMap2(tree, map) {
    tree.forEach(node => {
        map[node.nodeuuid] = node
        if (node.children && node.children.length > 0) {
            setMap2(node.children, map)
        }
    })

    return map
}

/**
 * 获取所有和子节点相关,被勾选的根父节点集合(包含已勾选和未勾选数据,通过是否勾选标识区分)
 * @param leafCheckedNodes 所有选中的叶子节点
 * @param treeMap 相关树节点映射(勾选与半勾选)
 * @returns rootNodes  和子节点相关,被勾选的根父节点集合
 */
function getAllCheckedRootNodes(leafCheckedNodes, treeMap) {
    let rootNodes = []
    leafCheckedNodes.forEach(node => {
        // 找到叶子结点的父节点
        let pNode = treeMap[node.pnodeId]
        // 迭代
        while (pNode) {
            // 添加已勾选的标志
            pNode.isChecked = true
            node = pNode
            pNode = treeMap[node.pnodeId]
        }
        // 如果pNode不存在,说明node是根节点
        if (!rootNodes.some(i => i.nodeuuid == node.nodeuuid)) {
            rootNodes.push(node)
        }
    })
    return rootNodes
}
  
/**
 * 删除未选中标识数据,递归获取重组后的完整树结构数据
 * @param rootNodes 跟勾选相关的根节点集合
 * @param checkedLeafNodes 所有选中的叶子节点
 * @returns 
 */
function getCheckedTree(rootNodes, checkedLeafNodes) {
    // 倒序,避免for循环中使用splice后导致index错乱
    for (let i = rootNodes.length - 1; i >= 0; i--) {
        const node = rootNodes[i]
        // 不是叶子节点
        if (node.children && node.children.length > 0) {
            // 检查勾选标志位,true,那么递归,false,那么删除
            if (node.isChecked) {
                getCheckedTree(node.children, checkedLeafNodes)
            } else {
                rootNodes.splice(i, 1)
            }
        } else {
            // 如果是叶子节点,那么检查其是否是勾选节点,是,保留,不是删除
            const flag = checkedLeafNodes.some(n => n.nodeuuid == node.nodeuuid)
            if (!flag) {
                rootNodes.splice(i, 1)
            }
        }
    }
    return rootNodes
}
标签: javascript

本文转载自: https://blog.csdn.net/m0_59983943/article/details/135477157
版权归原作者 半碗杂货铺 所有, 如有侵权,请联系我们删除。

“Naive UI 获取树tree完整选中树结构(通用方法,也适用于其他自定义组件)”的评论:

还没有评论