将事件指令添加到 svelte html 表达式?

Add event directive to svelte html expression?

我想在 svelte 中通过 html 表达式添加自定义按钮。 通过文档 here,我可以使用 @html 标签来做到这一点。

{@html 
`
 <button>
   click me
 </button>
`
}

我现在想向 html 字符串添加一个指令事件处理程序,即单击按钮时将调用的本地定义函数。到目前为止我尝试了什么:

{@html 
`
 <button
   on:click="${()=>doSomething()}">
   click me
 </button>
`
}

然而,如我所料,它没有用。我在想可能还有另一种方法,但到目前为止还想不出一个

从概念上讲,使用 @html 指令等同于执行 el.innerHTML = myHtmlString.

换句话说,在您的 HTML 字符串的上下文中,您完全不在 Svelte 的领域(并且完全在本机浏览器的领域)。

on:click 是特殊的 Svelte 语法,浏览器不会处理它。所以如果你想要你的 HTML 字符串中的事件,你需要返回原始 HTML/JS。也就是说,改用 onclick

当然,onclickon:click的语义完全不同。对于 onclick,你只能传递一个字符串,当事件发生时,它将是 eval'(而对于 on:click,你传递一个函数 reference, 当事件发生时将被调用)。

为了更清楚地说明这一点,让我们回顾一下 Svelte 的语法:

<button on:click={doSomething}>Click me</button>

相比之下,在原始 HTML 中,它看起来像:

{@html '<button onclick="doSomething()">Click click!</button>'}

查看重要区别:使用 onclick,您需要 调用 doSomething() 函数,否则点击时不会发生任何事情。

现在,额外的乐趣:这个 doSomething 函数需要在范围内可用...也就是说,您必须将它附加到 window:

<script context="module">
  // note: using context=module to avoid adding this function to window
  //       multiple times
  window.doSomething = () => { ... }
</script>
{@html '<button onclick="doSomething()">Click click!</button>'}

这太丑了...您可以改为这样做,以避免污染全局范围:

<script>
  import { onMount } from 'svelte'

    const doSomething = () => { ... }

    onMount(() => {
        const btn = document.querySelector('#grab-me')
        btn.addEventListener('click', doSomething)
    })
</script>

{@html '<button id="grab-me">Click click!</button>'}

现在我们正在污染 DOM ids...我们可以通过用 Svelte 控制的元素包装来进一步避免这种情况,我们可以使用 bind:this={el}...

总而言之,最好避免 @html 字符串中的动态元素,因为您会在其中失去 Svelte 的所有优势。 @html 最适合呈现静态 HTML 内容。

为什么要将按钮放在字符串中,而不是让 Svelte 管理它?

如果你真的需要走这条路,你可能也会对 this dirty trick 感兴趣,我绝对不建议使用它(我永远不会在我自己的代码中使用它)...但是这可能会让您对您要实现的目标有更深入的了解。