Svelte v3 以编程方式创建带有 props 和事件侦听器的组件



是否可以创建一个组件并以编程方式将事件侦听器附加到它?

我知道这对于使用<svelte:component/>的道具来说很容易通过{ ...props }传播来实现。我想知道是否可以实现类似的东西来附加事件侦听器。

例如,在以下示例中,我想以编程方式将on:message附加到Aon:count附加到B

<!-- App.svelte -->
<script>
import A from './A.svelte';
import B from './B.svelte';
let message = 'Hi there 👋';
let count = 0;
const components = [{
component: A,
props: { message },
listeners: { message: (m) => { console.log(`They say "${m}"`); } }
}, {
component: B,
props: { count },
listeners: { click: () => { count++; } }
}];
</script>
{#each components as component}
<div><svelte:component this={component.component} { ...component.props }/></div>
{/each}
<div>
<p>They say "{message}"!</p>
<p>They clicked {count} times!</p>
</div>
<!-- A.svelte -->
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
export let message = '';
function changeHandler(e) { dispatch('message', message); }
</script>
<input on:change={changeHandler} on:value={message} value={message} />
<!-- B.svelte -->
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
export let count = 0;
function clickHandler() { dispatch('count', count); }
</script>
<button on:click={clickHandler}>Click me</button>

这是一个现场演示:https://svelte.dev/repl/af1bd30ab75b43f19b72a306340b7282?version=3.18.2

即,我希望有一种方法可以将components数组扩展到

<A message={message} on:message={e => { message = e.detail; }}/>
<B count={count} on:count={e => { count = e.detail; }}/>

您可以使用$on在组件事件上动态注册侦听器。

在您的用例中,您可以使用此组件:

ComponentEvent.svelte

<svelte:component this={component.component} { ...component.props } bind:this={instance}/>
<script>
export let component;
let instance;

$: if (instance && component.listeners) {
for (let [key, listener] of Object.entries(component.listeners)) {
instance.$on(key, listener);
}
}
</script>

并在您的 App.svelte 中将 each 循环替换为 :

{#each components as component}
<ComponentEvent {component}/>
{/each}

请参阅此 REPL

你不能动态地附加侦听器,不 - 不要忘记Svelte是一种编译语言,它在编译时完成了所有繁重的工作,所以需要提前知道事情。

我为动态侦听器所做的是触发单个已知事件,然后让事件详细信息包含差分逻辑,例如事件名称等。如下:

// SomeComponent.svelte
<script>
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
dispatch('component-event', { name: 'alert', value: 'oh noes' })
dispatch('component-event', { name: 'log', value: 'some message' })
</script>
// App.svelte
<svelte:component this={someComponent} on:component-event={e => handleEvent(e)} />
<script>
function handleEvent ({ detail }) {
const { name, value } = detail
if (name === 'alert') { alert(value) }
if (name === 'log') { console.log(value) }
}
</script>

不确定是否可以像查找一样以编程方式附加它们,但您可以在对象中传递函数或回调,并考虑 svelte:component 标记中的每个潜在调度事件,如下所示:

<svelte:component
this={component.component}
{ ...component.props }
on:message={ component.function}
on:count={ component.function}
/>

这是 REPL 中的一个工作示例,它显示了对象中的箭头函数和一个回调(如果需要更丰富的函数(,回调仍然获取事件详细信息。

我认为如果组件中不存在调度的事件,则不会发生任何事情,但是如果您需要单个组件来调度多个事件,则需要其他内容。

最新更新