DOM은 Document Object Model의 약자로, HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation)할 수 있는 Model입니다.
즉, dom은 javascript가 아니라 javascirpt로 html을 조작할 수 있게 해주는 인터페이스 같은 존재합니다.
javascript로 html을 조작하기 위해선 DOM을 사용해야 합니다.
제가 생각하기에 가장 중요한 CRUD(Create, Read, Update and Delete)에 대해 먼저 아는게 중요하다고 생각합니다.
document 객체를 통해서 HTML 엘리먼트를 만들고(CREATE), 조회하고(READ), 갱신하고(UPDATE), 삭제하는(DELETE) 하는 방법과 HTML 요소 연결시켜주는 적용(APPEND)하는 메소드가 있습니다.
각 기능에 대해서 알아보고 어떤 메소드를 사용 하는 지 확인해봅시다.
먼저 CRUD에서 CREATE에 대해서 설명하겠습니다.
document.createElement('div')
엘리멘트를 만들기 위해서는 createElement 메소드를 사용해야 합니다.
Console.log에 document.createElement('div'); 입력해보면 <div>
태그가 나오는것을 알수있습니다.
하지만 <div>
태그가 생성 되었다고 해서 화면에 변화가 나타나는 것은 아닙니다.
그 이유는 <div>
라는 요소가 특정 엘리먼트에 연결되어있는게 아니라 혼자만 공중에 떠 있는 상태라고 생각하시면 됩니다.
해당 <div>
요소를 연결시키기 위해서는 APPEND를 해야합니다.
append를 붙이다는 뜻으로 부모 요소에 태그를 연결시켜준다고 생각하면 쉽습니다.
먼저 append라는 메소드를 사용해서 newDiv
를 부모 태그인 body에 넣어보겠습니다.
const newDiv = document.createElement('div');
document.body.append(newDiv);
create에 배웠던 document.createElement('div');
로 newDiv라는 새로운 변수를 생성하고 append 메소드를 활용해 body 엘리먼트에 append합니다.
append
메소드 외에 appendChild
라는 메소드도 존재합니다.
일단 두 메소드의 공통점은 둘 다 부모 요소에 추가해주는 역할입니다.
🙋 두 메소드가 어떻게 다른지 왜 메소드가 2개가 존재 하는지 확인해보겠습니다.
🧐 append는 한 번에 여러 개의 자식 요소를, appendChild는 한 번에 하나의 자식 요소만 추가.
li.append(span, p, div); // ok
ul.appendChild(li); // ok
li.appendChild(span, p, div); // not ok
🧐 append는 Node object
or DOMString objects
을 추가할 수 있고, appendChild는 Node object만
추가 가능합니다.
즉, append 를 쓰면 string
도 추가할 수 있습니다.
const div = document.createElement('div');
const span = document.createElement('span');
div.append('hello', span); // ok
div.appendChild(span); // ok
div.appendChild('hello', span); // not ok
🧐 append는 return 값을 반환하지 않지만, appendChild는 붙인 Node object 값을 반환합니다.
차이점을 확인했을 때 기능이나 확장성에서 append() 가 뛰어나기 때문에 append() 를 사용하는 것이 좋다고 생각합니다.
그렇다면 append를 하기 위해선 어떻게 부모 요소를 찾아야 할까요??
요소를 찾는 방법으론 getElementById,querySelector,querySelectorAll 등이 있습니다.
3가지 메소드가 어떤 기능을 가지고 있는지 알아봅시다.
1. getElementById()는 무엇인가?
element = document.getElementById(id);
id를 통해 엘리먼트를 반환합니다. 만약 document에 구체적인 ID의 엘리먼트가 없다면 null을 반환합니다.
2. querySelector()는 무엇인가?
element = document.querySelector(selectors);
selector의 구체적인 그룹과 일치하는 document안 첫번째 엘리먼트를 반환합니다. 일치하는게 없으면 null을 반환합니다.
3. querySelectorAll()는 무엇인가?
document.querySelectorAll('.fruit')
클래스 이름이 fruit
인 엘리먼트가 여러 개 있다고 가정해봅시다.
여러 개의 엘리먼트를 한 번에 가져오기 위해서는, querySelectorAll 을 사용합니다. 이렇게 조회한 HTML 엘리먼트들은 배열처럼 for문을 사용하실 수 있습니다.
⛔️ 하지만 실제 배열은 아니니 주의하세요!
앞서 조회한 HTML 엘리먼트들은 배열이 아닙니다! 이런 '배열 아닌 배열'을 유사 배열, 배열형 객체 등
다양한 이름으로 부릅니다. 정식 명칭은 Array-like Object
입니다.
querySelector(),querySelectorAll()만으로 대부분 조회가 가능해서 getElementById()는 많이 사용하지 않지만 이전 버전의 브라우저 호환성을 신경써야 한다면 옛날 방식을 사용할 수도 있으니 알아두는 것이 좋습니다.
그럼 지금까지 배운 내용을 콘솔로 찍어보겠습니다.
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
container id를 가지고 있는 div요소를 찾아서 새로 만든 tweetDiv를 append 시켜주었습니다.
추가 학습 리스트
제일 처음으로 검색되는 div를 반환하거나, div가 없다면 null을 반환합니다
아래 예제처럼 정말 강력한 선택자도 사용할 수 있습니다. 예제의 결과는 클래스가 "user-panel main"인
<div>(<div class="user-panel main">)
안의, 이름이 "login"인<input>
중 첫 번째 요소입니다.
var el = document.querySelector("div.user-panel.main input[name=login]");
document 하위의 어떤 객체든 자식 엘리먼트를 가지고 있다면 querySelector의 부모가 될 수 있습니다.
학습 자료
추가가 아닌 기존에 존재하는 요소를 업데이트하는 방법에 대해 알아봅시다.
text를 추가하기 위한 textContent
와 class를 추가하기 위한 classList.add()
메소드가 존재합니다.
console.log(oneDiv) // <div></div>
oneDiv.textContent = 'dev';
console.log(oneDiv) // <div>dev</div>
testContent를 이용해 문자열을 입력하여 추가합니다.
newDiv.classList.add('fruit')
console.log(newDiv) // <div class="fruit">dev</div>
classList.add를 이용해 'fruit' 클래스를 추가합니다.
textContent 말고도 innertext가 존재하며, class와id 뿐만 아니라 다른 Attribute 를 추가하고 싶으면 setAttribute()메소드를 사용하면 됩니다.
const container = document.querySelector('#container')
const newDiv = document.createElement('div')
container.append(tweetDiv)
tweetDiv.remove() // 이렇게 append 했던 엘리먼트를 삭제할 수 있습니다.
document.querySelector('#container').innerHTML = '';
이렇게 값을 삽입하여 변경하는 건 매우 쉬운 방법이지만 보안 위험으로 추천하지 않는 방법입니다.
참고 자료: MDN문서
3-1. 첫 번째 자식 엘리먼트만 제거합니다.
onst container = document.querySelector('#container');
while (container.firstChild) {
container.removeChild(container.firstChild);
}
3-2. 자식 엘리먼트가 1개만 남을 때까지, 마지막 자식 엘리먼트를 제거 방법입니다.
const container = document.querySelector('#container');
while (container.children.length > 1) {
container.removeChild(container.lastChild);
}
3-3. 클래스 이름이 tweet인 엘리먼트만 찾아서 제거하는 방법입니다.
const fruits = document.querySelectorAll('.fruit')
fruits.forEach(function(fruit){
fruit.remove();
})
// or
for (let fruit of fruits){
fruit.remove()
}
element와 node의 차이 (difference between element and node in javascript dom)
children과 childNodes의 차이 (difference between children and childNodes in javascript dom)
removeChild와 remove의 차이 (difference between removeChild and remove in javascript dom)
tweets에 forEach는 되는데, reduce는 안되는 이유 (why array method is not working on nodelist)
tweets를 유사 배열에서 배열로 바꾸는 방법 (how to convert nodelist into javascript array)