Да и нет.
На самом деле то, что вы сделали, связывает переменную с различным экземпляром компонента. Объект тот же, ===
, с той же ссылкой ... Пока это не произойдет:
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
изменится, а это именно то, что нам нужно.