纯JavaScript递归处理嵌套数组
// 递归遍历嵌套数组的通用函数
function traverseNestedArray(arr, callback, parent = null, level = 0) {
if (!Array.isArray(arr)) return
arr.forEach((item, index) => {
// 对当前项执行回调
callback(item, index, parent, level)
// 如果有子数组,递归处理
if (item.children && Array.isArray(item.children) && item.children.length > 0) {
traverseNestedArray(item.children, callback, item, level + 1)
}
})
}
// 使用示例
const data = [
{
id: 1,
name: '节点1',
children: [
{ id: 11, name: '子节点1-1' }
]
}
]
traverseNestedArray(data, (item, index, parent, level) => {
console.log(`Level ${level}: ${item.name}, 父节点: ${parent?.name || '无'}`)
})
// 输出:
// Level 0: 节点1, 父节点: 无
// Level 1: 子节点1-1, 父节点: 节点1
vue页面遍历未知层级的嵌套数组
RecursiveItem.vue
<template>
<div class="recursive-item">
<!-- 当前节点内容 -->
<div class="item-content" @click="toggleExpand">
<span v-if="hasChildren" class="expand-icon">{{ isExpanded ? '▼' : '►' }}</span>
{{ item.title || item.name }}
</div>
<!-- 递归渲染子节点 -->
<transition name="expand">
<div v-if="hasChildren && isExpanded" class="children">
<RecursiveItem
v-for="child in item.children"
:key="child.id || child.key"
:item="child"
:level="level + 1"
@update-item="handleUpdateItem"
/>
</div>
</transition>
</div>
</template>
<script>
export default {
name: 'RecursiveItem', // 必须定义name属性以支持递归调用
props: {
item: {
type: Object,
required: true
},
level: {
type: Number,
default: 0
}
},
data() {
return {
isExpanded: false
}
},
computed: {
// 判断是否有子节点
hasChildren() {
return this.item.children && Array.isArray(this.item.children) && this.item.children.length > 0
}
},
methods: {
toggleExpand() {
if (this.hasChildren) {
this.isExpanded = !this.isExpanded
}
},
handleUpdateItem(data) {
// 向上冒泡事件
this.$emit('update-item', data)
}
}
}
</script>
<style scoped>
.recursive-item {
padding-left: 20px;
}
.item-content {
padding: 8px;
cursor: pointer;
border-radius: 4px;
user-select: none;
display: flex;
align-items: center;
}
.item-content:hover {
background-color: #f5f5f5;
}
.expand-icon {
margin-right: 8px;
font-size: 12px;
}
.children {
border-left: 1px dashed #ddd;
margin-left: 10px;
}
/* 展开/折叠动画 */
.expand-enter-active,
.expand-leave-active {
transition: all 0.3s ease;
overflow: hidden;
}
.expand-enter-from,
.expand-leave-to {
opacity: 0;
max-height: 0;
}
.expand-enter-to,
.expand-leave-from {
opacity: 1;
max-height: 1000px;
}
</style>
父组件使用:
<template>
<div class="nested-tree">
<h3>嵌套数组展示</h3>
<RecursiveItem
v-for="rootItem in nestedData"
:key="rootItem.id || rootItem.key"
:item="rootItem"
@update-item="handleUpdateItem"
/>
</div>
</template>
<script>
import RecursiveItem from './RecursiveItem.vue'
export default {
name: 'NestedTree',
components: {
RecursiveItem
},
data() {
return {
nestedData: [
{
id: 1,
name: '分类1',
children: [
{
id: 11,
name: '子分类1-1',
children: [
{ id: 111, name: '子子分类1-1-1' },
{ id: 112, name: '子子分类1-1-2' }
]
},
{ id: 12, name: '子分类1-2' }
]
},
{
id: 2,
name: '分类2',
children: [
{ id: 21, name: '子分类2-1' }
]
}
]
}
},
methods: {
handleUpdateItem(data) {
// 处理从子组件传来的更新事件
console.log('更新数据:', data)
// 这里可以根据需要更新nestedData
}
}
}
</script>
<style scoped>
.nested-tree {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
</style>
来源:豆包