DOM 이벤트 연결
Svelte는 다음의 코드와 같이 on:
디렉티브로 요소에 모든 이벤트를 연결할 수 있습니다.
<div on:mousemove={handleMousemove}> The mouse position is {m.x} x {m.y} </div>
Svelte는 on:click
, on:mousemove
처럼 요소에 이벤트를 연결할 필요가 있을 때, on:eventName의 형태로 속성을 정의해주기만 하면 됩니다.
<script> let m = { x: 0, y: 0 }; function handleMousemove(event) { m.x = event.clientX; m.y = event.clientY; } </script> <div on:mousemove={handleMousemove}> The mouse position is {m.x} x {m.y} </div> <style> div { width: 100%; height: 100%; } </style>
인라인 핸들러
Svelte는 이벤트 핸들러를 인라인으로 선언할 수도 있습니다.
<div on:mousemove="{e => m = { x: e.clientX, y: e.clientY }}"> The mouse position is {m.x} x {m.y} </div>
위 코드에서 따옴표” “가 없어도 에러가 발생하지 않지만, 일부 환경에서는 구문 강조 표시에 유용할 수 있습니다.
참고로 일부 프레임워크에서는 내부 루프와 같은 성능상의 이유로 인라인 이벤트 핸들러를 권장하지 않지만, Svelte에서는 인라인 이벤트 핸들러가 성능상의 제약을 발생시키지 않기 때문에 이런 제약에 대한 고민은 필요없다고 하네요.
<script> let m = { x: 0, y: 0 }; </script> <div on:mousemove="{e => m = { x: e.clientX, y: e.clientY }}"> The mouse position is {m.x} x {m.y} </div> <style> div { width: 100%; height: 100%; } </style>
이벤트 수정자
Svelte의 DOM 이벤트 핸들러는 동작을 변경하는 수정자를 가질 수 있는데, 다음과 같이 once
라는 이름의 수정자가 있는 경우에는 이벤트 핸들러가 한 번만 실행됩니다.
<script> function handleClick() { alert('no more alerts') } </script> <button on:click|once={handleClick}> Click me </button>
이벤트 수정자의 전체 목록은 다음과 같은데, 각 이벤트 수정자는 on:click|once|capture={...}
처럼 함께 연결해서 사용할 수 있습니다.
- preventDefault
- 핸들러를 실행하기 전에
event.preventDefault()
를 호출하며, 클라이언트 측 폼 양식 처리에 유용 - stopPropagation
event.stopPropagation()
을 호출하여 이벤트가 다음 요소에 도달하는 것을 방지- passive
- 터치/휠 이벤트에서 스크롤 성능을 향상시킴(Svelte가 안전한 위치에서 자동으로 추가)
- nonpassive
- 명시적으로 설정,
passive: false
- capture
- 버블링 단계 대신 캡처 단계에서 핸들러를 실행
- once
- 처음 실행된 후 핸들러를 제거
- self
event.target
이 요소 자체인 경우에만 핸들러를 실행- trusted
event.isTrusted
가true
인 경우에만 핸들를 실행(이벤트가 사용자 작업에 의해 트리거된 경우)
컴포넌트 이벤트
컴포넌트는 이벤트를 전달할 수 있는데, 이를 위해 이벤트 디스패처를 만들어야 합니다.
<script> import Inner from './Inner.svelte'; function handleMessage(event) { alert(event.detail.text); } </script> <Inner on:message={handleMessage}/>
<script> import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); function sayHello() { dispatch('message', { text: 'Hello!' }); } </script>
위 코드의 createEventDispatcher
는 컴포넌트가 처음 인스턴스화될 때 호출되어야 하는데, 나중에 내부에서는 호출할 수 없기 때문입니다.
App.svelte는 on:message
디렉티브 덕분에 Inner.svelte가 전달한 메시지를 수신할 수 있는데, 이 디렉티브는 on:
접두사가 붙은 속성으로, on:
접두사의 뒤에는 전달할 이벤트 이름을 적어주면 됩니다. App.svelte에서는 on:message
로 이벤트를 전달하고 있는데, 이 속성이 없으면 메시지는 계속 발송되지만 앱은 반응하지 않습니다.
이벤트의 이름은 다른 이름으로 변경할 수도 있는데, 만약 Inner.svelte에서 dispatch('message')
를 dispatch('myevent')
로 변경했다면 App.svelte에서도 속성의 이름을 on:message
에서 on:myevent
로 변경해 주어야 합니다.
이벤트 포워딩
DOM 이벤트와 달리 컴포넌트 이벤트는 버블링되지 않기 때문에, 일부 깊게 중첩된 컴포넌트에서 이벤트를 수신하기 위해서는 중간 컴포넌트가 이벤트를 전달해야 주어야 합니다.
다음과 같이 App.svelte 및 Inner.svelte 컴포넌트가 있고, <Inner/>
를 포함하는 Outer.svelte라는 컴포넌트가 있을 경우, 이벤트를 전달할 수 있는 방법은 createEventDispatcher
를 Outer.svelte에 추가하고, message
이벤트를 수신하고, 이에 대한 핸들러를 만드는 겁니다.
<script> import Outer from './Outer.svelte'; function handleMessage(event) { alert(event.detail.text); } </script> <Outer on:message={handleMessage}/>
<script> import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); function sayHello() { dispatch('message', { text: 'Hello!' }); } </script>
<script> import Inner from './Inner.svelte'; </script> <Inner on:message/>
위 코드에서 Outer.svelte
의 <Inner on:message/>
는 약어를 사용한 것인데, on:message
와 같이 값을 지정해주지 않는 경우에는 ‘모든 message 이벤트를 전달’하라는 의미가 됩니다.
DOM 이벤트 포워딩
DOM 이벤트에서도 이벤트 전달을 할 수 있는데, 다음과 같이 <CustomButton>
클릭에 대한 알림을 받고 싶다면, CustomButton.svelte의 <button>
요소에 click
이벤트를 전달하기만 하면 됩니다.
<script> import CustomButton from './CustomButton.svelte'; function handleClick() { alert('Button Clicked'); } </script> <CustomButton on:click={handleClick}/>
<button on:click> Click me </button> <style> button { background: #E2E8F0; color: #64748B; border: unset; border-radius: 6px; padding: .75rem 1.5rem; cursor: pointer; } button:hover { background: #CBD5E1; color: #475569; } button:focus { background: #94A3B8; color: #F1F5F9; } </style>