【问题标题】:Svelte v3 programmatically create a component with props and event listenersSvelte v3 以编程方式创建具有道具和事件侦听器的组件
【发布时间】:2020-05-30 15:43:16
【问题描述】:

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

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

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

<!-- 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; }}/>

【问题讨论】:

    标签: svelte svelte-3


    【解决方案1】:

    您可以使用$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 components as component}
        <ComponentEvent {component}/>
    {/each}
    

    看到这个REPL

    【讨论】:

      【解决方案2】:

      您不能动态附加侦听器,不 - 不要忘记 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>
      

      【讨论】:

      • 有趣的方法!感谢分享。另外,我不完全确定为什么在可以动态附加道具时从技术上讲不能动态附加事件侦听器。也许这只是当前 API 的一个限制。
      【解决方案3】:

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

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

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

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

      【讨论】:

      • 这种方法需要事先知道回调是什么并覆盖所有回调。这在我的玩具演示中很好,但我实际上正在寻找一种不需要预先知道事件名称的解决方案。
      • 我认为没有 on: 指令就无法连接听众
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      • 2022-09-26
      • 1970-01-01
      • 2011-08-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多