JS. 이벤트 버블링과 이벤트 위임

MJ·2023년 6월 1일
0

Java Script DOM

목록 보기
16/17
post-thumbnail
post-custom-banner

이벤트 버블링

  • 한 요소에 이벤트가 발생하면 해당 요소의 이벤트를 처리하고 부모요소의 이벤트가
    다음에 실행됩니다.

  • 가장 최상단의 부모요소의 이벤트를 만날 때 까지, 이벤트가 존재하는 모든 부모요소의
    이벤트를 한 번씩 수행합니다.

focus 이벤트와 같이 버블링 되지 않는 이벤트도 있습니다. 몇몇 이벤트를 제외하곤
대부분의 이벤트는 버블링 됩니다.


1.1 이벤트 버블링 확인

<body>
    <p onclick="alert('단락')">
        textsts
        <button onclick="alert('버튼')">Click</button>
    </p>
</body>

이벤트 발생


1.2 이벤트 버블링 중단

  • event.stopPropagation() 이벤트 객체 메서드를 사용해서 버블링을 중단할 수 있습니다.
<head>
   생략
    
    <style>
        .hide {
            display: none;
        }
    </style>

    <title>Poketmon Demo</title>
</head>

<body>
    <div id="container">
        Click To Hide
        <button>Change Color</button>
    </div>

    <script src="./app.js"></script>
</body>
const button = document.querySelector('button');
const container = document.querySelector('#container');

button.addEventListener('click', function () {
    container.style.backgroundColor = randomColor();
})

container.addEventListener('click', function () {
    container.classList.toggle('hide');
})


/* 랜덤색상 추출 함수 */
const randomColor = () => {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);

    return `rgb(${r},${g},${b})`
}

⭐ 이벤트 버블링으로 인해 컨테이너안의 모든 요소는 클릭 시 요소가 숨겨집니다.
버튼 요소를 클릭했을 때, 요소가 숨겨지지 않고 색상이 변경되려면 부모요소의 버블링을
중단해야 한다.


const button = document.querySelector('button');
const container = document.querySelector('#container');

/* 이벤트 객체를 이용해서 버블링 중단 */
button.addEventListener('click', function (e) {
    container.style.backgroundColor = randomColor();
    e.stopPropagation();	// 부모요소의 이벤트에 영향을 받지 않습니다.
})

container.addEventListener('click', function () {
    container.classList.toggle('hide');
})

const randomColor = () => {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);

    return `rgb(${r},${g},${b})`
}

⭐ 이벤트 버블링이 중단되어 부모요소의 이벤트가 발생하지 않습니다.!



이벤트 위임

  • 특정 요소마다 이벤트를 할당하지 않고, 요소의 공통 조상에 이벤트 핸들러를 단 하나만
    할당해도 여러 요소를 한꺼번에 다룰 수 있습니다.

2.1 이벤트 위임 실습

<body>
    <h1>Form Event !</h1>

    <form action="/dogs" id="commentForm">
        <input type="text" name="username" placeholder="username">
        <input type="text" name="comment" placeholder="comment">
        <button>Post Comment</button>
    </form>

    <h2>Comment :</h2>
    <ul>
      	<!-- 클릭 시 삭제될 li 요소 -->
        <li>hey</li>
        <li>hey</li>
    </ul>
    <script src='./app.js'> </script>
</body>
const lis = document.querySelectorAll('li');
const commentForm = document.querySelector('#commentForm');
const ul = document.querySelector('ul');

/* li 요소를 클릭 시, 삭제 이벤트 발생 */
for (let i of lis) {
    i.addEventListener('click', () => {
        i.remove();
    })
}

commentForm.addEventListener('submit', (e) => {
    e.preventDefault();

    /* 변수 및 함수 수정 */
    const userName = commentForm.elements.username;
    const userComment = commentForm.elements.comment;
    newComment(userName.value, userComment.value);

    /* 입력필드 초기화 */
    userName.value = '';
    userComment.value = '';
}
)

/* 댓글 생성 함수 */
function newComment(userName, userComment) {
    /* li 태그와, 컨텐츠를 강조해줄 b 태그 생성 */
    const newComment = document.createElement('li');
    const bTag = document.createElement('b');

    bTag.append(userName);
    newComment.append(bTag);
    newComment.append(` : ${userComment}`);

    ul.append(newComment);
}

⭐ 이벤트 수신기는 처음부터 존재하는 li 요소에 대해서는 작동하지만 새로 추가되는
li 요소에 대해서는 이벤트가 발생하지 않습니다.

즉, 추후에 추가될 요소에 대해서는 이벤트가 발생하지 않는다.


2.1 타겟 대상 확인하기

  • 이벤트 위임을 통해 요소를 지우기 전에, 특정 요소만 지워질 수 있게 target 속성을
    이용해 요소의 내부를 확인해야 합니다.
const commentForm = document.querySelector('#commentForm');
const ul = document.querySelector('ul');

ul.addEventListener('click', (e) => {
    console.log('click');
    console.log(e);
});

commentForm.addEventListener('submit', (e) => {
    e.preventDefault();

    /* 변수 및 함수 수정 */
    const userName = commentForm.elements.username;
    const userComment = commentForm.elements.comment;
    newComment(userName.value, userComment.value);

    /* 입력필드 초기화 */
    userName.value = '';
    userComment.value = '';
}
)

/* 댓글 생성 함수 */
function newComment(userName, userComment) {
    /* li 태그와, 컨텐츠를 강조해줄 b 태그 생성 */
    const newComment = document.createElement('li');
    const bTag = document.createElement('b');

    bTag.append(userName);
    newComment.append(bTag);
    newComment.append(` : ${userComment}`);

    ul.append(newComment);
}

⭐ 이벤트를 적용한것은 ul 요소지만, 이벤트 객체안에 target 속성을 확인해서
사용자가 ul 요소안에 어떤 요소를 클릭했는 지 확인할 수 있다.

확인을 해야하는 이유는 ul 요소안에 li 요소이외에 다른 요소가 있을수도 있기에
타겟을 확인하고, 해당 타겟이 지워야될 요소가 맞다면 속성을 사용하면 됩니다.


const commentForm = document.querySelector('#commentForm');
const ul = document.querySelector('ul');

ul.addEventListener('click', (e) => {
    console.dir(e.target); // 클릭한 요소의 태그명을 확인
});

/* 생략 */

nodeName 속성을 사용해서 사용자가 클릭한 요소가 지워야할 요소가 맞는지
비교하고 필요한 요소만 삭제할 수 있습니다.


2.3 이벤트 위임 진행

const commentForm = document.querySelector('#commentForm');
const ul = document.querySelector('ul');

ul.addEventListener('click', (e) => {
    e.target.nodeName === 'LI' && e.target.remove();
  // 노드명이 'LI'가 맞는 경우에만 우측의 피 연산자(remove)를 수행한다
});

/* 생략 */

⭐ 이렇게 nodeName을 이용해서 삭제해야될 요소만 삭제하고, 삭제하지 말아야할
불필요한 요소는 이벤트 발생을 막을 수 있습니다.

profile
프론트엔드 개발자가 되기 위한 학습 과정을 정리하는 블로그
post-custom-banner

0개의 댓글