멋쟁이 사자처럼 FE 2기 - 30

임홍렬·2022년 5월 12일
0
post-thumbnail

220512


DOM


DOM 이란?

DOM은 웹 페이지를 프로그래밍 언어로 조작할 수 있도록 연결시켜주는 역할을 한다.
HTML 개별 요소가 레고 부품이면 제작된 완성품이 DOM이다.
완성했다고해서 조작할 수 없는 상태인 것이 아니라 추가로 생성, 수정, 삭제할 수 있다.
이때 각각의 요소와 속성, 콘텐츠를 표현하는 단위를 '노드(node)'라고 합니다.

Virtual DOM 이란?

실제 조립(DOM)을 하지 않고 가상으로 조립(Virtual DOM)을 해놓고 바뀌는 부품이 있다면 바꿔놓고 조립을 하는 것이다.

Parsing(파싱)이란?

일련의 문자열을 의미있는 token으로 분해하고 이들로 이루어진 parse tree를 만드는 과정을 말한다. 브라우저가 코드를 이해하고 사용할 수 있도록 해주기 위함이다.

트리형 자료구조

HTML 코드를 해석해서 트리 형태로 정보를 표현하는 문서를 생성한다.
property와 method를 통해 문서 구조, 내용, 스타일 등을 변경할 수 있다. 
부모 노드와 자식 노드를 이용해 노드 간 계층 구조를 표현한다.

  • 하나의 자료 뒤에 여러개의 자료가 존재할 수 있는 자료구조이다.
  • tree, graph 해당된다.

  • 하나의 자료 뒤에 하나의 자료만 존재할 수 있는 자료구조이다.
  • array, stack, queue 해당된다.

DOM 트리에 접근하기

// 해당하는 Id를 가진 요소에 접근하기
document.getElementById()

// 해당하는 모든 요소에 접근하기
document.getElementsByTagName();

// 해당하는 클래스를 가진 모든 요소에 접근하기
document.getElementsByClassName();

// css 선택자로 단일 요소에 접근하기
document.querySelector("selector");

// css 선택자로 여러 요소에 접근하기
document.querySelectorAll("selector");

DOM 제어 명령어

이벤트 삽입

target.addEventListener( type, listener )

<button>HELLO!</button>


// 이벤트의 타입에는 click, mouseover, mouseout, wheel 등 다양한 이벤트를 감지합니다.
// listener 함수의 인수에는 이벤트에 대한 정보가 담겨있습니다.

const myBtn = document.querySelector("button");

myBtn.addEventListener('click', function(){
	console.log("hello world");
})

클래스 제어

DOM api를 통해 요소의 class 속성을 제어할 수 있다.
<button>Make me BLUE!</button>


const myBtn = document.querySelector("button");

myBtn.addEventListener('click', function(){


myBtn.classList.add("blue");  // blue 라는 클래스의 속성 값을 지정 할 수 있습니다.
myBtn.classList.remove(“blue”); // 클래스를 제거합니다.
myBtn.classList.toggle(“blue”); // 클래스를 토글합니다. 없으면 넣어주고, 있으면 제거합니다.
myBtn.classList.contains(“blue”); // 해당하는 클래스가 있는지 확인합니다.
})

요소 제어

<ul></ul>
<button>Make me MORE!</button>


// document.createElement(target); target 요소를 생성합니다.
// document.createTextNode(target); target 텍스트를 생성합니다.
// element.appendChild(target);    target 요소를 element의 자식으로 위치합니다.
// element.removeChild(target);    element의 target 자식 요소를 제거합니다.

const myBtn = document.querySelector("button");
const myUl = document.querySelector("ul");

myBtn.addEventListener('click', function(){
	for(let i=0; i < 5; i++){
		const myLi = document.createElement('li');
		myUl.appendChild(myLi);
	}
})
<div id="parentElement">
    <span id="childElement">hello guys~</span>
</div>


// parentElement.insertBefore(target, location); target요소를 parentElement의 자식인 location 위치 앞으로 이동합니다.

var span = document.createElement("span");
var sibling = document.getElementById("childElement");
var parentDiv = document.getElementById("parentElement");
parentDiv.insertBefore(span, sibling);

JavaScript 문자열을 사용해 element, text 노드를 생성하거나 추가하기

DOM api를 이용하면 요소 안의 값에 접근하여 값을 가져오거나, 변경할 수 있습니다.
<p></p>
<input type="text">
<button>Write Something!</button>


const myBtn = document.querySelector("button");
const myP = document.querySelector("p");
const myInput = document.querySelector("input");

myBtn.addEventListener('click', function(){
	myP.textContent = myInput.value;
});

