Svelte 이벤트 연결하기

Svelte 이벤트 핸들러 다루기

DOM 이벤트 연결

Svelte는 다음의 코드와 같이 on: 디렉티브로 요소에 모든 이벤트를 연결할 수 있습니다.

DOM에 이벤트 연결하기
<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.isTrustedtrue인 경우에만 핸들를 실행(이벤트가 사용자 작업에 의해 트리거된 경우)

컴포넌트 이벤트

컴포넌트는 이벤트를 전달할 수 있는데, 이를 위해 이벤트 디스패처를 만들어야 합니다.

컴포넌트 이벤트 연결
App.svelte
<script>
    import Inner from './Inner.svelte';

    function handleMessage(event) {
        alert(event.detail.text);
    }
</script>

<Inner on:message={handleMessage}/>
이벤트 디스패처 만들기
Inner.svelte
<script>
    import { createEventDispatcher } from 'svelte';

    const dispatch = createEventDispatcher();

    function sayHello() {
        dispatch('message', {
            text: 'Hello!'
        });
    }
</script>

위 코드의 createEventDispatcher는 컴포넌트가 처음 인스턴스화될 때 호출되어야 하는데, 나중에 내부에서는 호출할 수 없기 때문입니다.

App.svelteon:message 디렉티브 덕분에 Inner.svelte가 전달한 메시지를 수신할 수 있는데, 이 디렉티브는 on: 접두사가 붙은 속성으로, on: 접두사의 뒤에는 전달할 이벤트 이름을 적어주면 됩니다. App.svelte에서는 on:message로 이벤트를 전달하고 있는데, 이 속성이 없으면 메시지는 계속 발송되지만 앱은 반응하지 않습니다.

이벤트의 이름은 다른 이름으로 변경할 수도 있는데, 만약 Inner.svelte에서 dispatch('message')dispatch('myevent')로 변경했다면 App.svelte에서도 속성의 이름을 on:message에서 on:myevent로 변경해 주어야 합니다.

이벤트 포워딩

DOM 이벤트와 달리 컴포넌트 이벤트는 버블링되지 않기 때문에, 일부 깊게 중첩된 컴포넌트에서 이벤트를 수신하기 위해서는 중간 컴포넌트가 이벤트를 전달해야 주어야 합니다.

다음과 같이 App.svelteInner.svelte 컴포넌트가 있고, <Inner/>를 포함하는 Outer.svelte라는 컴포넌트가 있을 경우, 이벤트를 전달할 수 있는 방법은 createEventDispatcherOuter.svelte에 추가하고, message 이벤트를 수신하고, 이에 대한 핸들러를 만드는 겁니다.

Outer 컴포넌트 불러오기
App.svelte
<script>
    import Outer from './Outer.svelte';

    function handleMessage(event) {
        alert(event.detail.text);
    }
</script>

<Outer on:message={handleMessage}/>
이벤트 디스패처 설정하기
Inner.svelte
<script>
    import { createEventDispatcher } from 'svelte';

    const dispatch = createEventDispatcher();

    function sayHello() {
        dispatch('message', {
            text: 'Hello!'
        });
    }
</script>
Inner 컴포넌트 불러오기
Outer.svelte
<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 이벤트를 전달하기만 하면 됩니다.

CustomButton 컴포넌트로 이벤트 포워딩하기
App.svelte
<script>
    import CustomButton from './CustomButton.svelte';

    function handleClick() {
        alert('Button Clicked');
    }
</script>

<CustomButton on:click={handleClick}/>
Button 요소로 이벤트 받기
CustomButton.svelte
<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>

답글 남기기