ABOUT ME

꾸준히 기록을 가치있게 :) GOGOGO!

Today
Yesterday
Total
  • [Day 31] JS DOM & 이벤트
    TIL/멋쟁이사자처럼 FE스쿨 2기 2022. 5. 12. 23:16
    SMALL

    DOM 은 HTML 문서의 내용을 트리형태로 구조화하여 웹페이지와 프로그래밍 언어를 연결시켜주는 역할을 한다.

    이때 각각의 요소와 속성, 콘텐츠를 표현하는 단위를 '노드(node)'라고 한다.

     

     

    돔 트리에 접근

    document.getElement~

    document.querySelelector(All)~

     

    (*querySelector() 는 코드 초단에만 사용하는 것이 좋다. 실행 시 코드 전체에서 요소를 찾아 실행하기 때문에 메모리 효율이 낮고 코드처리 속도가 느리다.. 그래서 함수 안에서 반복적인 사용은 지양된다.)

     

    돔 제어

    1. 이벤트 삽입 .addEventListener()

    2. 클래스 제어 .classList.[add/remove/toggle/contains]

    3.요소 제어

    document.createElement()

    document.createTextNode()

    element.appendChild()

    element.removeChild()

     

    4. element, text 노드 생성하거나 추가

    element.innerHTML : 텍스트 안에 태그가 있다면 html 태그로 인식하여 파싱한다.

    * 단 <script> 태그는 적용되지 않는다.

    element.textContent : 말그대로 순수한 텍스트를 추가한다.

     

    5.  요소 노드를 원하는 곳에 배치: insertAdjacentHTML()

        <strong class="sayHi">
            반갑습니다.
        </strong>
    
        <script>
            const sayHi = document.querySelector('.sayHi');
            sayHi.insertAdjacentHTML('beforebegin', '<span>안녕하세요 저는</span>');
            sayHi.insertAdjacentHTML('afterbegin', '<span>재현입니다</span>');
            sayHi.insertAdjacentHTML('beforeend', '<span>면접오시면</span>');
            sayHi.insertAdjacentHTML('afterend', '<span>치킨사드릴게요</span>');
        </script>
    
    
    //재현님 진짜죠

    beforbegin은 strong(반갑습니다)태그 바깥

    afterbegin은 strong 태그 안에서 반갑습니다 전에

    beforeend는 strong 태그 안에서 반갑습니다 후에

    afterend는 strong 태그가 끝나고 바깥!

     

    6. 돔 안에서 노드 찾기

    <body>
        <!-- 주석입니다 주석. -->
    <article class="cont">
        <h1>안녕하세요 저는 이런 사람입니다.</h1>
        <p>지금부터 자기소개 올리겠습니다</p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Deserunt incidunt voluptates laudantium fugit, omnis
        dolore itaque esse exercitationem quam culpa praesentium, quisquam repudiandae aut. Molestias qui quas ea iure
        officiis.
        <strong>감사합니다!</strong>
    </article>
    
    <script>
        const cont = document.querySelector(".cont");
    console.log(cont.firstElementChild);  // 첫번째 자식 h1
    console.log(cont.lastElementChild);   // 마지막 자식 strpmg
    console.log(cont.nextElementSibling); // 다음 형제요소 <script>
    console.log(cont.previousSibling);    // 이전 형제요소 여기서는 주석의 줄바꿈이 콘솔에 찍힌다..!
    console.log(cont.children);           // 모든 직계자식 h1, p, strong
    console.log(cont.parentElement);      // 부모 요소 body
    </script>
    </body>

    previousSibling() 콘솔에 찍은 결과.. 줄바꿈(개행문자)도 노드로 인식....

     


     

    이벤트 전파(Event Propagaiton)

    출처: 제코베

     

    돔트리 내 윈도우부터 top to bottom으로 캡처링 이벤트를 찾는데, 이벤트 대상을 찾는 과정에서 브라우저는 발견하는 모든 캡처링 이벤트 리스너를 실행시킨다.

    (캡처링 단계)

     

    캡처링이 끝나면 다시 돔트리를 올라가면서 만나는 모든 버블링 이벤트 리스너를 실행한다. 

    (버블링 단계)

     

    이러한 전체 프로세스에서 캡처링이벤트->버블링 이벤트 순서대로

    이벤트 리스너가 차례로 실행되는 것을 이벤트 전파라고 한다.

     

    보통 버블링의 형태로 이벤트를 많이 실행하는데,

    버블링 이벤트에 캡쳐링을 설정해줌으로써(세번째 파라미터에 true 설정)

    이벤트 실행 순서를 바꾸고 싶을 때 이 개념을 유용하게 사용할 수 있다!

     

    이벤트 전파가 돔트리 내부에서

    캡쳐링->버블링 순서로 가는 것은 브라우저의 기본 원칙이라서 바꿀 수는 없지만

    실행을 멈추게 할 수 있는데, 

     

    그것을 할 수 있는 대표적인 메소드가 바로

    e.stopPropagation()

    e.preventDefalut() 이다!! 

     

    이 둘의 차이점이 핵심인데,

     

    전자는 캡처링 혹은 버블링 단계에서 현재 이벤트의 추가적인 전파(진행)을 막지만,

    디폴트된 behaviors를 막을 순 없다.

     

    예를 들면, a 태그의 링크는 기본적으로 클릭하면 페이지가 이동이 되는데,

    이것은 여전히 실행이 가능하고, 단지 다음 이벤트로 갈 수 없는 것이다.

     

    그러나 후자는 페이지 이동을 막을 수 있다!

    디폴트된 behavior 자체를 막을 수 있다.

    그래서 form의 기본적인 submit 으로 인해 페이지가 리프레쉬되는 것을 막거나

    체크박스에 체크를 못하는 등의 액션을 취할 수 있다!!

     

     

    이벤트 target, currentTarget

     

    target: 이벤트가 발생한 곳

    currentTarget: 이벤트가 발생한 곳에 연결되어 있는 요소

     

    크게 요소를 html, body, div로 나눈다면,

    각각의 입장에서 target과 currentTarget 은 위 그림과 같이 나타낼 수 있다.

     

    위 그림에서 본 것처럼 자식요소의 이벤트는 부모요소에게까지 영향을 미치는데, 

    또 부모의 이벤트도 자식에 영향을 미친다.

     

    이것을 이벤트 위임이라고 한다.

    이벤트 위임을 사용하면 요소 하나하나 핸들러를 주지 않고

    연결되어있는 공통 요소 하나에만 핸들러를 줘도 여러 요소의 이벤트를 다룰 수 있다.

     

    아래 예시를 보자.

    <body>
        <article class="parent">
            <ol>
                <li><button class="btn-first" type="button">버튼1</button></li>
                <li><button type="button">버튼2</button></li>
                <li><button type="button">버튼3</button></li>
            </ol>
        </article>
    
        <script>
            const parent = document.querySelector('.parent');
            parent.addEventListener('click', function (event) {
                console.log(event.target);
                if (event.target.nodeName === "BUTTON") {
                    event.target.innerText = "버튼4";
                }
            })
        </script>
    </body>

     

    리스너함수의 target 을 버튼 전체를 감싸고 있는 parent로 정하고,

    nodeName 이 BUTTON일 경우,(반드시 대문자로 확인한다..!)

    버튼의 innerText를 버튼 4로 바꾼다.

     

     

    클릭 이벤트를 지정해서 클릭하면 

     

     

    이렇게 자식들이 잘 바뀐다

     

     

    근데 이벤트 위임을 쓸 때 조심해야할 점이 있다.

    만약 버튼 안에 다른 요소가 있다면 

        <article class="parent">
            <ol>
                <li><button class="btn-first" type="button">버튼1<span>누르기</span></button></li>
                <li><button type="button">버튼2<span>누르기</span></button></li>
                <li><button type="button">버튼3<span>누르기</span></button></li>
            </ol>

    버튼이 말고도 다른 요소 안에서도 이벤트가 동작할 우려가 있다.

    따라서, event.target 을 이용해 클릭 이벤트가 button 안에서 일어났는지 아닌지 파악해야 한다.

    이러한 우려를 고친 코드는 아래와 같다.

     

     

            const parent = document.querySelector('.parent');
            parent.addEventListener('click', function (event) {
                let btn = event.target.closest('button');  //1
                if (!btn) return; //2
                if (!parent.contains(btn)) return; //3
                 event.target.innerText = "버튼4";  //4
            })

    1) element.closest 메서드로 btn의 상위 요소중 button과 일치하는 가장 가까운 조상 요소를 리턴한다.

    즉, 이벤트가 발생한 요소에서 시작해 가장 가까운 button 요소를 찾는다.

    2) 만약 target이 btn 안에 있지 않으면 null 리턴하며

    3) parent 바깥에 있는 btn 에 적용되는 걸 막기 위해 parent의 btn이 아니면 null을 리턴한다

    4) 이렇게 확인 작업을 다 거친 후에야 버튼4로 이너텍스트를 변경한다.

     

     

     

     

    이 포스팅은

    제코베,

    모던자바스크립트,

    https://ko.javascript.info/event-delegation

    김버그님 유튜브 동영상

    https://www.youtube.com/watch?v=7gKtNC3b_S8

    을 보고

    정리와 응용이 혼합된 글입니다. 

    반응형
Designed by Tistory.