Svelte 动态多组件阵列

san*_*der 4 typescript svelte

编辑:REPL 答案https://svelte.dev/repl/eb7616fd162a4829b14a778c3d1627e4?version=3.48.0

我所说的会导致这样的情况:

首先我们有一个按钮:

<button on:click={add}> Add </button>
<div id="columnflexbox">
Run Code Online (Sandbox Code Playgroud)

当我点击它时,应该会发生以下情况:

<button on:click={add}> Add </button>
<!-- This exists in DOM-->
<div id="columnflexbox">

<!-- This div and components get rendered, the Div does not exist in DOM -->
<div class="row" style="display:flex;flex-direction:row">
comp1 (instance1) 
comp2 (instance1)
</div>
Run Code Online (Sandbox Code Playgroud)

当我再次单击它时,会添加另一行(带有新实例):添加

<div id="columnflexbox">


<div class="row" style="display:flex;flex-direction:row">
comp1 (instance1) 
comp2 (instance1)
</div>
<!-- Second div is generated, it does not exist in DOM, new instances of components -->
<div class="row" style="display:flex;flex-direction:row">
comp1 (instance2)
comp2 (instance2)
</div>


</div>
Run Code Online (Sandbox Code Playgroud)

有一个界面:

export interface complexObject {
    comp1 : ComplexObj1
    comp2: ComplexObj2
}

let row: complexObject[] = []
Run Code Online (Sandbox Code Playgroud)

添加功能:

function add(){        
    let newObj:complexObject = {
        comp1: new Comp1({target: div}), // I have to add a target here, or I get compile error, but how since the element doesn't exist?
        comp2: new Comp2({target: div})
    }

    row.push(newObj);
}
Run Code Online (Sandbox Code Playgroud)

我会使用这种方法,但我不能,因为我在没有添加目标的情况下收到编译错误:

{#each row as rowitem }

    <div class="row">
        {rowitem.comp1}
        {rowitem.comp2}
    </div>
    
{/each}
Run Code Online (Sandbox Code Playgroud)

编辑:事实证明,当我将目标添加为渲染中指定的 html 时,样式会正确应用,如下所示:

添加功能:

function add(){    
    let div = document.createElement("div");
    div.setAttribute('class',"row")


    let newObj:complexObject = {
        comp1: new Comp1({target: div}),
        comp2: new Comp2({target: div})
    }

    row.push(newObj);
}


{#each row as rowitem }
<div class="row">
        {rowitem.comp1}
        {rowitem.comp2}
</div>    
        

{/each}
Run Code Online (Sandbox Code Playgroud)

现在的问题是组件没有被渲染,我得到的是

[object Object]     [object Object]
Run Code Online (Sandbox Code Playgroud)

当我尝试这样渲染时:

  <svelte:component this={rowitem.comp1}>

    </svelte:component>
Run Code Online (Sandbox Code Playgroud)

我收到错误:

TypeError: l is not a constructor
Run Code Online (Sandbox Code Playgroud)

如果我尝试修改添加函数并删除new关键字,我会得到以下结果:

Type 'typeof comp1__SvelteComponent_' is missing the following properties from type 'comp1__SvelteComponent_': $$prop_def, $$events_def, $$slot_def, $on, and 5 more.ts(2740)
Run Code Online (Sandbox Code Playgroud)

原来这是指定接口的问题,应该这样指定:

export interface complexObject {
    comp1 : typeof ComplexObj1
    comp2: typeof ComplexObj2
}
Run Code Online (Sandbox Code Playgroud)

H.B*_*.B. 6

为此,通常会使用svelte:component组件的构造函数作为输入以及可能想要传递的任何道具。例如

<script>
    import Comp from './Comp.svelte';
    
    let components = [
        [Comp, { content: 'Initial' }],
        [Comp, { content: 'Initial 2' }],
    ];
    function add(component, props) {
        components = [...components, [component, props]];
    }
</script>

<button type=button on:click={() => add(Comp, { content: 'Added' })}>
    Add
</button>

{#each components as [component, props]}
    <svelte:component this={component} {...props}>
        (Slotted content)
    </svelte:component>
{/each}
Run Code Online (Sandbox Code Playgroud)

REPL 示例


类型示例:

<script lang="ts">
    import type { SvelteComponent, SvelteComponentTyped } from 'svelte';
    import Comp from './Comp.svelte';
    import Comp2 from './Comp2.svelte';
    
    let components: [typeof SvelteComponent, Record<string, any>][] = [
        [Comp, { content: 'Initial' }],
        [Comp2, { color: 'blue' }],
    ];
    function add<T extends typeof SvelteComponentTyped<P, any, any>, P>(
        component: T,
        props: P
    ) {
        components = [...components, [component, props]];
    }
</script>
Run Code Online (Sandbox Code Playgroud)

add强制组件及其 props 之间的一致性,而数组不能,至少在使用元组时是这样。如果每个项目都是一个类,则该类可以强制其内部类型一致性。