Svelte中用JavaScript实现点击树结构仅单个div激活聚焦的方案
核心问题排查
你的代码无法实现单选效果的核心原因有2个:
- for循环语法完全错误:
for语句的三个参数顺序应为「初始化语句、循环条件、迭代语句」,你写反了循环条件和迭代语句的位置,导致重置旧元素聚焦状态的逻辑一次都没有执行过 - 每次点击都往
history数组新增当前元素的引用,会导致数组无限膨胀,冗余数据越来越多,遍历效率持续降低
最优修改方案
不需要用历史记录机制实现单选逻辑,只需要维护一个全局的「当前激活元素」引用即可,修改后的代码如下:
<script lang="ts"> import type { FrontendFile } from '$lib/front'; export let content: FrontendFile; // 替换原有history数组,所有递归节点共用同一个激活状态引用 export let activeFile: FrontendFile | null = null; let text = ''; function focusUnfocus() { // 点击已激活元素则取消激活 if (activeFile === content) { activeFile = null; content.status.focused = false; } else { // 先重置上一个激活元素的状态 if (activeFile) { activeFile.status.focused = false; } // 激活当前元素 content.status.focused = true; activeFile = content; } // 同步样式类 text = content.status.focused ? 'font-black' : ''; } </script> <div class="{text}" on:click={focusUnfocus}> {content.name} </div> {#each content.children as sub} <!-- 递归传递激活状态的绑定 --> <svelte:self bind:activeFile content={sub} /> {/each}
调用该组件时,在父层初始化activeFile即可:
<!-- 父组件调用示例 --> <Tree content={rootFile} bind:activeFile={null} />
临时兼容方案
如果你一定要保留原有的history逻辑,只需要修正for循环的语法即可生效,但不推荐长期使用该方案:
// 修正后可以正常遍历的for循环 for (let i=0; i < history.length; i++) { history[i].status.focused = false; }
内容的提问来源于stack exchange,提问作者Willem Vanhulle
相关产品推荐
相关产品推荐

