• focusout, blur 이벤트 차이와 이해 :: 마이구미
    Javascript 2018. 6. 9. 15:35

    이 글은 focusout 와 blur 의 차이점을 알아보고, 이벤트 발생에 있어, 주의사항을 다뤄본다.

    다음과 같은 의문 또는 버그가 발생했다면, 글이 도움이 될 것이다.

    focusout 과 blur 의 차이를 알고 싶다.

    focusout 또는 blur 를 사용중 다음과 같은 에러가 발생했다.


    "Uncaught DOMException: Failed to execute 'remove' on 'Element': The node to be removed is no longer a child of this node. Perhaps it was moved in a 'blur' event handler?"


    focusout 과 blur 의 차이


    focusout 는 의미 그대로 엘리먼트가 포커스를 잃었을 때 발생되는 이벤트이다.

    같은 용도로 사용되는 이벤트로 blur 가 있는 것이다.


    둘 사이의 차이점은 버블링 여부이다. => 버블링은 다른 글을 참고바란다. (http://mygumi.tistory.com/315)

    focusout 는 버블링이 일어나고, blur 는 버블링이 일어나지 않는다.


    세트로는 {focusin - focusout} 와 {focus - blur} 로 분류된다.

    다음 예제 코드를 통해 보다 쉽게 이해할 수 있을 것이다.


    See the Pen focusout vs blur by leejunghyun (@mygumi) on CodePen.


    focusout vs blur

    위 예제의 출력값을 보면 focusout 은 자식 -> 부모 순으로 출력되는 것으로 보아 버블링을 확인할 수 있다.

    blur 의 경우에는 포커스를 잃은 자식만이 출력되는 것을 확인할 수 있다.




    Error => Failed to execute 'remove' on 'Element': ......


    위와 같은 에러는 remove 또는 removeChild 와 같은 엘리멘트를 삭제하는 메소드를 사용할 때 주로 발생한다.

    다음과 같은 시나리오를 보자.

    자세한 코드는 다음 링크를 통해 확인하면 된다. => Codepen Example


    • 입력창을 만든다.
    • 생성된 입력창은 ESC 키 또는 포커스를 잃게 되면 삭제된다.


    위 과정을 위해서는 keyup, blur(또는 focusout) 이벤트를 사용하면 된다.


    input.addEventListener("keyup", e => { if (e.keyCode === 27) { e.target.remove(); } }); input.addEventListener("blur", e => { input.remove(); })


    이와 같은 예제에서 ESC 키를 눌렀을 때, 언급했던 에러가 발생되는 것이다.

    왜 발생하는 것일까?

    에러를 해석하면 제거할 엘리먼트가 존재하지 않는다는 식으로 말한다.

    하지만 코드를 보면 전혀 그렇게 될리가 없다고 생각된다.


    이유는 엘리먼트가 제거될 때, 포커스를 잃었다는 이벤트를 발생하게 된다.

    * blur 뿐만 아니라 focusout 도 이와 같이 발생된다.

    이것을 그림으로 표현하면 다음과 같다.


    Failed to execute 'remove' on Element


    위와 같은 흐름 때문에 제거할 엘리먼트가 존재하지 않기 때문에 에러가 발생하게 된다.

    문제를 해결하기 위해서는 많은 방법이 있겠지만, 2가지를 다뤄본다.


    1. 플래그 변수 활용


    input.addEventListener("keyup", e => { if (e.keyCode === 27) { removed = true; // Please set it before the remove(). e.target.remove(); } }); input.addEventListener("blur", e => { if (removed) { return; } input.remove(); })


    2. 다른 이벤트에 제거 위임


    input.addEventListener("keyup", e => { e.target.blur(); });


    keyup 이벤트에서 제거하지 않고, 바로 포커스를 잃는 이벤트를 발생시켜 제거를 위임한다.

    자세한 건 예제 코드 링크를 참고하길바란다.

    TAG

    댓글 0

Designed by Tistory.