苗条的自定义元素不转发事件

时间:2020-03-06 10:46:21

标签: svelte tabulator svelte-3 svelte-component

我想在我的项目中使用Tabulator,该项目尚未与Svelte集成。这是我之前已经使用过的非常完整的数据表库。但是,当我尝试使用操作按钮(编辑,删除...)创建典型列时,我总是使用它们的Custom Formatters来将html作为字符串返回。

格式化列的函数返回以下内容:

return '<ul class="actions_row"><li><custom-button on:click={handleClick}>Edit</custom-button></li></ul>';

<custom-button />是使用<svelte:options>创建的自定义元素,并通过 index.html <script src="lib/CustomButton.js"></script>)添加到项目中。

自定义按钮显示在表格中,但它无法转发事件。似乎该组件无法在其自身范围之外进行通信。

3 个答案:

答案 0 :(得分:1)

您的自定义格式化程序返回的字符串将作为“普通” HTML处理,因此Svelte语法不再可用...即on:click是Svelte语法,浏览器将不处理。

我不是自定义元素专家,但是很不幸,according to others,您要尝试做的事情是不可能的。也就是说,您不能仅通过HTML在自定义元素上注册自定义事件侦听器。您必须必须使用JS来完成。像这样:

    <script>
      document.querySelector('custom-button')
        .addEventListener('my-event', e => {
          console.log(e.detail)
        })
    </script>

此外,请注意,Svelte中来自自定义元素的事件当前受到某些限制(请参见this issue)。

因此,为了使自定义元素具有自定义事件,您必须使用某种解决方法。例如,以下是触发上述片段中的侦听器的组件:

<svelte:options tag="custom-button" />

<script>
  import { onMount } from 'svelte';

  let el

  onMount(() => {
    const interval = setInterval(() => {
      let event = new CustomEvent('my-event', {
          detail: {time: Date.now()},
          bubbles: true,
          composed: true, // needed for the event to traverse beyond shadow dom
      })
      el.dispatchEvent(event)
    }, 1000)

    return () => {
      clearInterval(interval)
    }
  })
</script>

<button bind:this={el}><slot /></button>

请注意,此类代码对旧版浏览器的支持有限。

说了这么多,对于您的示例而言,正是这样,您显然可以通过在本机浏览器onclick而非Svelte的on:click中注册事件来使其工作。我仍然不是CE专家,但我的猜测是浏览器会处理所有本机元素(例如,单击或按下CE元素)上都可用的标准事件...

因此,这似乎应该对您有用:

return '<ul class="actions_row"><li><custom-button onclick="handleClick">Edit</custom-button></li></ul>';

注意:onclick="handleClick",而不是on:click={handleClick}。您现在处在标准浏览器领域,因此适用通常的规则,就像使用普通的<button> ... handleClick一样,必须在范围内可用,等等。

答案 1 :(得分:0)

发生这种情况的原因是因为您正在从格式化程序中返回HTML字符串,这意味着在将其转换为字符串的过程中,所有的JS绑定(例如click事件处理程序)都将被删除。 (单击功能绑定的上下文将丢失,因为该功能仅在写入字符串而不是在解析位置写入的函数中才有效)

为了保留绑定,您应该返回表示按钮的 Node Object 本身,而不仅仅是按钮的HTML,这样,其他事件添加到该按钮的事件绑定库将保持不变。

答案 2 :(得分:0)

我正在使用自定义组件中的以下代码调度事件。

<script>
    import { get_current_component } from "svelte/internal";
    const thisComponent = get_current_component();
    
      // Standard function for dispatching custom events
      const dispatchWcEvent = (name, detail) => {
        thisComponent.dispatchEvent(new CustomEvent(name, {
          detail,
          composed: true, // propagate across the shadow DOM
        }));
      };
    
       function handleClose(event) {
           event.preventDefault();
           // dispatching collpase event
           dispatchWcEvent("collapse", "tooltip")
       }
<script>

<svelte:options tag="my-component"></svelte:options>
    
<span class="icon-cross" on:click={event => handleClose(event)}>X</span>

在 Real DOM 中捕获自定义事件(js 文件不是 svelte 项目的一部分)

let shadow = document.querySelectorAll("my-component");
// if you have single occurence then you can skip the foreach loop and use querySelector

shadow.forEach(function(elem) {
  elem.addEventListener("collapse", e => {
    alert('event handled');
  });
});