이벤트 위임으로 메뉴 선택 구현하기

이벤트 델리게이션을 사용해 관리하기 편한 메뉴 구조를 만들 수 있습니다.

이벤트 델리게이션을 사용하면, 메뉴 추가나 변경에 따르는 이벤트 처리 작업을 최소화 할 수 있고, HTML/CSS 와 자바스크립트가 깨끗하게 분리되기 때문에 유지보수 및 협업에서도 유리합니다.

아래와 같은 구조를 가지는 가로 메뉴를 이벤트 델리게이션으로 메뉴 클릭 이벤트 처리를 해보겠습니다.

메뉴 항목 클릭시 AJAX로 페이지 내용을 가져와 페이지 갱신 없이 메뉴를 이동하는 웹사이트 제작에 사용할 수 있습니다.

예제의 CSS는 기본 레이아웃만 적용되어있습니다.

각 메뉴 항목은 이벤트 버블링을 이용한 이벤트 델리게이션 사용 예를 보기 위해 여러겹의 태그로 감싼 것입니다.

<style>    .menuwrap{        width: 100%;        text-align: center;    }          .menu{      position: relative;      margin: 0 auto;      list-style: none;    }    .menu li{      font-size: 0.9375em;      padding: 5px 15px;      text-align: center;      display: inline-block;      cursor: pointer;      padding: 10px;    }    .menu li a{        padding: 10px;    }    .menu li a span{        padding: 10px;    }    .active{        font-weight: bold;        border-bottom: 2px solid #a00;        color: #a00;    }  </style>
<div class="menuwrap">    <ul class="menu">        <li class="item" data-menuid="0"><a class="active"><span>메인</span></a></li>        <li class="item" data-menuid="1"><a><span>소개</span></a></li>        <li class="item" data-menuid="2"><a><span>상품</span></a></li>        <li class="item" data-menuid="3"><a><span>고객지원</span></a></li>        <li class="item" data-menuid="4"><a><span>오시는길</span></a></li>    </ul></div>

이벤트 위임(Deligation)으로 메뉴 항목 클릭에 반응하기 위해서는 중첩된 요소들 중에 어떤 것이 클릭한 건지 알아야 합니다.

개별 메뉴 항목 안에 중첩된 내부 요소에 패딩이 있으면 겹치지 않는 영역이 생기면서 <li>, <a>, <span> 중 어느 한 태그 영역을 클릭하게 됩니다.

실제로는 AJAX로 페이지 정보를 가져오기 위해 필요한 정보로 "menuid" 값이 필요하고, <li> 태그의 "menuid" 속성값을 알아야 합니다.

따라서, 중첩된 내부 요소를 클릭한 경우 상위의 <li> 요소 엘리먼트 노드를 알아내야 합니다.

콜백 함수의 이벤트 파라메터 객체에서 클릭한 타겟 요소를 얻은 후 태그 이름에 따라 부모 요소로 올라가 <li> 태그 요소를 얻습니다.

let clickli = event.target.tagName == 'A' ? event.target.parentNode: (event.target.tagName == 'SPAN' ? event.target.parentNode.parentNode : event.target);

<ll> 요소를 얻었으므로 기존 선택 메뉴의 "active" 클래스를 지우고 클릭한 새 메뉴 항목에 "active" 클래스를 추가해 활성화합니다.

마지막으로 새로 선택한 메뉴의 페이지를 가져오기 위한 "menuid" 값을 알아야 합니다.

"clickli.getAttribute('data-menuid')", 또는 "clickli.dataset.menuid" 로 "menuid" 값을 얻습니다.

이벤트 위임을 이용하면 각 메뉴 항목마다 이벤트를 등록할 필요가 없어집니다.없이, 

전체 메뉴 항목 영역에 이벤트 리스너를 등록함으로써 이벤트 버블링(Event Bubbling)으로 올라오는 이벤트를 캡쳐해 선택한 메뉴에 대한 정보를 얻을 수 있습니다.

document.addEventListener('DOMContentLoaded', function(){ // DOM 로딩 후 이벤트 리스너 등록    document.querySelector('.menu').addEventListener('click', function(e){ // 전체 메뉴영역을 클릭하는 이벤트 리스너 등록        //클릭 메뉴 항목 찾기        let target = e.target; // 클릭한 엘리먼트         //UL 리스트 아이템인 <li> 엘리먼트를 얻기 위해 <li> 하위에서 클릭한 태그에 따라 상위 부모를 찾는 방법을 다르게함.        let clickli = target.tagName == 'A' ? target.parentNode: (target.tagName == 'SPAN' ?            target.parentNode.parentNode : target);                if(clickli){            //현재 활성 메뉴 초기화            let currentCategory = document.querySelector('.menu a.active');            if(currentCategory){                currentCategory.classList.remove('active');            }                        //새 선택 메뉴 활성화            clickli.querySelector('a').classList.add('active');
            let pageURL = "/api/page?menuid="+clickli.getAttribute('data-menuid');            //AJAX로 새로 로딩할 새 페이지 내용을 가져옴.        }    });});