【问题标题】:Svelte custom element don't forward eventsSvelte 自定义元素不转发事件
【发布时间】:2023-03-13 00:40:02
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: svelte tabulator svelte-3 svelte-component


    【解决方案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)。

    因此,为了让您的自定义元素拥有自定义事件,您必须使用某种解决方法。例如,这里有一个组件会触发上述 sn-p 中的监听器:

    <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 元素上的 click 或 keydown...

    所以,看来这应该适合你:

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

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

    【讨论】:

      【解决方案2】:

      发生这种情况的原因是因为您正在从格式化程序返回一个 HTML 字符串,这意味着任何 JS 绑定(例如单击事件处理程序)都将被剥离,作为将其转换为字符串的一部分。 (点击函数绑定的上下文将丢失,因为该函数仅在写入字符串的函数中有效,而不是在解析字符串的位置)

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          猜你喜欢
          • 2020-06-17
          • 2021-08-22
          • 2021-12-12
          • 2019-10-14
          • 2021-07-22
          • 1970-01-01
          • 2021-01-25
          • 1970-01-01
          • 2019-10-16
          相关资源
          最近更新 更多