It's going to be one day 🍀

안녕하세요! 매일 매일 공부하려고 노력하는 백엔드 개발자 지망생의 공부 흔적입니다.

Front-End/JS

[JS] DOM

2jin2 2024. 1. 15. 21:20

[공부 내용 정리]

DOM (Document Object Model)

- 브라우저에서 제공하는 API

- API : Application Programming Interface. 한마디로 '설명서'

 

DOM API란?

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

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

- 결국 DOM은 수많은 노드들의 집합임.

 

DOM 트리에 접근

- document 객체를 통해 HTML 문서에 접근함.

- document는 브라우저가 불러온 웹페이지를 나타내며, DOM 트리의 진입점 역할.

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

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

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

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

// css 선택자로 **여러 요소**에 접근하기
document.querySelectorAll("selector");
  • 특정한 쿼리(CSS 선택자)를 날려서 접근할 수도 있음(querySelector) -> 가장 많이 사용함!
  • querySelector가 같은 클래스를 갖는 요소를 선택할 경우, 첫 번째(단일요소)만 선택.

DOM 제어 명령어

1. 이벤트 삽입

target.addEvenListener(type, listener) 의 문법 형태를 지님.

<button>HELLO!</button>

 

* JavaScript 제어 명령어는 script 태그 안에 넣어서 실행시켜야함! (따로 파일 분리를 할수도 있음.)

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

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

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

ex) 버튼을 누를때마다 hello world 출력 (11번 수행한 상태)

 

2. 클래스 제어

classList 객체를 통해 요소의 class 속성을 제어할 수 있음.

<button>Make me BLUE!</button>
myBtn.addEventListener('click', function(){
    // blue라는 클래스 속성 값 지정 가능
    
	myBtn.classList.remove("blue"); // 클래스 제거
    myBtn.classList.toggle("blue"); // 클래스 토글(껐다켰다)
    myBtn.classList.contains("blue"); // 해당하는 클래스가 있는지 확인

3. 요소 제어

DOM api를 이용해서 요소를 새롭게 생성하고, 위치하고, 제거할 수 있음.

 

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

DOM api를 이용해서 요소 안의 값에 접근하여 값을 가져오거나, 변경할 수 있음.

<script>
    // 코드를 <body> 태그의 끝에 위치시킴
    const myBtn = document.querySelector("button");
    const myP = document.querySelector("strong");
    const myInput = document.querySelector("input");

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

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

실행 결과

* 둘 다 버튼을 눌렀을 때 div 영역에 내용을 출력하는데 사용하는 프로퍼티

- innerHTML : 태그를 문자열에 입력하면 태그로 인식해서 태그에 맞게 출력됨.

- innerText : 태그를 입력해주어도 문자열 그대로 받아들여서 문자열 그대로 출력됨.

- textContent : 노드의 텍스트 콘텐츠를 표현. 콘텐츠를 단순히 텍스트로만 다룸.

 

5. 속성 제어하기

-> 요소의 style을 제어하는 객체

-> 속성에 접근하고 수정할 수 있는 Attribute 메서드

-> 요소에 데이터를 저장하도록 도와주는 data 속성

 

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

insertAdjacentHTML : 요소 노드를 대상의 인접한 주변에 배치함.

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

실행 화면 - 반갑습니다를 기준으로

 

7. DOM 안에서 노드 탐색하기

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.childNodes);         // 모든 자식노드 찾음.
console.log(cont.parentElement);      // 부모 요소 찾음.
// 자기 자신부터 시작해 부모로 타고 올라가며 가장 가까운 cont 클래스 요소를 찾음. 단, 형제요소는 찾지 않음.
console.log(cont.querySelector('strong').closest('.cont').innerHTML);

 

이벤트 객체

이벤트에서 호출되는 핸들러에는 이벤트와 관련된 모든 정보를 가지고 있는 매개변수가 전송됨. 이것이 바로 이벤트 객체!

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

-> 첫 번째 버튼에만 핸들러를 넣어줌.

 

버튼1을 누를 때 마다 이벤트와 관련된 모든 정보를 가지고 있는 매개변수 전송됨

 

이벤트 흐름

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

출처 - 위니브

버블링 단계한 요소에 이벤트가 발생하면 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작하고, 최상단의 부모 요소를 만날 때까지 반복되면서 핸들러가 동작현상. 아래서부터 위로 올라가는 것

캡쳐링 단계 : 버블링과는 반대로 최상위 태그에서 해당 태그를 찾아 내려가는 것. 위에서부터 아래로 내려가는 것

이벤트 전파 : 이러한 과정에서 이벤트 리스너가 차례로 실행되는 것.

 

이벤트 target, currentTarget

- target : 실제 이벤트가 발생하는 요소. 이 속성을 통해 이벤트 리스너가 없는 요소의 이벤트가 발생했을 때도 해당 요소에 접근 할 수 있음.

- currentTarget : 이벤트 리스너가 달린 요소

 

이벤트 위임

우리는 이벤트의 흐름을 통해 이벤트 리스너가 없는 요소의 이벤트가 발생했을 때도 해당 요소에 접근 할 수 있다는 것을 알게됨. 이것을 이용해 마치 리스너가 있는 것 처럼 사용할 수 있음. 이러한 테크닉을 이벤트 위임이라고 함.

 

이벤트의 this

이벤트 리스너 함수 내부에서의 this 값은 이벤트가 연결된 노드를 참조함.

 

preventDefault()

브라우저의 기본 이벤트 동작을 취소함. 

-> 브라우저의 기본 동작을 중지하고 자바스크립트를 통해 기능을 처리하고자 할 때 사용함.

<body>
<!-- 앵커의 기본 동작을 중지 -->
<a href="https://www.naver.com" class="link">네이버 링크입니다만..</a>
<script>
    const link = document.querySelector('.link');
    link.addEventListener('click', (event) => {
        console.log('clicked');
        event.preventDefault();
    })
</script>

<!-- submit 의 기본 동작을 중지 -->
<form action="">
    <button type="submit" class="submit">제출</button>
</form>
<script>
    const submit = document.querySelector('.submit');
    submit.addEventListener('click', (event) => {
        console.log('clicked');
        event.preventDefault();
    })
</script>
</body>

실행 화면 - 앵커와 제출 버튼 중지됨

 

stopPropagation()

앞서 공부한 preventDefault를 통해 브라우저의 기본 이벤트 동작을 취소할 수 있지만, 이벤트 흐름을 막지는 못함.

따라서 만약 이벤트 흐름을 막고 싶다면 event.stopPropagation() 코드를 추가하면 됨.

 

실습)

