1. 왜 알아보는가 ?회사에서 Show addEventListener 로 이벤트를 추가하는 것은 어려운 일이 아닙니다. 콜백으로 사용하는 함수의 경우 기존 mouse event에서 콜백으로 사용하는 함수를 사용하면 되기에 별 문제가 없을 것이라 생각했습니다. 그러나 터치 이벤트는 사용하는 기기가 바뀌기 때문에 고려해야 할 사항들이 꽤 있었습니다. 제가 직면한 문제는 다음과 같습니다.
그래서 알아보도록 하면서 같이 이것 저것 알아보려고 합니다. 2. 이벤트의 흐름stackoverflow에 있는 글인 What is event bubbling and capturing? 에서 좋은 자료와 이미지를 찾았습니다. 2.1 Event의 PhaseDom event는 총 4가지의 실행 단계를 가지고 있습니다.
설명만 봐서는 자세히 이해가 되지 않기에 간단한 실습을 진행 해 봤습니다. 2.2 이벤트 버블링한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작합니다. 가장 최상단의 조상 요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작합니다.
위와 같은 코드를 작성하고 실행을 해보면, d3 => d2 => d1 순으로 호출이 됩니다. 자바스크립트의 이벤트들은 대부분 버블링되며 캡처링 되는 일은 거의 없습니다. 또한, 현대 브라우저들은 기본적으로 모든 이벤트들을 버블링 하게 끔 구현 되어 있습니다. 2.3 이벤트 캡처링이벤트 버블링과 반대로 동작하는 과정입니다.
이경우 d1 => d2 => d3 순으로 나타나게 됩니다. 여기서 재미있는 것을 발견했습니다. d3 만 capute: true 일 경우 이벤트 캡처링이 일어나지 않습니다. 그 이유는 d3의 부모 들이 버블링 단계를 따르기 때문입니다. 그렇기에 capture를 사용할 경우 DOM TREE내에서 캡처링할 부모와 자식의 관계를 잘 살펴보고 옵션을 넣어줘야 할 것 같습니다.
그렇다면 캡처링은 왜 나타난 걸까요? MDN의 이벤트 입문 을 보면 다음과 같습니다.
2.4 이벤트 위임이런 브라우저의 구조 때문에 우리는 버블링을 겪게 되고, 이를 피하고 싶을 경우도 생길 것 입니다. 이 때 event.stopPropagation() 을 사용함으로써 이벤트의 전파를 막을 수 있습니다. 이벤트 버블링은 유용하게 쓰일수도 있습니다. 이벤트 위임 이라는 기법을 쓸 수 있기 때문입니다. 이벤트 위임이란, 다수의 자식 요소 중 하나를 선택했을 때 같은 이벤트 함수를 호출하길 원하면 자식 요소에 이벤트를 다 걸어주는게 아닌, 부모에 설정하고 자식에게서 일어난 이벤트가 부모에게 올라오게 하여 효율적으로 코드를 작성할 수 있게 합니다.
위 예시 코드의 경우 아래 사진 처럼 나타나게 됩니다.
여기서 저 숫자를 누르게 되면, 해당 숫자를 alert하게 됩니다.
2.5 이벤트 전파 막기캡처링의 경우 개발자가 직접 옵션을 줘야 합니다. 그렇기에 캡처링에 이벤트 전파를 막을 일은 거의 없을 것입니다. 3. 브라우저 기본 동작상당수 이벤트는 발생 즉시 브라우저에 의해 특정 동작을 자동으로 수행합니다. 3.1 브라우저 기본 동작 막기브라우저 기본 동작을 막는 방법은 두가지가 있습니다.
3.2 passiveaddEventListener의 세번째 인자로 객체를 넣을 경우, passive라는 옵션을 넣을 수 있습니다. passive가 true 를 가지게 되면, 브라우저에게 preventDefault()를 호출하지 않겠다고 알립니다. 저는 여기서 이슈가 있었는데요, 제가 겪었던 이슈와 비슷한 예제를 만들었습니다.
개발자 모드로 디바이스를 Galaxy S5뷰로 봤을 때 저렇게 나옵니다. 동작하는 모습을 보면 이렇게, 저 작은 상자를 움직일 때 화면이이 떨리는 모습을 볼 수 있었습니다. 이 이슈는, 브라우저는 스크롤링을 발생시키는 이벤트를 감지했을 때 먼저 모든 핸들러를 처리하는데, 이때 passive: true 옵션은 핸들러가 스크롤링을 취소하지 않을 것이라는 정보를 브라우저에게 알려주는 역할을 합니다. 이 정보를 바탕으로 브라우저는 화면을 최대한 자연스럽게 스크롤링 할 수 있게 하고 이벤트는 적절하게 처리됩니다. Firefox, Chrome 같은 몇몇 브라우저에서 touchstart 와 touchmove 이벤트의 passive 는 기본값이 true입니다.
설명한 것 처럼, preventDefault를 추가 해 봤습니다.
그러자 다음과 같은 에러로그가 찍히게 됩니다.
touchstart와 touchmove의 경우, 이벤트 기본 passive가 true인데, 이 때 preventDefault를 넣어서 생기는 에러 입니다.
이렇게 하니 에러로그가 나오지 않습니다.! 해결 되었습니다. 3.3 이벤트의 흐름을 막는 것에 대해서event 객체의 프로퍼티중에 defaultPrevented라는 값이 있습니다. 어떤 이벤트를 preventDefault로 막았을 경우 true 아니면 false를 나타내는 값입니다. 이는, eventBubbling을 막기 위해 수 많은 문서에서
4. 마무리이벤트의 종류는 정말 많고, 그 안에서 제가 사용하는 이벤트의 수는 한정적입니다. 또한, 저는 이벤트의 인터페이스로 노출된 것들을 생각 없이 사용했었는데 이번 기회에 조금 더 이해할 수 있는 계기가 되었습니다. 이벤트의 수많은 프로퍼티와 함수, 그리고 디테일한 이벤트(touchmove, touchstart) 및, 제가 앞으로 사용해야 할 이벤트가 있을 때 대충 이벤트의 값만 확인하는게 아닌, 조금더 구체적이고 문제가 될 수 있는 상황을 방지하기 위해 문서를 더 적극적으로 봐야 겠다는 생각이 들었습니다. 참고자료Event.eventPhase |