【问题标题】:How to pass parameters to on:click in Svelte?如何将参数传递给 on:click 在 Svelte 中?
【发布时间】:2020-02-04 07:49:06
【问题描述】:

将函数绑定到按钮简单明了:

<button on:click={handleClick}>
    Clicks are handled by the handleClick function!
</button>

但是当我这样做时,我看不到将参数(参数)传递给函数的方法:

<button on:click={handleClick("parameter1")}>
    Oh no!
</button>

该函数在页面加载时被调用,并且永远不会再次调用。

是否可以将参数传递给从on:click{} 调用的函数?


**编辑:**

我刚刚找到了一个 hacky 方法来做到这一点。从内联处理程序调用函数有效。

<button on:click={() => handleClick("parameter1")}>
    It works...
</button>

【问题讨论】:

  • 即使是文档也没有明确提及。但是,是的,我认为现在就是这样。直到他们想出不同的解决方案。
  • 这不是 hack,它是它的工作原理。教程svelte.dev/tutorial/inline-handlers中明确提及
  • 感谢您的 cmets!这种“hacky 方式”毕竟不是那么糟糕,但我敢说文档和教程对此并不是非常明确的。不过,也许只有我一个人。
  • 对于它的价值,on:click{() =&gt; clickHandler(param)} 的原因是,正如 Rich 上面所说,“它是如何工作的”,因为需要将 reference 传递给需要的函数被执行。通过调用on:click{clickHandler(param)},您将立即执行该函数。这不是你想要的。

标签: svelte svelte-3


【解决方案1】:

哈巴狗解决方案

使用!= 分配。是的,分配给!=。诡异如地狱。示例Foo(on:click!='{() =&gt; click(i)}')。这是per documentation for svelte-preprocess (a necessary transpiler to include templates in pug)

Pug 将元素属性内的所有内容编码为 html 实体,因此 attr="{foo &amp;&amp; bar}" 变为 attr="foo &amp;amp;&amp;amp; bar"。为了防止这种情况发生,不要使用= 运算符,而是使用不会编码您的属性值的!= [...] 这也是传递回调所必需的。

就我个人而言,我会为此使用一个 util 函数,因为使用 != 进行分配让我很困扰。

// util fn
const will = (f, v) => () => f(v);
// in pug template we can again assign with =
Foo(on:click='{will(click, i)}')

