Svelte中使用svelte:self实现嵌套循环获取子数据的可行性
关于Svelte中递归渲染菜单的问题
问题描述
我想知道能不能用svelte:self来获取children.service1和children.sublinks,还是应该选择递归或多重循环的方式?另外我已经尝试了一种实现,但觉得可以优化。
原始数据
let mainMenuLinks = [ { name: 'Services', link: '/services', children: [ { service1: 'Auditng & Assurance', icon: 'fa fa-check', link: '/services/audit', caption: 'We provide a full range of audit and assurance services to a wide range of clients', sublinks: [ { name: 'Compliance Audit', link: '/services/audit/compliance' }, { name: 'Financial Audit', link: '/services/audit/financial' }, ] }, { service2: 'Taxation', icon: 'fa fa-calculator', link: '/services/taxation', caption: 'We provide a full range of audit and assurance services to a wide range of clients', sublinks: [ { name: 'Corporate Tax', link: '/services/taxation/corporate' }, { name: 'Individual Tax', link: '/services/taxation/individual' }, ] } ] } ];
现有实现代码
<script> export let links; </script> {#each links as link} <h3> {link.name} </h3> {#each link.children as item, index} <h5> {item[`service${index+1}`]} </h5> {#each item.children as i} <p> {i.name} </p> {/each} {/each} {/each}
解决方案
1. 先统一数据结构(关键优化点)
你的原始数据结构有个明显问题:子项用service1、service2这种动态键名,子链接用sublinks,和父级的name、children命名不统一,导致渲染时要动态拼接键名,既麻烦又容易出错。建议改成统一格式:
- 所有层级的项都用
name存标题 - 子项列表统一用
children命名(替换原来的sublinks)
修改后的数据:
let mainMenuLinks = [ { name: 'Services', link: '/services', children: [ { name: 'Auditng & Assurance', icon: 'fa fa-check', link: '/services/audit', caption: 'We provide a full range of audit and assurance services to a wide range of clients', children: [ { name: 'Compliance Audit', link: '/services/audit/compliance' }, { name: 'Financial Audit', link: '/services/audit/financial' }, ] }, { name: 'Taxation', icon: 'fa fa-calculator', link: '/services/taxation', caption: 'We provide a full range of tax services to a wide range of clients', children: [ { name: 'Corporate Tax', link: '/services/taxation/corporate' }, { name: 'Individual Tax', link: '/services/taxation/individual' }, ] } ] } ];
2. 用svelte:self实现递归组件(最优方案)
svelte:self完全可行,而且是Svelte官方推荐的递归组件实现方式,比多重循环更优雅,能轻松处理任意层级的菜单,以后扩展层级也不用改组件代码。
创建一个Menu.svelte组件:
<script> export let items; </script> {#each items as item} <div class="menu-item"> <!-- 渲染当前项的标题和链接 --> {#if item.link} <a href={item.link} class="menu-link"> {#if item.icon} <i class={item.icon}></i> {/if} {item.name} </a> {:else} <span class="menu-title">{item.name}</span> {/if} <!-- 如果有子项,递归渲染 --> {#if item.children && item.children.length > 0} <div class="submenu"> <svelte:self items={item.children} /> </div> {/if} </div> {/each}
3. 使用组件
在父组件中引入并使用这个菜单组件:
<script> import Menu from './Menu.svelte'; let mainMenuLinks = [/* 上面修改后的数据 */]; </script> <Menu items={mainMenuLinks} />
为什么这比多重循环好?
- 代码更简洁,逻辑清晰,避免了多层嵌套的
{#each}循环 - 支持任意层级的菜单扩展,不用因为加了新层级而修改组件
- 数据结构统一后,维护成本更低,不容易出现键名拼接错误
如果实在不想修改原始数据结构,也可以用svelte:self,但需要在组件里处理动态键名(比如取item[Object.keys(item).find(k => k.startsWith('service'))]来获取标题,把sublinks作为子项),但这种方式不推荐,因为数据结构不规范会增加后续维护的复杂度。
内容的提问来源于stack exchange,提问作者jeff
相关产品推荐
相关产品推荐

