在 Svelte 中生成具有多个长选择元素的表单很慢

问题描述 投票:0回答:1

我正在用 Svelte 编写一个应用程序,并且有一个页面,其中有一个显示为表格的值列表。我希望能够编辑这些值,并且其中一个值由

select
元素选择,具有大约 100 个可能的值。

有一个按钮可以在表格显示和表单编辑模式之间切换显示(使用

select
元素)。

问题是,如果有多行创建

select
项目,每个项目都具有相同的 100 个可能的选项值,则 Svelte 需要很长时间才能生成表单(当大约有大约 100 个选项值时,大约需要一整秒才能切换到编辑模式) 15 个
select
元素)。我在同一个应用程序上使用 React 时没有遇到这个问题(我将大部分应用程序从 React 移植到 Svelte),所以我想我做错了什么,或者有一种微妙的方法可以让事情变得更快。 .

这是一个小的工作示例来说明:

<script>
  const pokemonList = ["bulbasaur", "ivysaur", "venusaur", "charmander", "charmeleon", "charizard", "squirtle", "wartortle", "blastoise", "caterpie", "metapod", "butterfree", "weedle", "kakuna", "beedrill", "pidgey", "pidgeotto", "pidgeot", "rattata", "raticate", "spearow", "fearow", "ekans", "arbok", "pikachu", "raichu", "sandshrew", "sandslash", "nidoran-f", "nidorina", "nidoqueen", "nidoran-m", "nidorino", "nidoking", "clefairy", "clefable", "vulpix", "ninetales", "jigglypuff", "wigglytuff", "zubat", "golbat", "oddish", "gloom", "vileplume", "paras", "parasect", "venonat", "venomoth", "diglett", "dugtrio", "meowth", "persian", "psyduck", "golduck", "mankey", "primeape", "growlithe", "arcanine", "poliwag", "poliwhirl", "poliwrath", "abra", "kadabra", "alakazam", "machop", "machoke", "machamp", "bellsprout", "weepinbell", "victreebel", "tentacool", "tentacruel", "geodude", "graveler", "golem", "ponyta", "rapidash", "slowpoke", "slowbro", "magnemite", "magneton", "farfetchd", "doduo", "dodrio", "seel", "dewgong", "grimer", "muk", "shellder", "cloyster", "gastly", "haunter", "gengar", "onix", "drowzee", "hypno", "krabby", "kingler", "voltorb", "electrode", "exeggcute", "exeggutor", "cubone", "marowak", "hitmonlee", "hitmonchan", "lickitung", "koffing", "weezing", "rhyhorn", "rhydon", "chansey", "tangela", "kangaskhan", "horsea", "seadra", "goldeen", "seaking", "staryu", "starmie", "mr-mime", "scyther", "jynx", "electabuzz", "magmar", "pinsir", "tauros", "magikarp", "gyarados", "lapras", "ditto", "eevee", "vaporeon", "jolteon", "flareon", "porygon", "omanyte", "omastar", "kabuto", "kabutops", "aerodactyl", "snorlax", "articuno", "zapdos", "moltres", "dratini", "dragonair", "dragonite", "mewtwo", "mew"];

  let team = [
    "bulbasaur",
    "charmander",
    "squirtle",
    "caterpie",
    "weedle",
    "pidgey",
    "rattata",
    "spearow",
    "ekans",
    "pikachu",
    "sandshrew",
    "nidoran-f",
    "nidoran-m",
    "clefairy",
    "vulpix",
    "jigglypuff",
  ];

  let isEditing = false;
</script>

<main>
  {#if isEditing}
    <form>
      {#each team as teamMember}
        <div>
          <select bind:value={teamMember}>
            {#each pokemonList as pokemonName}
              <option value={pokemonName}>{pokemonName}</option>
            {/each}
          </select>
        </div>
      {/each}
    </form>
  {:else}
    <table>
      {#each team as teamMember}
        <tr>
          <td>{teamMember}</td>
        </tr>
      {/each}
    </table>
  {/if}
  <button on:click={() => (isEditing = !isEditing)}>Toggle</button>
</main>

请注意,生成的所有选择都具有完全相同的选项列表,因此有没有办法生成一次元素并每次重用它?或者任何其他解决方案可以使其响应更快?在示例中,如果我只保留一行,那么切换到编辑模式几乎是瞬时的,但随着添加更多行,它需要的时间明显更长。

forms svelte html-select
1个回答
0
投票

请注意,存在多种构建,并且开发 Svelte 构建的性能会比生产构建更差。此外,SSR 与 CSR 可能具有不同的性能特征,并且不同的浏览器以不同的方式处理大型 HTML 片段。

不过,这种场景至少可以通过两种方式进行优化:

  • 仅在与某个特定项目交互时显示选择(例如单击它) - 应该很简单
  • 仅在列表中的项目变得相关时才生成它们,即焦点位于元素上

对于后一种方法,您可以将选项的生成分离到单独的组件中,例如

<select bind:value={teamMember}>
  <LazyOptions list={pokemonList} value={teamMember} />
</select>
<script>
  export let list;
  export let value;

  let focused = false;

  function checkFocus(node) {
    const select = node.closest('select');

    const update = () => focused = document.activeElement == select;

    select.addEventListener('focus', update);
    select.addEventListener('blur', update);
    update();

    return {
      destroy() {
        select.removeEventListener('focus', update);
        select.removeEventListener('blur', update);
      },
    };
  }
</script>

<!-- Makes sure that the currently selected value always exists.
     Also provides an entry into the DOM to find the select. -->
<option style:display="none" use:checkFocus>{value}</option>

{#if focused}
  {#each list as o}
    <option>{o}</option>
  {/each}
{/if}

REPL

还有其他方法可以做到这一点,例如传递焦点状态,但这种方式封装得更整齐。

© www.soinside.com 2019 - 2024. All rights reserved.