Svelte中实现列表的显示/隐藏切换
在Svelte中实现子菜单展开/折叠的正确方式
Svelte的核心是用响应式状态驱动DOM,不用像原生JS那样手动查询和操作元素。针对你的需求,只需要给每个子项维护一个展开状态,再通过条件渲染控制菜单显示即可,具体步骤如下:
1. 定义响应式状态
在组件脚本中添加一个对象,用来记录每个子项的展开状态(key为子项的id,值为布尔值):
<script> import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); // 记录每个子项的展开状态,初始为空,点击后自动添加对应id的状态 let expanded = {}; </script>
2. 修改模板逻辑
给按钮添加点击事件
点击按钮时切换对应子项的展开状态,同时阻止事件冒泡避免触发父级链接的点击:
<button on:click={(e) => { e.stopPropagation(); expanded[child.id] = !expanded[child.id]; }}> <i class="chevron-down" class:rotated={expanded[child.id]}></i> </button>
控制子菜单的显示
通过{#if}指令,只有当子项处于展开状态且有子菜单时,才渲染对应的ul:
{#if child.children?.length > 0 && expanded[child.id]} <ul class="this-one"> {#each child.children as grandChild} <li> <a href={grandChild.route.path} on:click={() => dispatch('click')}> {grandChild.name} </a> </li> {/each} </ul> {/if}
完整修改后的代码
<script> import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); let expanded = {}; </script> <ul> {#each item.children as child (child.id)} <li> <div> <a href={child.route.path} on:click={() => dispatch('click')}> <span>{child.name}</span> </a> {#if child.children?.length > 0} <button on:click={(e) => { e.stopPropagation(); expanded[child.id] = !expanded[child.id]; }}> <i class="chevron-down" class:rotated={expanded[child.id]}></i> </button> {/if} </div> {#if child.children?.length > 0 && expanded[child.id]} <ul class="this-one"> {#each child.children as grandChild} <li> <a href={grandChild.route.path} on:click={() => dispatch('click')}> {grandChild.name} </a> </li> {/each} </ul> {/if} </li> {/each} </ul> <style> /* 可选:给箭头添加旋转动画 */ .chevron-down { transition: transform 0.2s ease; } .rotated { transform: rotate(180deg); } </style>
关键思路说明
- 抛弃原生JS“找DOM→改样式”的思路,转而用状态描述DOM应该呈现的样子,Svelte会自动处理DOM更新。
- 用对象
expanded跟踪每个子项的状态,因为循环中的每个子项是独立的,不能用单个布尔变量控制所有项。 e.stopPropagation()是可选的,用来防止点击按钮时触发父级<a>标签的点击事件,根据你的业务需求决定是否保留。
内容的提问来源于stack exchange,提问作者Asbestus Bonitas
相关产品推荐
相关产品推荐

