如何保留对循环中创建的组件的引用?

How to keep a reference to component created within a loop?

我正在学习 Svelte,我正在尝试制作一个组件(调色板)。我盲目地寻求一种解决方案,其中每个 ColorSelector(您单击的颜色 div)都是一个 Svelte 组件。 (我很乐意举一个没有使用子组件的例子)

我在ColorSelector.svelte组件文件中导出了一个selected属性。我想在单击其中一个时实例化的每个 ColorSelectors 上将 属性 设置为 false,但已单击的 ColorSelectors 除外。

但是,我正在努力寻找如何在循环中保持对实例化组件的引用。我怎样才能做到这一点?

<script lang="ts">
  import { Colors, Color } from "./modules/colors";
  import ColorSelector from "./ColorSelector.svelte";

  const DEFAULT_COLOR = Colors.LIGHT_WHITE;
  let selectedColor:Color = DEFAULT_COLOR;

function handleClick(event, i) {
  selectedColor = event.detail.color;
  // When clicked set ColorSelector.selected = false on evert ColorSelectors 
  // except the one that has been clicked
}
</script>

<div>
  {#each Object.values(Colors) as color, i}
    <ColorSelector on:selected={handleSelect} color={color}></ColorSelector>
  {/each}
</div>

<style>
  div {
    display: flex;
  }
</style>

要在循环中保留对组件的引用,您可以对数组使用 bind:this。看看这个问题

为了能够在 option must be activated with <svelte:options accessors={true}/> Here's a solution with the data flow I assume you were trying to build >> REPL

组件上设置 属性
<script>
    import ColorSelector from './ColorSelector.svelte'
    import {Colors} from './Colors'
    const DEFAULT_COLOR = Colors.LIGHT_WHITE;

    let selectedColor = DEFAULT_COLOR
    let colorSelectors = []

    function handleSelect(e,i) {
        selectedColor = e.detail.color
        colorSelectors.forEach(cS => cS.selected=false)
        colorSelectors[i].selected = true
    }

</script>

<p><b>{selectedColor}</b></p>

<div>
    {#each Object.values(Colors) as color, i}
    <ColorSelector {color} bind:this={colorSelectors[i]}
                           selected={color === DEFAULT_COLOR ? true : false}
                           on:selected="{(e) => handleSelect(e,i)}"/>
    {/each}
</div>

<style>
    div {
        display: flex;
        flex-wrap: wrap;
        box-sizing: border-box;
    }
</style>

[ColorSelector.svelte]

<svelte:options accessors={true}/>

<script>
    import { createEventDispatcher } from 'svelte';
    const dispatch = createEventDispatcher();
    
    export let color, selected  

    function handleClick() {
        dispatch('selected', {
            color
        });
    }
</script>

<div class="color-selector"
         class:selected
         style:background={color}            
         on:click={handleClick}
    ></div>

<style>
    .color-selector {
        flex-basis: 200px;
        flex-grow: 1;
        height: 100px;
        box-sizing: border-box;
    }
    .selected {
        border: 5px solid black;
    }
</style>


但我认为构建选择器并不真正需要这些功能,selected = true/false 标志也不是,因为只有一种选择的颜色很重要。 这是一个更简单的解决方案,有和没有组件 REPL

<script>
    import ColorSelector from './ColorSelector.svelte'
    import {Colors} from './Colors'
    const DEFAULT_COLOR = Colors.LIGHT_WHITE;
    let selectedColor = DEFAULT_COLOR;
</script>

<p><b>{selectedColor}</b></p>

<div>
    {#each Object.values(Colors) as color, i}
    <div class="color-selector"
             class:selected-color={selectedColor === color}
             style:background={color}            
             on:click={() => selectedColor = color}
        ></div>
    {/each}
</div>

<hr>

<div>
    {#each Object.values(Colors) as color, i}
    <ColorSelector {color} bind:selectedColor />
    {/each}
</div>

<style>
    div {
        display: flex;
        flex-wrap: wrap;
        box-sizing: border-box;
    }
    .color-selector {
        flex-basis: 200px;
        flex-grow: 1;
        height: 100px;
    }
    .selected-color {
        border: 5px solid black;
    }
    hr {
        margin: 3rem;
    }
</style>

[ColorSelector.svelte]

<script>
    export let color, selectedColor
</script>

<div class="color-selector"
         class:selected-color={selectedColor === color}
         style:background={color}            
         on:click={() => selectedColor = color}
    ></div>

<style>
    .color-selector {
        flex-basis: 200px;
        flex-grow: 1;
        height: 100px;
        box-sizing: border-box;
    }
    .selected-color {
        border: 5px solid black;
    }
</style>