截止文章记录前,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
版权归原作者 半碗杂货铺 所有, 如有侵权,请联系我们删除。
版权归原作者 半碗杂货铺 所有, 如有侵权,请联系我们删除。