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를 자식요소로 추가
})
예시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>
<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 |