<body>
<!-- submit 의 기본 동작을 중지 -->
<h1>나의 todo list</h1>
<p>1. 오늘 저녁에는 부대찌개를 끓여 먹겠다.<button type="button">삭제</button></p>
<p>2. 후식으로 슈팅스타를 먹겠다.<button type="button">삭제</button></p>
<p>3. 자기 전에 반드시 내일 아침 메뉴를 생각해두겠다.<button type="button">삭제</button></p>

<script>
	// 각 <p> 태그에 대해 반복문 실행
    const txts = document.querySelectorAll('p');
    txts.forEach((item)=>{
    	// 클릭 이벤트 리스너 추가
        item.addEventListener('click', (event)=>{
        	// 그 텍스트 내용을 알림창으로 표시함.
            alert(event.target.childNodes[0].data);
        });
    });
	// 각 <button> 태그에 대해 반복문 실행
    const btns = document.querySelectorAll('button');
    btns.forEach((item)=>{
    	// 클릭 이벤트 리스너 추가
        item.addEventListener('click', (event)=>{
        	// 확인 대화 상자를 통해 삭제 여부 물어봄.
            const reselt = confirm('삭제하시겠습니까?');
            // 이벤트 전파를 중지 (부모 요소의 클릭 이벤트 등을 방지함.)
            event.stopPropagation();
            
            // 확인을 선택하면 해당 <P> 요소를 삭제함.
            if(reselt){
                event.target.parentElement.remove();
            }
        });
    })
</script>
</body>

실행화면


처음 배우는 DOM 개념은 너무 어려웠다.. 이해 안되는 건 구글링하고 유튜브 찾아보며 겨우 이해했지만 앞으로 다양한 코드를 직접 써보고 고생하며 알아가야 진정 익숙해질 것 같다. 갈길이 머니까 더 열심히 하자!!

'Front-End > JS' 카테고리의 다른 글

[JS] 객체지향 프로그래밍  (0) 2024.01.15
[JS] This  (0) 2024.01.12
[JS] Type(배열, 객체)  (0) 2024.01.12
[JS] for문/while문  (1) 2024.01.11
[JS] 변수/함수/조건문  (0) 2024.01.10