본문 바로가기

프로그래밍/기타

[Vus.JS] 하위 컴포넌트의 Key Event를 막아보자.

서론

 

회사에서는 ckeditor4 라이브러리를 사용해 에디터를 사용하고 있다.

그냥 사용하는 것이 아닌 Modal 창에 띄워놓고 사용하는데, maximize 기능으로 최대화를 할 때 ESC버튼으로 창을 닫을 시 화면이 깨지는 현상이 발생했다.

 

ckeditor 라이브러리 제작자도 Modal에서 사용하면 버그가 발생할 수 있다고 경고했다.

하지만 나는 ITO 서비스를 하고 있고, 고객이 원하는 스펙을 만들기 위해서 Modal에 사용했으니 이제 버그를 고쳐야한다.

 

본론

 

수정하기에 앞서 문제를 정의해봤다.

Modal 창에 있는 ckeditor를 사용할 때 최대화를 하고, 그 상태에서 ESC 버튼을 누르면 화면이 깨진다.

 

이제 ckeditor의 문제인지 Modal의 문제인지 파악을 해야한다.

우선 라이브러리 스펙 상 ESC 버튼을 누른다고 최대화가 풀리거나 하지 않았다.

따라서 Modal에서 처리를 해주고 있다고 가정했다.

 

Modal의 경우 사내 공통 라이브러리에서 가져오는데 해당 코드는 축약해서 이렇게 되어있다.

<template>
    <div @keydown.esc="keyClose" tabindex="-1">
    </div>
</template>

현재 Modal에서 ESC 버튼이 입력될 경우 Modal 창을 닫고 있어서 생기는 문제였다.

 

첫 번째 시도

 

stackoverflow에서는 부모 컴포넌트에서 v-on 키보드 이벤트 리스너를 추가하면 된다고 했다.

 

하지만 "@keydown.esc" 로 발생시킨 이벤트는 부모 컴포넌트로 전파되지 않고 따라서 부모에서 막을 수 없었다.

 

두 번째 시도

 

addEventListener 메소드로 keydown 이벤트를 캡처하고 preventDefault 메소드로 기본 동작을 막아보자.

<div>
    <Child ref="child"/>
</div>

<script>
    mounted() {
        this.$refs.child.$el.addEventListener('keydown', (e) => { e.preventDefault(); }, true);
    }
</script>

 

하지만 첫 번째 시도와 마찬가지로 부모 컴포넌트에서 e.preventDefault()를 해도 이미 자식에서는 keyClose 함수를 시키고 난 뒤였다. 이런 현상은 버블링 현상이라고 한다.

 

마지막 시도

 

최후의 수단으로 자식 컴포넌트의 keyClose 함수를 재정의 하는 방법으로 해결했다.

이는 되도록 권장하지 않는 방법인데, Child Component와 Parent Component가 밀접하게 결합되어 유지보수하기 어렵기 때문이다.

 

하지만 현재 상황이 공통 라이브러리를 가져와 사용하므로 Child Component의 코드를 변경할 수 없다.는 문제점과 @keydown.esc를 사용하고 있어 Parent Component에서 keyClose 호출 제어가 불가능 점 때문에 선택하게 되었다.

 

mounted() {
    this.$refs.child.keyClose = function(){};
}

 

mounted 훅에서 Child Component의 keyClose 함수를 재정의해서 무력화 시켰고, 고객에게도 해당 에디터를 사용하는 경우, ESC로 Modal창을 종료하지 못한다고 안내하며 해당 버그 수정을 완료했다.

 

결론

공통 라이브러리를 제작할 때 v-on을 사용하지 않고 @keydown을 사용한 이유는 모르겠지만... 가져다 쓰는 개발자 입장에서는 확장성이 없다고 느껴졌다.

차라리 키보드 입력으로 종료하는 것을 컴포넌트 호출 시 변수로 조정하게 하면 어땠을까 하는 아쉬움이 남았다.