Передача события: click в динамически созданное ‹svelte: component /›

Мне в основном нужно иметь возможность запускать что-то в одном или нескольких компонентах (которые динамически добавляются через svelte: component) при нажатии значка / кнопки в родительском компоненте. например Мне нужно зацепить части, обозначенные ** ниже: -

<script>
 let charts = [
    ChartA,
    ChartB,
    ChartC
  ];
</script>
{#each charts as chart, i}
    <div class="wrapper">
        <div class="icon" on:click={**HowToPassClickEventToComponent**}></div>
        <div class="content">
        <svelte:component this={charts[i]} {**clickedEvent**}/>
        </div>
    </div>
{/each}

Мне удалось заставить что-то работать, отключив массив реквизитов, но каждый компонент уведомляется при изменении массива, поэтому это не очень чисто.

Я искал как в Google, так и в StackOverflow, а также задавал этот вопрос в канале Svelte Discord, но в настоящее время безуспешно.

Svelte Repl показывает проблему

Это кажется таким простым требованием, но через пару дней я все еще застрял, поэтому очень ценю любые советы о том, как передавать события в динамические компоненты.


person Minty    schedule 26.09.2019    source источник
comment
Пусть каждый компонент определяет и добавляет свой собственный обработчик: click. И взгляните на ‹svelte: component›   -  person voscausa    schedule 26.09.2019
comment
Я хочу избежать дублирования кода в каждом компоненте, имея внешний компонент, предоставляющий панель инструментов, которая передает событие щелчка дочернему элементу для обработки щелчка. Я не думал, что это будет так сложно, когда все остальное в Svelte так просто.   -  person Minty    schedule 26.09.2019
comment
Зачем пропускать событие клика. Каждый компонент может обрабатывать свой собственный обработчик. И если A, B, ... не идентичные подкомпоненты, вы всегда можете поделиться кодом, импортировав общий файл js.   -  person voscausa    schedule 26.09.2019
comment
И если у вас есть событие щелчка из нескольких источников в родительском компоненте, вы можете идентифицировать источник с помощью цели события и поделиться действием с вложенными компонентами, объединяющими опору или хранилище.   -  person voscausa    schedule 26.09.2019
comment
Компоненты действительно все разные, и использование файла common.js может помочь в этом конкретном примере, но я думаю, что все еще существует допустимый вариант использования для передачи события в компонент. Передача свойства также будет работать, но, к сожалению, это не работает и при использовании динамически сгенерированных компонентов, как показано в следующем модифицированном REPL - svelte.dev/repl/fc91e089278848eba782f9ef994f534e?version=3.12.1   -  person Minty    schedule 26.09.2019
comment
Я не знаю, почему ваш код не работал, но если вы используете связывание типа: ‹svelte: component this = {charts [i]} bind: event = {flag} /›, он работает нормально.   -  person voscausa    schedule 26.09.2019
comment
Добавление привязки: кажется, имеет значение, но это приводит к тому, что все компоненты меняются при нажатии кнопки (из-за единственной переменной флага), что не является тем, что требуется, и приводит к тому, что массив реквизитов из исходного вопроса что действительно некрасиво, поскольку каждый компонент должен проверять, был ли он целью щелчка. Спасибо, и я очень признателен за ваши предложения.   -  person Minty    schedule 26.09.2019
comment
И теперь я понимаю, почему ваш код не работал. Вы должны использовать: event = {flag}, а не event: {flag}   -  person voscausa    schedule 26.09.2019
comment
Возможно, этот вопрос вернет полезный ответ: stackoverflow.com/questions/58115156/   -  person voscausa    schedule 26.09.2019
comment
Спасибо, я тоже буду следить за этим.   -  person Minty    schedule 26.09.2019


Ответы (1)


Вы можете сделать это вот так:

<script>
    import ChartA from './ChartA.svelte'
    import ChartB from './ChartB.svelte'
    import ChartC from './ChartC.svelte'
    let charts = [
        ChartA,
        ChartB,
        ChartC
    ];
    let events = [];
</script>

<style>
    .icon{
        width:60px;
        height:30px;
        background-color:grey;
    }
</style>

{#each charts as chart, i}
    <div class="wrapper">
        <div class="icon" on:click={e=>events[i] = e}>Click</div>
        <div class="content">
            <svelte:component this={charts[i]} event={events[i]}/>
        </div>
    </div>
{/each}

Однако передача событий в виде данных была бы немного необычной. Было бы более идиоматично установить какое-то состояние в родительском компоненте в ответ на событие и передать это состояние вниз.

В качестве альтернативы, если дочерние компоненты действительно должны ответить к самим событиям вы можете применить такой подход ...

<script>
    import ChartA from './ChartA.svelte'
    import ChartB from './ChartB.svelte'
    import ChartC from './ChartC.svelte'
    let charts = [
        ChartA,
        ChartB,
        ChartC
    ];
    let instances = []; 
</script>

<style>
    .icon{
        width:60px;
        height:30px;
        background-color:grey;
    }
</style>

{#each charts as chart, i}
    <div class="wrapper">
        <div class="icon" on:click={e => instances[i].handle(e)}>Click</div>
        <div class="content">
            <svelte:component
                this={charts[i]}
                bind:this={instances[i]}
            />
        </div>
    </div>
{/each}

... где каждый дочерний компонент экспортирует handle метод:

<script>
    let event;
    export function handle(e){
        event = e;
    };
</script>
person Rich Harris    schedule 26.09.2019
comment
Привет, Рич! Ваше второе предложение идеально подходит для того, что мне нужно, и я очень ценю его. Спасибо также за Svelte (что совершенно потрясающе). - person Minty; 26.09.2019
comment
Да, очень мило. - person voscausa; 26.09.2019
comment
После долгих поисков этот ответ показал мне, что использование export необходимо при вызове функций дочерних компонентов, наконец, я могу перестать биться головой о клавиатуру. :) - person glormph; 15.10.2019