【讨论】:

    【解决方案2】:

    我正在使用:

    {#each data as item}    
       <li on:click={handle(item)}>{item.name}</li>
    {/each}
    

    ...它在渲染时没有运行该函数,它在点击时起作用。

    【讨论】:

    • 如果你能在 REPL 中证明这对你有用,我会感到震惊。这是一个 REPL,显示这些函数确实会在初始渲染时运行,而不是在点击时运行。 svelte.dev/repl/741340eb0ec34ae89601a1f069747c22?version=3.44.1
    • 你说得对,我不记得我为什么写了它当时有效。
    • 经常发生在我身上,事情停止工作或完全改变如此频繁。
    【解决方案3】:

    TL;DR

    只需将处理函数包装在另一个函数中。为了优雅,请使用箭头功能。


    您必须使用函数声明,然后使用参数调用处理程序。箭头函数很优雅,适合这种情况。

    为什么我需要另一个函数包装器?

    如果你只使用处理程序并传递参数,它会是什么样子?

    大概是这样的:

    <button on:click={handleClick("arg1")}>My awesome button</button>
    

    但是请记住,handleClick("arg1") 这是您立即调用函数的方式,而这正是您这样说时发生的事情,当执行到这一行时它将被调用,并且 不像预期的那样, 按钮点击...

    因此,您需要一个函数声明,它只会由 click 事件调用,并在其中调用您的处理程序,并使用任意数量的参数。

    <button on:click={() => handleClick("arg1", "arg2")}>
        My awesome button
    </button>
    

    正如@Rich Harris(Svelte 的作者)在上面的 cmets 中指出的那样: 这不是 hack,而是文档在其教程中也显示的内容: https://svelte.dev/tutorial/inline-handlers

    【讨论】:

    • 对我来说它不起作用
    • on:click={() =&gt; handleClick("arg1", "arg2")} 是要走的路
    【解决方案4】:

    Rich 在评论中回答了这个问题,所以感谢他,但是在点击处理程序中绑定参数的方法如下:

    <a href="#" on:click|preventDefault={() => onDelete(projectId)}>delete</a>
    <script>
    function onDelete (id) {
      ...
    }
    </script>
    

    为了给同样为此苦恼的人提供一些额外的细节,如果不是,应该在文档中,你也可以在这样的处理程序中获取点击事件: p>

    <a href="#" on:click={event => onDelete(event)}>delete</a>
    <script>
    function onDelete (event) {
      // if it's a custom event you can get the properties passed to it:
      const customEventData = event.detail
    
      // if you want the element, you guessed it:
      const targetElement = event.target
      ...
    }
    </script>
    

    Svelte docs/tutorial: inline handlers

    【讨论】:

    • 为什么在按钮没有 URL 的情况下使用链接?
    • 因为我构建的 PWA 将链接作为后备,所以这更多是习惯的原因。它很容易成为一个按钮。
    • 我认为一个按钮会在页面上提交表单,即使它在表单之外。至少那是我看到的,即使是&lt;button type="button"&gt;...&lt;/button&gt;
    【解决方案5】:

    有发布死亡的风险,请查看https://svelte.dev/repl/08aca4e5d75e4ba7b8b05680f3d3bf7a?version=3.23.1

    可排序的表。注意以一种神奇的方式将参数传递给标题点击处理函数。不知道为什么会这样。可能是自动柯里化?

    【讨论】:

    • 该REPL中的sort函数返回一个函数,该函数处理点击。加载组件时,sort 被调用两次,带有列名,并返回两个函数,一个按 id 排序,一个按 val 排序。
    【解决方案6】:

    这里有一个 debounce 方法和事件参数:

    <input type="text" on:keydown={event => onKeyDown(event)} />
    
    
    const onKeyDown = debounce(handleInput, 250);
    
    async function handleInput(event){
        console.log(event);
    }
    

    【讨论】:

      【解决方案7】:

      我得到了它的工作:

      <a href="#" on:click|preventDefault={onDelete.bind(this, project_id)}>delete</a>
      
      function onDelete(id) {
      }
      

      【讨论】:

        【解决方案8】:

        文档中没有提到明确的方法,您的解决方案会起作用,但确实不是很优雅。我自己的首选解决方案是在 script 块本身中使用 currying

        const handleClick = (parameter) => () => {
           // actual function
        } 
        

        在 HTML 中

        <button on:click={handleClick('parameter1')>
           It works...
        </button>
        

        小心柯里化

        正如 cmets 中提到的,currying 有其陷阱。在上面的例子中,最常见的 handleClick('parameter1') 在点击时不会被触发,而是在渲染时,返回一个函数,该函数又会在点击时触发。这意味着该函数将始终使用“parameter1”作为它的参数。

        因此,只有在使用的参数是某种常量并且一旦渲染后就不会改变时,使用这种方法才是安全的。

        这会让我想到另一点:

        1) 如果它是一个使用参数的常量,你也可以使用一个单独的函数

        const handleParameter1Click = () => handleClick('parameter1');
        

        2) 如果该值是动态的但在组件中可用,则仍然可以使用独立函数来处理:

        let parameter1;
        const handleParameter1Click = () => handleClick(parameter1);
        

        3) 如果值是动态的,但由于依赖于某种范围(例如:#each 块中呈现的项目列表)而无法从组件中获得,则 'hacky'方法会更好。但是我认为在这种情况下最好将列表元素本身作为一个组件并回退到案例#2

        总结:柯里化在某些情况下会起作用,但不建议使用,除非您非常了解并谨慎使用它。

        【讨论】:

        • 不要这样做!只需创建一个内联函数 (on:click={() =&gt; handleClick('parameter1')})
        • 刚刚意识到这是您正在响应的建议。我建议不要使用 currying 方法的原因有两个——首先,发生的事情不太清楚(人们倾向于认为handleClick('parameter1')当点击发生时发生的事情,这是错误的。其次,这意味着每当参数更改时,处理程序都需要重新启动,这是次优的。目前,有一个错误,这意味着无论如何都不起作用svelte.dev/repl/a6c78d8de3e2461c9a44cf15b37b4dda?version=3.12.1
        • 没错,我不知道这个错误我自己从未遇到过。然后再次在我正在处理的代码库中,我们从不传递这样的参数,它们几乎总是对象并且这似乎有效:svelte.dev/repl/72dbe1ebd8874cf8acab86779455fa17?version=3.12.1
        • 我用一些套路的陷阱和其他反思更新了我的答案。感谢您的输入
        • 啊,是的,只要引用本身不发生变化,它就可以与对象一起使用(并且底层错误也会在适当的时候得到修复)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-19
        • 1970-01-01
        • 2021-12-08
        • 2021-12-18
        • 2021-05-14
        • 2020-03-12
        • 2023-02-13
        相关资源
        最近更新 更多