如何在 svelte 中从另一个 child 更新 child 组件

How to update a child component from another child in svelte

我在汽车名称上有一个 select 显示汽车颜色。当我在 car 字段中输入汽车并且它存在于汽车列表中时,我在 Maintain 中显示颜色(这有效)

如果我改变当前select车上的颜色并保存更改,我希望更新后的颜色出现在原理child的输入框中(汽车)

如果我 re-select 汽车,它可以工作,但我希望它在单击 保存 按钮后立即更新。

如何在保存时更新颜色?

这是REPL

App.svelte

<script>
    import Cars from './Cars.svelte'
    import MaintainCar from './MaintainCar.svelte'
    let cars = {'Audi': 'red', 'BMW':'blue', 'Hillman': 'green'}

    function maintenance() {
        console.log(cars)
    }
</script>

<main>
    <Cars cars={cars}/>
    <MaintainCar cars={cars} on:message={maintenance} />
</main>

Cars.svelte

<script>
    export let cars
    export let selected_car = ''
    let colour = ''
    let car_list = getCars(cars)
    $: colour = cars[selected_car]

    function getCars(cars) {
        let car_list = []
        for (const [key, value] of Object.entries(cars)) {
            car_list.push(key);
        }
        if (!selected_car) {
            selected_car = car_list[0]
            colour = cars[selected_car]
        }
        return car_list
    }

    function selectCar() {
        colour = cars[selected_car]
    }
</script>

<select bind:value={selected_car} on:click={selectCar}>
    {#each car_list as car}
        <option value={car}>
            {car}
        </option>
    {/each}
</select>
<input type="text" bind:value={colour} placeholder="colour"/>

MaintainCar.svelte

<div>
    <input type="text" bind:value={car} placeholder="car"/>
        <input type="text" bind:value={colour} placeholder="colour"/>
    <div>
        <button class="select-button" on:click={saveData}>Save</button>
    </div>
</div>

<script>
    import { createEventDispatcher } from 'svelte';
    const dispatch = createEventDispatcher();
    export let cars
    let car = ''
    $: colour = checkCar(car)

    function checkCar(car) {
        colour = '';
        if (car && car in cars) {
            colour = cars[car];
        }
        return colour
    }

    function saveData() {
        cars[car] = colour;
        car = ''
        colour = ''
        dispatch('message', {
            text: 'colour'
        });
    }
</script>

好吧,如果您希望信息以一种方式下降,并以另一种方式返回,您需要... two-way 绑定!

变化:

<MaintainCar cars={cars} on:message={maintenance} />

至:

<MaintainCar bind:cars={cars} on:message={maintenance} />

现在它附带了很多的注意事项...

首先,它仅在 child 组件中分配给从外部绑定的完全相同的变量时才有效。就像您现在碰巧做的那样,但是很容易丢失它,因为您从数组中提取一个项目,从 object 中提取一个道具或其他任何东西。总而言之,您必须小心 在 child 组件 中所做的事情,以支持从外部使用它的方式[=40] =],这种情况很少见。

第二个警告是关于 two-way 一般绑定。虽然它在某些情况下非常有用并且可以节省大量样板文件,但它也可能导致建立一个难以跟踪依赖关系的混乱网络,上下波动......因此,请谨慎使用。

一个通常更合理的方法是使用一个商店,它本身具有反应性,而不是依赖于脆弱和棘手的 two-way 绑定链。 Svelte 让这一切变得简单!

您可以更改 parent 组件中的 cars 反应变量:

<script>
  const cars = writable({'Audi': 'red', 'BMW':'blue', 'Hillman': 'green'})

  // don't forget to prefix it with $ to access its _value_
  console.log($cars)
  ...
</script>

<!-- pass the store directly to children (not the value) -->
<Cars {cars}/>
<MaintainCar {cars} on:message={maintenance} />

然后 children 可以轻松地访问存储中的值或更改它,并将更改传播回使用该存储的任何地方:

<script>
  export let cars

  function saveData() {
    $cars[car] = colour;
  }

  ...
</script>

...

请参阅此 REPL 并将您的示例转换为商店。