728x90

JavaScript 이벤트 전파 중단 방법 (IE 대응 추가)

자바스크립트

자바스크립트에서 이벤트 처리를 할 때 계층적으로 이벤트가 실행되는 경우가 있습니다. 이를 이벤트 버블링이라 합니다. 또한, 이벤트 버블링으로 인해 예상하지 못한 결과를 겪을 때가 있습니다. 이에 따른 해결 방법은 다음과 같습니다.

이벤트 수행을 막는 방법

자바스크립트에서 이벤트 수행을 막기 위해서 제공하는 메소드가 몇 가지 있습니다.

  • event.preventDefault()
  • event.stopPropagation()
  • event.stopImmediatePropagation()

각각 어느 상황에 사용되는지에 대해 알아보겠습니다.

부모에게 이벤트가 전파되는 것을 막기

<body>
    <div id="parent">
        <button>클릭</button>
    </div>
</body>
$parentDiv = document.querySelector('#parent');
$button = document.querySelector('button');

$parentDiv.addEventListener('click', function() { alert('click parent') })
$button.addEventListener('click', function() { alert('click button') })

위와 같은 구조의 HTML에서 버튼을 클릭할 경우, 'click button' 알림과 'click parent' 알림이 모두 노출됩니다. 이렇게 이벤트가 상위에 전파되는 것을 막기 위해 event.stopPropagation()을 사용할 수 있습니다.

IE에서는 event.stopPropagation() 대신 event.cancelBubble = true; 구문을 추가하여 해결할 수 있습니다.

$parentDiv = document.querySelector('#parent');
$button = document.querySelector('button');

$parentDiv.addEventListener('click', function() { alert('click parent') })
$button.addEventListener('click', function() {
    alert('click button');

    // 이벤트가 부모에게 전파되는 것을 막습니다.
    if (event.stopPropagation) event.stopPropagation();
    else event.cancelBubble = true; // IE 대응
})

위와 같이 작성하면 버튼을 클릭했을 때 'click parent' 알림이 노출되는 것을 막을 수 있습니다.

동일한 DOM에 걸린 이벤트 막기

<body>
    <div id="parent">
        <button>클릭</button>
    </div>
</body>
$parentDiv = document.querySelector('#parent');
$button = document.querySelector('button');

$parentDiv.addEventListener('click', function() { alert('click parent') })
$button.addEventListener('click', function() { alert('click button') })
$button.addEventListener('click', function() { alert('click button2') })

위와 같은 이벤트가 있을 때, 버튼을 클릭하면 'click button', 'click button2', 'click parent' 알림이 노출될 것입니다. 한 element에 이벤트가 둘 이상이 있을 때 다른 이벤트의 실행을 event.stopImmediatePropagation()으로 막을 수 있습니다.

IE에서는 event.stopImmediatePropagation() 대신 event.isImmediatePropagationEnabled = false; 구문을 추가하여 해결할 수 있습니다.

$parentDiv = document.querySelector('#parent');
$button = document.querySelector('button');

$parentDiv.addEventListener('click', function() { alert('click parent') })
$button.addEventListener('click', function() {
    alert('click button');

    // 동일한 DOM에 걸린 이벤트를 막습니다.
    if (event.stopImmediatePropagation) event.stopImmediatePropagation();
    else event.isImmediatePropagationEnabled = false; // IE 대응
})
$button.addEventListener('click', function() { alert('click button2') })

주의: 실행 순서까지 병경하지는 못합니다.

$parentDiv = document.querySelector('#parent');
$button = document.querySelector('button');

$parentDiv.addEventListener('click', function() { alert('click parent') })
$button.addEventListener('click', function() { alert('click button') })
$button.addEventListener('click', function() {
    alert('click button2');

    // 동일한 DOM에 걸린 이벤트를 막습니다.
    if (event.stopImmediatePropagation) event.stopImmediatePropagation();
    else event.isImmediatePropagationEnabled = false; // IE 대응
})

위와 같이 작성할 경우, 'click button2' 알림은 'click button' 알림이 노출된 이후에 노출되므로 'click button', 'click button2' 두 개의 알림이 모두 노출됩니다.

기본 동작 막기

element가 갖고 있는 기본 동작을 막을 수도 있습니다.

<body>
    <a href="#">클릭</a>
</body>
$a = document.querySelector('a');

$a.addEventListener('click', function() { alert('click a') })

위 코드에서 '클릭'을 클릭한다면 'click a'라는 알림창과 함께 페이지 최상단으로 이동하며, url의 끝에 '#'이 추가될 것입니다. 하지만, event.preventDefault()를 사용하여 엘리먼트 기본 동작을 막을 수 있습니다.

IE에서는 event.returnValue = false; 구문을 사용해 막을 수 있습니다.

$a = document.querySelector('a');

$a.addEventListener('click', function() {
    alert('click a');

    // 동일한 DOM에 걸린 이벤트를 막습니다.
    if (event.preventDefault) event.preventDefault();
    else event.returnValue = false; // IE 대응
})

jQuery를 이용한다면 이벤트 callback 함수에 return false;를 추가하여 기본 동작을 막을 수도 있습니다.

728x90
728x90