// input 요소에 'input' 이벤트를 연결하면 실시간으로 값이 반영되게 만들 수도 있습니다.
myInput.addEventListener('input', ()=>{
  myP.textContent = myInput.value;
});

myP.innerHTML = "<strong>I'm Strong!!</strong>";
myP.outerHTML = "<div></div>";

// innerHTML 은 요소(element) 내에 포함된 HTML 마크업을 가져오거나 설정합니다.
// innerText 속성은 요소의 렌더링된 텍스트 콘텐츠를 나타냅니다. (렌더링된에 주목하세요. innerText는 "사람이 읽을 수 있는" 요소만 처리합니다.)
// textContent 속성은 노드의 텍스트 콘텐츠를 표현합니다.

더 인접한곳(Adjacent)으로 정밀하게 배치하기

insertAdjacentHTML : 요소 노드를 주어진 위치에 배치합니다.
<strong class="sayHi">
    반갑습니다.
</strong>


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>');

DOM 안에서 노드 탐색하기

<!-- 주석입니다 주석. -->
<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>


const cont = document.querySelector(".cont");
console.log(cont.firstElementChild);  // 첫번째 자식을 찾습니다.
console.log(cont.lastElementChild);   // 마지막 자식을 찾습니다.
console.log(cont.nextElementSibling); // 다음 형제요소를 찾습니다.
console.log(cont.previousSibling);    // 이전 형제노드를 찾습니다.
console.log(cont.children);           // 모든 직계자식을 찾습니다.
console.log(cont.parentElement);      // 부모 요소를 찾습니다.

이벤트 객체

이벤트에서 호출되는 핸들러에는 이벤트와 관련된 모든 정보를 가지고 있는 매개변수가 전송된다.
<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>


const btnFirst = document.querySelector('.btn-first');
btnFirst.addEventListener('click', (event) => {
    console.log(event);
});

이벤트 흐름

브라우저 화면에서 이벤트가 발생하면 브라우저는 가장 먼저 이벤트 대상을 찾기 시작한다.

  • 브라우저가 이벤트 대상을 찾아갈 때는 가장 상위의 window 객체부터 document, body 순으로 DOM 트리를 따라 내려간다. 이를 캡처링 단계라고 한다.

이때 이벤트 대상을 찾아가는 과정에서 브라우저는 중간에 만나는 모든 캡처링 이벤트 리스너를 실행시킨다.
(true 를 주지 않는다면 캡쳐링 단계에서 실행되지 않는다)그리고 이벤트 대상을 찾고 캡처링이 끝나면 이제 다시 DOM 트리를 따라 올라가며 만나는 모든 버블링 이벤트 리스너를 실행한다. 이를 이벤트 버블링 단계라고 한다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../reset.css">
    <style>
    </style>
</head>

<body>
    <article class="parent">
        <button class="btn" type="button">버튼</button>
    </article>

    <script>
        const parent = document.querySelector('.parent');
        const btnFirst = document.querySelector('.btn');
        btnFirst.addEventListener('click', (event) => {
            console.log("btn capture!");
        })

        window.addEventListener('click', () => {
            console.log("window capture!");
        }, true); // true : 캡처링 단계의 이벤트가 발생하도록 합니다.

        document.addEventListener('click', () => {
            console.log("document capture!");
        }, true);

        parent.addEventListener('click', () => {
            console.log("parent capture!");
        }, true);

        btnFirst.addEventListener('click', (event) => {
            console.log("btn bubble!");
        })

        parent.addEventListener('click', () => {
            console.log("parent bubble!");
        });

        document.addEventListener('click', () => {
            console.log("document bubble!");
        });

        window.addEventListener('click', () => {
            console.log("window bubble!");
        });
    </script>
</body>

</html>

이벤트 target, currentTarget

target 속성에는 이벤트가 발생한 진원지의 정보가 담겨 있습니다. target 속성을 통해 이벤트 리스너가 없는 요소의 이벤트가 발생했을 때도 해당 요소에 접근 할 수 있다.
currentTarget 속성에는 이벤트 리스너가 연결된 요소가 참조되어 있다.
<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);
        console.log(event.currentTarget);
    })
</script>

이벤트 위임

앞에서 우리는 이벤트의 흐름을 통해 이벤트 리스너가 없는 요소의 이벤트가 발생했을 때도 해당 요소에 접근 할 수 있다. 이를 이용해 이벤트 리스너가 없어도 마치 리스너가 있는 것 처럼 사용 할 수 있다.
<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../reset.css">
    <style>
    </style>
</head>

<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>

</html>

이벤트의 this

이벤트 리스너 함수 내부에서의 this 값은 이벤트가 연결된 노드를 참조한다.
<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(this);
    })
</script>
profile
뜨내기 FE 개발자

0개의 댓글