Jak przekazać parametry do: kliknij Svelte?

24

Powiązanie funkcji z przyciskiem jest łatwe i proste:

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

Ale nie widzę sposobu na przekazywanie parametrów (argumentów) do funkcji, gdy to robię:

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

Funkcja jest wywoływana przy ładowaniu strony i nigdy więcej.

Czy w ogóle można przekazać parametry do wywoływanej funkcji on:click{}?


EDYTOWAĆ:

Właśnie znalazłem hackerski sposób, aby to zrobić. Działa wywoływanie funkcji z wbudowanego modułu obsługi.

<button on:click={() => handleClick("parameter1")}>
    It works...
</button>
FelDev
źródło
Tego nie wspomnieli nawet doktorzy. Ale tak, na razie tak myślę ... Dopóki nie wymyślą innego rozwiązania ...
Manish
6
To nie jest hack, to jak to działa . Zostało to wyraźnie wspomniane w samouczku svelte.dev/tutorial/inline-handlers
Rich Harris,
3
Dziękuję za komentarze! Ten „hacky sposób” robienia tego wcale nie jest taki zły, ale odważyłbym się powiedzieć, że dokumenty i samouczek nie mówią o tym zbyt wyraźnie. Może to tylko ja.
FelDev,

Odpowiedzi:

4

TL; DR

Wystarczy zawinąć funkcję modułu obsługi w inną funkcję, aby użyć funkcji strzałki elegancji


Musisz użyć deklaracji funkcji, a następnie wywołać program obsługi z argumentami. Funkcja strzałki jest elegancka i dobra w tym scenariuszu.

DLACZEGO potrzebuję innego opakowania funkcji?

Gdybyś użył tylko modułu obsługi i przekazał parametry, jak by to wyglądało?

Prawdopodobnie coś takiego:

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

Pamiętaj jednak, handleClick("arg1")że w ten sposób wywołujesz funkcję natychmiast, i właśnie tak się dzieje, gdy ujmujesz to w ten sposób, zostanie ona wywołana, gdy wykonanie osiągnie tę linię, a nie zgodnie z oczekiwaniami, PRZYCISK PRZYCISKU ...

Dlatego potrzebujesz deklaracji funkcji, która będzie wywoływana tylko przez zdarzenie click, a wewnątrz niej wywołujesz program obsługi z dowolną liczbą argumentów.

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

Jak zauważył @Rich Harris (autor Svelte) w komentarzach powyżej: To nie jest hack, ale to, co dokumentacja pokazuje również w ich samouczkach: https://svelte.dev/tutorial/inline-handlers

V. Sambor
źródło
12

Rich odpowiedział na to w komentarzu, więc mu to dziękuję, ale sposób wiązania parametrów w module obsługi kliknięć jest następujący:

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

function onDelete (id) {
  ...
}

Aby podać dodatkowe szczegóły dla osób, które również borykają się z tym problemem, a jeśli tak nie jest, powinny one znajdować się w dokumentacji, można również uzyskać zdarzenie click w takim module obsługi:

<a href="#" on:click={event => onDelete(event)}>delete</a>

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
  ...
}
Antony Jones
źródło
Dlaczego używasz linków do przycisków, skoro nie mają one adresu URL?
mikemaccana
Ponieważ buduję PWA, które mają linki jako awarie, więc jest to raczej powód do nawyku. Może to być przycisk.
Antony Jones
1

Mam z tym do czynienia:

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

function onDelete(id) {
}
chovy
źródło
1

Oto metoda debounce i argument zdarzenia:

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


const onKeyDown = debounce(handleInput, 250);

async function handleInput(event){
    console.log(event);
}
chovy
źródło
-1

W dokumentacji nie ma wyraźnego sposobu, a twoje rozwiązanie będzie działać, ale w rzeczywistości nie jest zbyt eleganckie. Moim preferowanym rozwiązaniem jest używanie curry w samym bloku skryptu .

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

I w HTML

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

Uważaj na curry

Jak wspomniano w komentarzach, curry ma swoje pułapki. Najczęstszy z nich, który w powyższym przykładzie handleClick('parameter1')nie zostanie uruchomiony po kliknięciu, ale podczas renderowania, zwracając funkcję, która z kolei zostanie uruchomiona po kliknięciu. Oznacza to, że ta funkcja zawsze używa argumentu jako parametr1.

Dlatego użycie tej metody byłoby bezpieczne tylko wtedy, gdy użyty parametr jest pewnego rodzaju stałą i nie zmieni się po wyrenderowaniu.

To doprowadziłoby mnie do innego punktu:

1) Jeśli jest to stała używana parametr, równie dobrze możesz użyć oddzielnej funkcji

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

2) Jeśli wartość jest dynamiczna, ale dostępna w komponencie, można to nadal obsługiwać za pomocą autonomicznej funkcji:

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

3) Jeśli wartość jest dynamiczna, ale nie jest dostępna z komponentu, ponieważ zależy to od pewnego rodzaju zakresu (np. Listy elementów renderowanych w bloku #each) , podejście „hacky” będzie działać lepiej. Myślę jednak, że w takim przypadku lepiej byłoby mieć elementy listy jako komponent i wrócić do przypadku nr 2

Podsumowując: curry będzie działać w pewnych okolicznościach, ale nie jest zalecane, chyba że jesteś bardzo dobrze świadomy i ostrożny, jak go używać.

Stephane Vanraes
źródło
3
Nie rób tego! Wystarczy utworzyć funkcję wbudowaną ( on:click={() => handleClick('parameter1')})
Rich Harris,
1
Właśnie zdałem sobie sprawę, że to propozycja, na którą odpowiedziałeś. Powód, dla którego odradzam podejście curry, jest dwojaki - po pierwsze, mniej od razu wiadomo, co się dzieje (ludzie zwykle zakładają, że handleClick('parameter1')tak się dzieje, gdy kliknięcie dzieje się niepoprawnie. Po drugie, oznacza to, że moduł obsługi musi być odbijany za każdym razem, gdy zmieniają się parametry, co jest nieoptymalne. Obecnie istnieje błąd, co oznacza, że ​​i tak nie działa svelte.dev/repl/a6c78d8de3e2461c9a44cf15b37b4dda?version=3.12.1
Rich Harris
1
To prawda, że ​​nie byłam świadoma tego błędu, który sam nigdy go nie spotkał. Z drugiej strony w bazie kodu, nad którą pracuję, nigdy nie przekazujemy takiego parametru, prawie zawsze są to obiekty i wydaje się, że działają: svelte.dev/repl/72dbe1ebd8874cf8acab86779455fa17?version=3.12.1
Stephane Vanraes
Zaktualizowałem swoją odpowiedź, dodając pułapki na curry i inne refleksje. Dzięki za wkład
Stephane Vanraes
Ach tak, będzie działać z obiektami, o ile samo odniesienie się nie zmieni (a podstawowy błąd również zostanie naprawiony we właściwym czasie)
Rich Harris,