苗条的动态多组件数组



EDIT: REPL for answer https://svelte.dev/repl/eb7616fd162a4829b14a778c3d1627e4?version=3.48.0

我所说的将渲染这个:

首先我们有一个按钮:

<button on:click={add}> Add </button>
<div id="columnflexbox">

当我点击它时,应该是这样的:

<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>

当我再次点击它,另一行被添加(新的实例):添加

<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>

存在一个接口:

export interface complexObject {
comp1 : ComplexObj1
comp2: ComplexObj2
}
let row: complexObject[] = []

添加功能:

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);
}

我将使用这种方式做它,但我不能,因为我得到编译错误没有添加目标:

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

{/each}
编辑:事实证明,当我将目标添加为渲染中指定的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}

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

[object Object]     [object Object]

当我尝试这样渲染时:

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

I get error:

TypeError: l is not a constructor

如果我尝试修改Add函数并删除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)

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

export interface complexObject {
comp1 : typeof ComplexObj1
comp2: typeof ComplexObj2
}

对于这种情况,通常会使用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}

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>

add强制组件和它的道具之间的一致性,数组不能,至少当使用元组时。如果每个项都是一个类,则该类可以强制其内部类型一致性。

如果您需要引用DOM元素,您可以在onMount中查询它,或者通过bind:this(然后在onMount中定义/可访问)REPL设置对变量的引用

<script>
import {onMount} from 'svelte'
import Comp from './Comp.svelte'
let container

onMount(() => {
const containerRef = document.getElementById('container')
console.log(containerRef, container)
const c = new Comp({target: container})
})
</script>
<div id="container" bind:this={container} />

(你查询getElementByID,但你的外部元素有class="columnflexbox",你迭代newObjsrow吗?因为first是一个对象,不能直接迭代,我想…)

最新更新