如何在 Svelte 中将参数传递给 on:click?

How to pass parameters to on:click in Svelte?

将功能绑定到按钮简单直接:

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

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

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

该函数在页面加载时调用,再也不会调用。

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


编辑:

我刚刚找到了一种 hacky 方法。从内联处理程序调用函数有效。

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

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

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

并且在 HTML

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

谨防柯里化

如评论中所述,柯里化有其缺陷。上例中最常见的 handleClick('parameter1') 不会在单击时触发,而是在渲染时触发,返回一个函数,该函数又会在点击时触发。这意味着这个函数将总是使用'parameter1'作为它的参数。

因此,只有当使用的参数是某种常量并且一旦呈现就不会改变时,使用此方法才是安全的。

这会让我想到另一点:

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

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

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

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

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

总而言之:柯里化在某些情况下会起作用,但不推荐使用,除非您非常了解并谨慎使用它。

我用这个解决了这个问题:

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

function onDelete(id) {
}

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

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

为同样为此苦苦挣扎的人提供一些额外的细节,应该在文档中,如果没有,您也可以在这样的地方获得点击事件处理程序:

<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

这是带有去抖动方法和事件参数的:

<input type="text" on:keydown={event => onKeyDown(event)} />


const onKeyDown = debounce(handleInput, 250);

async function handleInput(event){
    console.log(event);
}

TL;DR

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


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

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

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

大概是这样的:

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

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

因此,您需要一个函数声明,它将仅由点击事件调用,并且在其中您可以使用任意数量的参数调用您的处理程序。

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

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

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

或table table。请注意以一种神奇的方式将参数传递给 header 点击处理函数。不知道为什么会这样。 Auto-currying 也许吧?

我正在使用:

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

...它不是 运行 呈现时的功能,它在点击时起作用。

哈巴狗解决方案

!= 赋值。是的,分配 !=。真是太奇怪了。示例 Foo(on:click!='{() => click(i)}')。这是 per documentation for svelte-preprocess (a necessary transpiler to include templates in pug):

Pug encodes everything inside an element attribute to html entities, so attr="{foo && bar}" becomes attr="foo &amp;&amp; bar". To prevent this from happening, instead of using the = operator use != which won't encode your attribute value [...] This is also necessary to pass callbacks.

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

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