js json多层级取出每个层级的id值

这段代码主要用于遍历一个树形数据结构,收集所有节点的ID,并将它们存储到一个数组中。通过调用getIdListForTree函数,可以递归地访问每个节点及其子节点,将id推入idList数组。最后,打印出包含所有节点ID的列表。

// 源数据
var treeData = []
// id数组
var listId = []
function getIdListForTree (list, idList) {
    Array.isArray(list) && list.forEach((item) => {
        idList.push(item.id)
        getIdListForTree(item.children, idList)
    })
}
getIdListForTree(treeData, listId)
console.log(listId)

<think> 我们面对的问题是如何在多层嵌套数组中获取最里层某个特定(通常通过ID查找),并可能获取其所有父级信息。这在处理树形结构数据时非常常见。 根据引用[1],用户需要根据最里层的id找到它所属的每一层父级。我们需要设计一个递归或循环的方法来遍历多层嵌套数组,直到找到目标id,并记录路径。 引用[3]中提到,在Vue表格中需要根据级联选择器的多选id去匹配一个嵌套三层的数组的第三层id,然后取出名字渲染。这验证了需求:通过id查找并获取相关信息(如名称)以及路径。 引用[4]虽然讲的是修改内部数组对象,但同样涉及到多层嵌套数组的访问,说明在Vue中处理嵌套数组的常见性。 因此,我们将设计一个通用的方法来处理多层嵌套数组的查找,要求: 1. 能够根据最里层id找到对应的项。 2. 能够记录从根到该项目的路径(每一层的父级)。 假设数据结构示例(类似于引用[1]描述的多级嵌套): ```javascript let tree = [ { id: 1, name: 'level1', children: [ { id: 11, name: 'level1-1', children: [ { id: 111, name: 'level1-1-1' }, { id: 112, name: 'level1-1-2' } ] }, { id: 12, name: 'level1-2' } ] }, { id: 2, name: 'level2', children: [ { id: 21, name: 'level2-1' } ] } ]; ``` 我们需要一个函数,输入:数组和要查找的id;输出:一个对象,包含找到的节点和路径数组(路径数组按层级顺序,从根节点到目标节点)。 步骤: 1. 遍历数组的每一项。 2. 如果当前项的id等于目标id,则返回当前项,并记录当前项(作为路径的最后一个节点)。 3. 如果当前项有子节点(例如children数组),则递归查找子节点。 4. 如果递归查找找到了,则将当前项加入到路径中,并返回结果。 注意:可能存在多个同id?这里假设id唯一。 代码实现(JavaScript): ```javascript function findNodePath(nodes, id, path = []) { for (let node of nodes) { // 当前路径记录 let currentPath = [...path, node]; // 注意:这里新建一个数组,避免引用同一数组 // 如果当前节点就是目标节点,返回节点和路径 if (node.id === id) { return { node, path: currentPath }; } // 如果有子节点,递归查找 if (node.children && node.children.length) { let found = findNodePath(node.children, id, currentPath); if (found) { return found; } } } return null; // 没找到 } ``` 在Vue中使用: 假设我们在组件的methods中定义这个方法,然后调用它来获取节点和路径。 例如,在引用[3]的场景中,我们拿到一个id(可能是第三层的id),需要显示它的名字以及可能需要知道它的父级信息(比如显示层级关系),那么我们可以这样: ```javascript methods: { findNode(id) { return findNodePath(this.treeData, id); }, dataHandle(id) { let result = this.findNode(id); if (result) { // 这里可以返回节点名字,或者根据需求返回路径上的名字组合 return result.node.name; } return '未找到'; } } ``` 在模板中,我们遍历editForm.uids(多个id),然后对每个id调用dataHandle方法: ```html <span v-for="id in editForm.uids" :key="id"> {{ dataHandle(id) }} </span> ``` 注意:如果嵌套层级很深或者数据量很大,频繁查找可能影响性能,可以考虑提前建立索引(例如用Map存储id到节点和路径的映射)。 另外,引用[1]要求根据id获取每一层的父级,我们的方法返回的path就是路径数组,从根节点(第一层)到目标节点(最里层)。例如,对于id=111,path数组就是[tree[0], tree[0].children[0], tree[0].children[0].children[0]]。 如果只需要父级的信息而不需要目标节点本身,可以返回path.slice(0, -1)(去掉最后一个,因为最后一个是目标节点)。 总结: 1. 递归遍历数组查找目标节点,并记录路径。 2. 返回包含节点和路径的对象。 3. 在Vue中应用此方法处理数据渲染。 注意事项: - 确保id唯一,否则返回第一个匹配的。 - 性能考虑:如果数据非常大,递归可能导致栈溢出,可考虑使用循环(迭代)代替递归,或者使用尾递归优化(但JavaScript引擎不一定支持尾递归优化)。 - 路径数组中的每个节点是原对象的引用,注意不要意外修改。 完整示例: 假设在Vue组件中: ```html <template> <div> <!-- 渲染表格等 --> <table> <tr> <td>提醒给</td> <td> <span v-for="id in editForm.uids" :key="id"> {{ getNodeName(id) }} <!-- 显示名称 --> </span> </td> </tr> </table> </div> </template> <script> export default { data() { return { treeData: [ /* 上面示例的tree结构 */ ], editForm: { uids: [111, 21] // 示例id数组 } }; }, methods: { findNodePath(nodes, id, path = []) { // 方法实现如上 }, getNodeName(id) { const result = this.findNodePath(this.treeData, id); return result ? result.node.name : '未知'; } } }; </script> ``` 这样,表格中就会显示每个id对应的节点名称。 如果还需要显示层级关系,比如“level1/level1-1/level1-1-1”,则可以修改getNodeName方法: ```javascript getFullPath(id) { const result = this.findNodePath(this.treeData, id); if (result) { return result.path.map(item => item.name).join('/'); } return '未知'; } ``` 然后在模板中使用`getFullPath(id)`即可。 引用[2]是关于JSON多层嵌套的处理,虽然语言是Python,但思路一致:递归解析JSON直到最里层。我们这里用JavaScript在Vue中实现同理。 因此,多层嵌套数组获取最里层某个的方法主要是递归遍历,同时记录路径,直到找到目标。 </think> ### Vue多层嵌套数组获取最里层的方法 在Vue中处理多层嵌套数组获取最里层时,核心是**递归遍历**和**路径记录**。以下是完整解决方案: #### 1. 递归查找方法(核心实现) ```javascript export default { methods: { /** * 在多层嵌套数组中查找目标及其路径 * @param {Array} array 要搜索的嵌套数组 * @param {String|Number} targetId 要查找的目标ID * @param {String} idKey 对象ID的键名(默认为'id') * @param {String} childrenKey 子数组的键名(默认为'children') * @returns {Object} { node: 目标节点, path: 完整路径数组 } */ findNestedItem(array, targetId, idKey = 'id', childrenKey = 'children') { const stack = [...array.map(item => ({ node: item, path: [item] }))]; while (stack.length) { const { node, path } = stack.pop(); // 找到目标节点 if (node[idKey] === targetId) { return { node, path }; } // 继续搜索子节点 if (node[childrenKey]?.length) { stack.push(...node[childrenKey].map(child => ({ node: child, path: [...path, child] // 记录完整路径 }))); } } return null; // 未找到 } } } ``` #### 2. Vue组件应用示例 ```html <template> <div> <!-- 表格中渲染获取的 --> <table> <tr v-for="id in selectedIds" :key="id"> <td>ID: {{ id }}</td> <td>名称: {{ getNameById(id) }}</td> <td>路径: {{ getPathById(id) }}</td> </tr> </table> </div> </template> <script> export default { data() { return { // 示例数据结构(支持任意嵌套深度) nestedData: [ { id: 1, name: "一级", children: [ { id: 11, name: "二级-1", children: [ { id: 111, name: "三级-1" }, { id: 112, name: "三级-2" } ] } ] } ], // 用户选择的ID(来自级联选择器等) selectedIds: [111, 112] }; }, methods: { getNameById(id) { const result = this.findNestedItem(this.nestedData, id); return result ? result.node.name : "未知"; }, getPathById(id) { const result = this.findNestedItem(this.nestedData, id); return result ? result.path.map(item => item.name).join(" → ") : "未找到路径"; }, // 前面定义的findNestedItem方法放在这里 } }; </script> ``` #### 3. 方法特点说明 1. **非递归栈实现**: - 使用`while`循环替代递归,避免调用栈溢出 - 时间复杂度:$O(n)$(n为总节点数) - 空间复杂度:$O(d)$(d为最大深度) 2. **路径记录**: - 返回包含目标节点和完整路径的对象 - 路径格式:`[根节点, 父节点, ..., 目标节点]` 3. **灵活配置**: - 可自定义ID字段名(`idKey`) - 可自定义子数组字段名(`childrenKey`) - 支持任意嵌套深度 #### 4. 使用场景示例 ```javascript // 获取ID=111的完整信息 const result = this.findNestedItem(nestedData, 111); console.log(result); /* 输出: { node: { id: 111, name: "三级-1" }, path: [ { id: 1, name: "一级", ... }, { id: 11, name: "二级-1", ... }, { id: 111, name: "三级-1" } ] } */ // 获取最里层名称 const name = result.node.name; // "三级-1" // 获取父级信息 const parent = result.path[result.path.length - 2]; // 二级节点 ``` #### 5. 实际应用技巧 1. **性能优化**: ```javascript // 提前建立ID映射(适合频繁查询) created() { this.idMap = {}; this.buildIdMap(this.nestedData); }, methods: { buildIdMap(nodes, parentPath = []) { nodes.forEach(node => { const path = [...parentPath, node]; this.idMap[node.id] = { node, path }; if (node.children) this.buildIdMap(node.children, path); }); } } ``` 2. **处理特殊结构**: ```javascript // 当嵌套键名不一致时 findNestedItem(data, 111, 'value', 'subItems') ``` 3. **Vue响应式注意事项**: - 修改找到的节点时使用`Vue.set`确保响应式 ```javascript const result = this.findNestedItem(data, id); if (result) { this.$set(result.node, 'status', 'active'); } ``` #### 6. 替代方案对比 | 方法 | 优点 | 缺点 | |------|------|------| | **递归查找** | 代码简洁 | 深度大时可能栈溢出 | | **栈循环(推荐)** | 无栈溢出风险 | 代码稍复杂 | | **ID映射表** | $O(1)$查询时间 | 初始化耗内存 | | **Lodash_.find** | 无需自行实现 | 增加依赖包大小 | > 在多数场景下,推荐使用栈循环方案,它在性能和安全性间取得最佳平衡[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值