Можно ли связать одну и ту же переменную с несколькими компонентами с помощью Svelte? - PullRequest
0 голосов
/ 01 апреля 2020

Если один и тот же компонент используется несколько раз из одного и того же контекста, возможно ли связанное свойство совместно использовать в своих экземплярах?

Например, если у меня есть компонент, который создает флажки, как можно выбор (bind:group) объединить для селектора букв и селектора цифр?

В этом примере, если выбрано несколько букв, выбор будет правильно распространен и ограничен. Однако, если затем выбраны цифры, выбор буквы заменяется выбранными цифрами, а не соединением выбранных цифр с выбранными буквами.

// App.svelte
<script>
    import Selector from './Selector.svelte';

    let selection = [];

    $: console.log(selection);
</script>

<h2>Letters</h2>
<Selector options={['A', 'B', 'C']} bind:selection />

<h2>Numbers</h2>
<Selector options={[1, 2, 3]} bind:selection />

// Selector.svelte
<script>
    export let options;
    export let selection;
</script>


<div class="selector">
    {#each options as option}
    <label>
        <input type="checkbox" value={option} bind:group={selection} />
                {option}
    </label>
    {/each}
</div>

REPL: https://svelte.dev/repl/f97f859ea567473b9732b8933db870f7?version=3.20.1

1 Ответ

0 голосов
/ 01 апреля 2020

Да и нет.

На самом деле то, что вы сделали, связывает переменную с различным экземпляром компонента. Объект тот же, ===, с той же ссылкой ... Пока это не произойдет:

        selection = value;

Это из скомпилированного кода в вашем REPL. Когда вы устанавливаете флажок, Svelte создает новый массив, содержащий проверенные значения, и присваивает его переменной bind:group. На данный момент переменная остается прежней ... Но ее содержимое было заменено новой ссылкой на массив. Вот почему, когда вы меняете группу, вы теряете значение предыдущего.

Вы можете доказать это себе, обновив свой REPL, чтобы сделать selection объектом вместо массива, и добавить некоторые логики c для сохранения значения по ключу.

Например, в App.svelte измените выделение на объект:

    let selection = {};

А в Selector.svelte свяжите с промежуточной переменной и напишите только для объекта (не самого объекта):

<script>
    export let options;
    export let selection;

    let group = []
    $: for (const option of options) {
        selection[option] = group.includes(option)
    }
</script>


<div class="selector">
    {#each options as option}
    <label>
        <input type="checkbox" value={option} bind:group />
                {option}
    </label>
    {/each}
</div>

Обновлен REPL

Напечатайте значение selection как-нибудь, и вы увидите что он не сбрасывается и содержит значение из всех селекторов.

Итак, возвращаясь к вашей проблеме, проблема действительно в назначении. И тут мало что можно сделать с этим напрямую. В Svelte нет ничего для слияния связанных значений ... Однако теперь, когда мы поняли проблему, мы можем обойти ее.

Решение состоит в том, чтобы избежать непосредственного связывания publi c prop (то есть selection) но вместо этого связывайтесь с промежуточной переменной, как в нашем предыдущем примере, и сделайте слияние как-то самостоятельно (много способов здесь доступно).

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

<script>
  export let options;
  export let selection;

    let group = []

    const update = () => {
      selection = selection
        .filter(x => !options.includes(x))
        .concat(group)
    }

    // when group changes, update
    $: group, update()
</script>

<div class="selector">
  {#each options as option}
    <label>
      <input type="checkbox" value={option} bind:group />
          {option}
    </label>
  {/each}
</div>

REPL

Примечание. Я не поместил выражение selection = selection.filter(x => !options.includes(x)).concat(group) непосредственно в реактивный блок, потому что наше обновление будет запускаться при selection меняется. И так как он разделен, он изменится снаружи. На самом деле, это будет бесконечное условие l oop, но у Svelte есть защита от этого специально (для реактивных блоков). Но лучше не полагаться на это, а также избегать потерь. Здесь это сработает только тогда, когда наш локальный group изменится, а это именно то, что нам нужно.

...