JS

JS(13) DOM(Document Object Model)

UserDonghu 2023. 8. 26. 22:32

DOM (Document Object Model)

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

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

 

DOM 트리에 접근하기

document 객체를 통해 HTML 문서에 접근 가능

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

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

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

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

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

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

 

DOM 제어 명령어

 

이벤트 삽입

target.addEventListener(type, listener)

<button>버튼</button>
const myBtn = document.querySelector("button");

//버튼을 클릭하면 로그에 hello world 출력
myBtn.addEventListener('click', function(){
	console.log("hello world");
})

 

클래스 제어

target.classList

<div>박스</div>
const box = document.querySelector("div");

// click했을때 box라는 div가 red클래스 값을 갖고있으면 제거, 아니면 추가
box.addEventListener('click', function(){
	if(box.classList.contains("red")){
    	box.classList.remove("red");
    }else{
    	box.classList.add("red");
    }
    // box.classList.toggle("red"); 한줄로 red 가 없으면 넣어주고, 있으면 제거함
})

 

요소 제어

document.createElement(target) : target 요소를 생성

document.createTextNode(target) : target 텍스트를 생성

element.appendChild(target) : target 요소를 element의 자식으로 위치

element.removeChild(target) : element의 target 자식 요소를 제거

element.append(target) : target 요소를 element의 자식으로 위치. appendchild와 다른점은 여러개의 노드를 한번에, 텍스트도 자식 노드로 포함 가능.

target.remove() : target 요소를 제거

parentElement.insertBefore(target, location) : target요소를 parentElement의 자식인 location 위치 앞으로 이동

target.innerHTML : target 안에 HTML 마크업을 가져오거나 설정. 마크업으로 변환할 수 있으면 마크업으로, 없다면 그냥 문자열로 설정

 

예시1)

<ul>
</ul>

<input />

<button>버튼!</button>

// 요소들을 변수에 할당
const myBtn = document.querySelector("button");
const myUl = document.querySelector("ul");
const myInput = document.querySelector("input");

// myBtn을 클릭했을때 이벤트 리스너 함수 추가
myBtn.addEventListener('click',function(){
	const inputText = myInput.value; // myInput안에 텍스트 값
    if(inputText.trim() === ""){ // inputText의 앞뒤 공백을 없앤것이 빈값이면
    	return; // 리턴으로 함수를 끝냄. (아무동작 안함)
    }else{ // 값이 있으면
    	myInput.value=""; // myInput의 값을 공백으로 초기화
    }
    const myLi = document.createElement("li"); // li를 생성
    const btnDel = document.createElement("button"); // 버튼을 생성
    const btnTxt = document.createTextNode("완료"); // 텍스트 생성
    btnDel.append(btnTxt); // 생성한 버튼에 텍스트 추가
    btnDel.addEventListener('click', () => { // 생성한 btnDel 버튼을 클릭하면 myLi를 삭제
    	myLi.remove();
    });
    myLi.append('할일 : ', inputText, btnDel); // myLi에 자식요소로 텍스트와 btnDel을 추가
    myUl.appendchild(myLi); // myUl에 myLi를 자식요소로 추가
})

input에 텍스트 입력후 버튼!을 누르면 이렇게 나옴. 완료 누르면 remove

 

예시2)

<p></p>
<input type="text">
<button>강조</button>
const myBtn = document.querySelector("button");
const myP = document.querySelector("p");
const myInput = document.querySelector("input");

myInput.addEventListener('input', () => { // input안의 텍스트 실시간으로 p에 추가됨
    myP.textContent = myInput.value;
});

// 버튼 클릭했을때 강조하고, 이미 강조되어있으면 강조해제
myBtn.addEventListener('click', function () {
    if (myP.style.fontWeight === "bold") {
        myP.style.fontWeight = "";
        myBtn.textContent = "강조"
    }else{
        myP.style.fontWeight = "bold";
        myBtn.textContent = "강조해제";
    }
});

 

속성제어

target.style.속성 : ex) target.style.color = "red";

주의) 속성이 대쉬(-)를 통해 여러 단어로 나눠져있는 경우, 카멜케이스를 사용 (font-weight => fontWeight), float속성의 경우 예약어로 존재하므로 cssFloat로 사용.

 

target.getAttribute(속성) : 요소의 특정 속성 값에 접근

