首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Svelte.js -如何用新的道具重装子组件?

Svelte.js -如何用新的道具重装子组件?
EN

Stack Overflow用户
提问于 2019-09-19 12:44:10
回答 2查看 11.2K关注 0票数 16

我正在使用Svelte.js创建一个多步骤表单,但我遇到了一个问题,即用独特的道具呈现每个表单页面。

下面是一个简单的演示,向您展示我的意思:

代码语言:javascript
运行
复制
// App.svelte

<script>
    import FormPage from "./FormPage.svelte";
    let formNode;

    let pageSelected = 0;

    let formPages = [
        {
            name: "email",
            label: "Email"
        },
        {
            name: "password",
            label: "Password"
        }
    ];

    const handleIncPage = () => {
        if(pageSelected + 1 < formPages.length)
        pageSelected = pageSelected + 1;        
    }

    const handleDecPage = () => {
        if(pageSelected -1 > -1)
        pageSelected = pageSelected - 1;        
    }
</script>

<form bind:this={formNode}>
    <FormPage pageData={formPages[pageSelected]} />
</form>

<button on:click={handleDecPage}>Back</button>
<button on:click={handleIncPage}>Next</button>

<p>
    Page Selected: {pageSelected}
</p>

下面是FormPage组件:

代码语言:javascript
运行
复制
// FormPage.svelte

<script>
    export let pageData;

    const {name, label} = pageData;
</script>

<div id={`form-page-${name}`}>
    <label>Label: {label}</label>
    <input type="text" name={name} id={`input-${name}`} />
</div>

<pre>{JSON.stringify(pageData, null, 2)}</pre>

当我运行应用程序和inc/dec pageSelected时,pageData支柱成功地改变了--就像在pre元素中所看到的那样。但是,labelinput元素与第一页中的元素完全相同。包装iddiv元素和input元素的id也保持不变。

当我输入input并更改页面时,文本保持不变。

我的目标是:在FormPage更改时重新修改pageSelected组件,并让inputlabel基于这些新的道具更改它们的值。也应该是这样,当我更改页面时,已经输入到input中的文本应该更新并为空(因为输入没有初始值)。

在React.js中完成了多步表单之后,我将使用一个惟一的key属性来确保每次更改pageSelected状态时都会使用FormPage重选器。但我不知道如何在Svelte.js中做类似的事情。

有什么建议吗?

更新:

在阅读了问题 on StackOverflow之后,我了解了如何使inputlabel元素以及id属性发生变化。下面是我更新的FormPage组件:

代码语言:javascript
运行
复制
// FormPage.svelte

<script>
    export let pageData;

    $: name = pageData.name;
    $: label = pageData.label;

</script>

<div id={`form-page-${name}`}>
    <label>Label: {label}</label>
    <input type="text" name={name} id={`input-${name}`}  />
</div>

<pre>{JSON.stringify(pageData, null, 2)}</pre>

但是,input内部的文本仍然没有改变。

是否也有方法更新输入的值?对于我的用例来说,理想的做法是每次道具发生变化时创建一个全新的元素,但是Svelte似乎只更新了在同一个基础DOM节点上更改的少数属性。

在这种情况下,Svelte能被告知重新创建元素吗?

更新2

所以我想出了一种方法来改变输入的值。下面是我更新的FormPage组件:

代码语言:javascript
运行
复制
// FormPage.svelte

<script>
    export let pageData;

        import {onMount, afterUpdate, onDestroy} from "svelte";

        let inputNode;

        $: name = pageData.name;
        $: label = pageData.label;
        $: value = pageData.initialValue || "";

        onMount(() => {
            console.log("Mounted");
        });

        afterUpdate(() => {
            console.log("Updated");
            inputNode.value = value
        });

        onDestroy(() => {
            console.log("Destroyed");
        });

</script>

<div id={`form-page-${name}`}>
    <label>Label: {label}</label>
    <input type="text" name={name} id={`input-${name}`} bind:this={inputNode}  />
</div>

<pre>{JSON.stringify(pageData, null, 2)}</pre>

这解决了更新输入值的直接问题。

我添加了onMountafterUpdateonDestroy函数,以查看组件随时间的变化情况。

首先,调用onDestroy函数,然后调用onMount。这两个都只有一次火。然而,每次道具发生变化时,afterUpdate都会触发。这证实了我的怀疑,即该组件没有被重新创建。

EN

回答 2

Stack Overflow用户

发布于 2019-09-20 04:06:16

有更简单的方法来做这件事。pageData在您的FormPage中更新,问题是当您使用const {name, label} = pageData;时,基本上是将pageData中的namelabel参数的值分别分配给两个常量,namelabel。这两个变量不再绑定到父组件。为了解决这个问题,请在pageData中直接使用FormPage,如下所示。

FormPage.svelte

代码语言:javascript
运行
复制
<script>
    export let pageData;
</script>

<div id={`form-page-${pageData.name}`}>
    <label>Label: {pageData.label}</label>
    <input type="text" name={pageData.name} bind:value={pageData.value} id={`input-${pageData.name}`} />
</div>

注意:如果不希望编译器在没有传递undefined时给出pageData错误,那么可以将pageData初始化为空对象{},如so export let pageData = {};

至于input问题,最简单的方法是将value添加到formPages,然后将value添加到pageData.value,如上面的FormPage所示。

formPages数据

代码语言:javascript
运行
复制
let formPages = [{
    name: "email",
    label: "Email",
    value: ""
}, {
    name: "password",
    label: "Password",
    value: ""
}];

下面是REPL上的一个工作示例。

票数 8
EN

Stack Overflow用户

发布于 2021-03-19 05:16:15

{#key}..{/key}解决了这个问题。

在我的示例中,Sizing组件用于更新大小(字体大小或行高等),就像FormPage.svelte一样

代码语言:javascript
运行
复制
<script>
import Sizing from '..../Sizing.svelte'

const pages = {
  'font-size': Sizing,
  'line-height': Sizing, 
  ...
}
const props = {
  'font-size': { min: 8, max: 20, step: 1},
  'line-height': {min: 1, max: 3, step: 0.1}
}
let currentProp // 'font-size', 'line-height' etc ..
</script>

<div>
  {#key currentProp}
     <svelte:component this="{pages[currentProp]}" {...props}/>
  {/key}
</div>

每当currentProp更改时,也会更新Sizing。

{...props}映射到导出的变量。

代码语言:javascript
运行
复制
// Sizing.svelte
<script>
  export let min
  export let max
  export let step
</script>
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58011307

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档