You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:06:09