是否可以在插槽中制作子组件以将数据发送给其父项?

时间:2019-07-02 17:58:57

标签: svelte

我正在尝试在Sveltejs中创建一个Form组件。 此Form组件将使用<slot />来让其父级(App.svelte)定义哪些Inputs和Buttons应该在Form内。 Inputs和Buttons也是组件,一旦Input组件的值更改,我想更新父Form组件内的对象,当单击Button时,我想将数据发送回App组件。

我试图阅读Svelte文档并解决<slot let:name={value}>时遇到的这个问题,但是当Input组件的值更改时,我找不到更新Form组件的方法。

这是我要执行的操作的结构:

App.svelte

...
<Form on:submit={saveReceivedData}>
  <Input name="..." value="..." />
  <Button />
</Form>
...

Form.svelte

<script>
...
let data = {}
</script>
...
<form>
  <slot />
</form>
...

Input.svelte

...
<input name={name} value={value} on:input={updateDataVariableOnFormComponent} />
...

Button.svelte

...
<button on:click={sendDataVariableToAppComponent}>Send</button>
...

如果需要,我可以尝试向您发送完整的代码。但是,由于我的问题不是“我做错了什么?”但是“我该怎么做?”,我更喜欢以抽象的方式写问题。

2 个答案:

答案 0 :(得分:2)

当子组件更改时,您可以使用组件绑定来更新父组件中的数据:

syncErrors

有了该绑定,父级中的<Input name="..." bind:value={someValue} /> 将同步到子级中的someValue

要通知父项有关子项中的事件而不是状态更改,您可以使用event dispatcher ...

value

...在这种情况下,您可以收听<!-- Button.svelte --> <script> import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); </script> <button on:click={() => dispatch('thinghappened', someData)}>Send</button> 事件...

thinghappened

...或者您可以简单地使用<Button on:thinghappened={e => doSomethingWith(e)}/> 转发DOM事件,并使用<button on:click>Send</button>监听父事件中的click事件。

答案 1 :(得分:0)

这就是我想要做的。老实说,我对此不是100%满意,但是我爱Svelte:D

App.svelte

<script>
    import Form from "./Form.svelte"
    import Input from "./Input.svelte"
    import Button from "./Button.svelte"
    let data = {
        name: "John",
        surname: "Smith"
    }
    const saveValues = (event) => {
        data = event.detail
    }
</script>

<Form data={data} let:saveMe let:updateMe on:save={saveValues}>
    <Input
        label="Name"
        name="name"
        value={data.name}
        on:input={updateMe}
    />
    <Input
        label="Surname"
        name="surname"
        value={data.surname}
        on:input={updateMe}
    />
    <Button on:click={saveMe}>
        Save
    </Button>
</Form>

<h4>Saved data</h4>
<ul>
    {#each Object.entries(data) as d}
        <li>{d[0]}: {d[1]}</li>
    {/each}
</ul>

Form.svelte

<script>
    import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher();
    export let data;
    const saveMe = () => dispatch('save', data)
    const updateMe = (e) => data = {...data, [e.detail.name]: [e.detail.value]}
</script>

<slot saveMe={saveMe} updateMe={updateMe} />

Input.svelte

<script>
  import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher();
  export let name;
  export let label = false;
    export let value = "";
</script>

<div class="input-field">
  <input
    id={name}
    name={name}
    value={value}
        on:input={(e) => {
      value = e.target.value
      dispatch('input', e.target)
    }}
  />
  {#if label}
    <label
      for={name}
      class:active={value.length > 0}
    >{label}</label>
  {/if}
  <slot />
</div>

Button.svelte

<button on:click>
    <slot />
</button>