前言
针对移动端的部门人员选择树组件、网上一直没有找到好用的顺手的于是就萌生了自己封装一个的想法。效果如下:
并没有很完善系统的去测试,有可能存在bug
下面分享几个开发过程中用到的针对处理树形数据分方法,如果想要源代码的可以关注**IMyself**后续会在此发布。
树形数据示例
const treeData = [
{
id: 1,
name: '部门A',
children: [
{
id: 2,
name: '子部门A1',
children: [
{id: 4, name: '子部门A1-1'},
{id: 5, name: '子部门A1-2'}
]
},
{
id: 3, name: '子部门A2'
}
]
}
];
根据id查找出节点
const filterNode=(data, id) {
const result = [];
data.forEach(item => {
if (item.id === id) {
result.push(item);
}
if (item.children) {
result.push(...filterNode(item.children, id));
}
});
return result;
}
// 使用示例
const filtered = filterNode(treeData, 5);
//[
{id: 5, name: '子部门A1-2'}]
根据id查找出节点并向上获取所有父节点
- 方法一
const filterNode=(tree, nodeId)=> {
let result;
function search(nodes) {
for (let node of nodes) {
if (node.id === nodeId) {
result = node;
return true;
}
if (node.children) {
if (search(node.children)) {
node.children = [result];
result = node;
return true;
}
}
}
return false;
}
search(tree);
return [result];
}
// 使用示例
const filtered = filterNode(treeData, 5);
//result:
[
{
"id": 1,
"name": "部门A",
"children": [
{
"id": 2,
"name": "子部门A1",
"children": [
{
"id": 5,
"name": "子部门A1-2"
}
]
}
]
}
]
- 方法二
const filterNode = (tree, nodeId) =>{
for (const node of tree) {
if (node.id === nodeId) {
return node;
}
if (node.children) {
const found = filterNode(node.children, nodeId);
if (found) {
return {
...node,
children: [found]
};
}
}
}
return null;
}
//返回数组
const filterNode=(tree, nodeId)=> {
let result = [];
for (const node of tree) {
if (node.name === nodeId) {
result.push(node);
}
if (node.children) {
const found = filterNode(node.children, nodeId);
if (found.length) {
result.push({
...node,
children: found,
});
}
}
}
return result;
}
获取所有选中的值
let treeValue=[]
getSelectData(list = treeData, isRoot = true) {
list.forEach((item) => {
if (!item.isParent && item.selected) {
treeValue.push({
name: item.name,
id: item.id,
});
}
if (item.children && item.children.length) {
this.getSelectData(item.children, false);
}
});
if (isRoot) {
return treeValue;
}
},
获取选中的最底层节点的数量
const getSelectedLeafNodesCount=(treeData)=> {
let count = 0;
function traverse(node) {
if (node.children && node.children.length > 0) {
node.children.forEach(child => traverse(child));
} else if (node.selected) {
count++;
}
}
treeData.forEach(node => traverse(node));
return count;
}
判断父节点下所有子节点是否全部选中
const isAllChildrenChecked=(node)=> {
if (!node.children) {
return node.selected;
}
return node.children.every(this.isAllChildrenChecked);
}
设置节点选中(用于数据回显)
const setTreeData=(treeData, selectedIds)=> {
treeData.forEach((node) => {
if (node.children) {
this.setTreeData(node.children, selectedIds);
}
if (selectedIds.find((i) => i.id == node.id)) {
node.selected = true;
}
if (node.children && node.children.every((child) => child.selectedDept)) {
node.selected = true;
}
});
}
判断节点是否是最外层根节点
const isRoot=(node, treeData)=> {
// 判断是否在 treeData 数组中
if (!treeData.includes(node)) {
return false;
}
// 遍历 treeData 数组,判断是否有父节点
for (let n of treeData) {
if (n.children && n.children.includes(node)) {
return false;
}
}
return true;
},
给树形结构数据加上层级变量
const treeData=[
{
"name": "公司",
"children": [
{
"name": "CEO",
"children": [
{
"name": "财务部",
"children": [
{"name": "会计"},
{"name": "出纳"}
]
},
{
"name": "人事部",
"children": [
{"name": "招聘"},
{"name": "培训"}
]
}
]
},
{
"name": "COO",
"children": [
{
"name": "技术部",
"children": [
{"name": "开发"},
{"name": "测试"}
]
},
{
"name": "市场部",
"children": [
{"name": "营销"},
{"name": "策划"}
]
}
]
}
]
}
];
const arrayTreeAddLevel = (array, levelName = 'level', childrenName = 'children') => {
if (!Array.isArray(array)) return []
const recursive = (array, level = 0) => {
level++
return array.map(v => {
v[levelName] = level
const child = v[childrenName]
if (child && child.length) recursive(child, level)
return v
})
}
return recursive(array)
}
const newData = arrayTreeAddLevel(treeData)
console.log(newData);
// newData
[
{
"name": "公司",
"children": [
{
"name": "CEO",
"children": [
{
"name": "财务部",
"children": [
{
"name": "会计",
"level": 4
},
{
"name": "出纳",
"level": 4
}
],
"level": 3
},
{
"name": "人事部",
"children": [
{
"name": "招聘",
"level": 4
},
{
"name": "培训",
"level": 4
}
],
"level": 3
}
],
"level": 2
},
{
"name": "COO",
"children": [
{
"name": "技术部",
"children": [
{
"name": "开发",
"level": 4
},
{
"name": "测试",
"level": 4
}
],
"level": 3
},
{
"name": "市场部",
"children": [
{
"name": "营销",
"level": 4
},
{
"name": "策划",
"level": 4
}
],
"level": 3
}
],
"level": 2
}
],
"level": 1
}
]