target.setAttribute(속성, "") : 요소의 특정 속성 값에 접근하여 값을 수정

<p id = 'myP'>이것은 나의 P요</p>
<img src = "https://어쩌구저쩌구">



<script>
	const target = document.querySelector('p');
    const myimg = document.querySelector('img');
	const idAttr = target.getAttribute('id');
    console.log(idAttr); // myP
    
    myimg.setAttribute("src", "https://이사진으로할게요");
    console.log(myimg.getAttribute('src')); // https://이사진으로할게요
</script>

 

data속성

data-* 속성을 사용하면 HTML 요소에 추가적인 정보를 저장해서 객체처럼 사용 가능. 단, data속성 이름에 콜론이나 영문 대문자 안됨.

<img
    class = "MacbookPro"
    src = "img.jpg"
    data-cpu = "M1"
    data-ram = 16
    data-ssd = 256
>

<script>
    const img = document.querySelector('img');
    console.log(img.dataset); // DOMStringMap {cpu: "M1", ram: "16", ssd: "256"}
    console.log(img.dataset.cpu); // M1
    console.log(img.ssd); // 256
</script>

 

이벤트 객체

이벤트와 관련된 모든 정보를 가지고 있는 매개변수

<div class="box">박스입니다</div>
const myBox = document.querySelector('.box');
myBox.addEventListener('click', (event) => {
	console.log(event);
});
//MouseEvent {isTrusted: true, screenX: -1007, screenY: 124, clientX: 13, clientY: 16, …}

 

이벤트 흐름

브라우저에서 이벤트가 발생하면 이벤트 발생을 찾음

캡처링 단계 : 가장 상위의 window 객체부터 document, body 순으로 DOM트리를 따라 내려가면서 모든 캡처링 이벤트 리스너를 실행.

버블링 단계 : 다시 DOM트리를 따라 올라가며 만나는 모든 버블링 이벤트 리스너를 실행.

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

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

<head>
    <meta charset="UTF-8">
    <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 : 이벤트가 발생한 진원지의 정보. 이를 통해 이벤트 리스너가 없는 요소에서 이벤트가 발생했을 때도 해당 요소에 접근 가능

이벤트.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>

버튼3을 눌렀을때 target에는 버튼3이, currentTarget에는 이벤트 리스너가 연결된 article의 요소가 나온다.

 

<script>
        const parent = document.querySelector('.parent');
        parent.addEventListener('click', function (event) {
            console.log(event.target);
            if (event.target.nodeName === "BUTTON") { // 타겟이 버튼이면
                event.target.textContent = "버튼4"; // 버튼안에 text를 버튼4로 바꿔버림
            }
        })
</script>

이런식으로 이벤트를 위임해서 이벤트 리스너가 없는 요소에 이벤트가 발생했을 때도 있는 것 처럼 사용.

 

이벤트 취소

이벤트.preventDefault() : 브라우저의 기본 이벤트 동작을 취소

이벤트.stopPropagation() : 이벤트 전파를 막기

<form action="#">
	<button type="submit" class="submit">제출</button>
</form>

<script>
	const $form = document.querySelector("form");
	$form.addEventListener("submit",(e)=>{
		console.log(e); // SubmitEvent {isTrusted: true, submitter: <button class="submit">, type: "submit", target: <form>, currentTarget: <form>, …}
		e.preventDefault(); // preventDefault로 submit버튼을 눌러도 아무 동작이 일어나지 않음.
	})
</script>
<script>
    const submit = document.querySelector('.submit');
    submit.addEventListener('click', (event) => {
        console.log('clicked');
        event.preventDefault(); // 버튼을 눌러도 submit되지않음. 지우면 새로고침되고 #으로 action함
        event.stopPropagation(); // 이벤트 전파를 막음.
    });
    document.body.addEventListener('click', () => {
        console.log('event still alive!'); // 이벤트 전파를 막아서 실행되지않음. stopPropagation을 지우면 클릭할때 실행됨
    });
</script>

'JS' 카테고리의 다른 글

JS 실습 - 쇼핑몰 간단하게 만들기  (0) 2023.08.28
JS(14) 동기 비동기 ★★중요  (0) 2023.08.28
JS(12) JSON  (0) 2023.08.25
JS(11) 전개구문과 디스트럭쳐링(구조 분해 할당)  (0) 2023.08.25
JS(10) 조건문과 반복문  (0) 2023.08.24