웹 페이지 내의 모든 콘텐츠를 객체(document)로 나타내주는데, 이 객체(document)는 수정이 가능하다.
즉, DOM 구조에 접근한다는 것은 문서와 문서 요소에 접근한다는 것과 같은 원리이다. DOM과 브라우저를 렌더링할 때 다음과 같은 과정을 거친다.
DOM에 따르면, 모든 HTML 태그는 객체이다. 이런 모든 객체는 JS를 통해 접근할 수 있고, 페이지를 조작할 때 이 객체를 사용한다.
예를 들어 document.body는 <body>
태그를 객체로 나타낸 것이다.
DOM은 HTML을 아래와 같은 태그 트리 구조로 표현한다.
사진에서는 포함되지 않았지만 문자는 텍스트 노드가 된다.
개발자 도구를 사용하면 DOM을 검사해보고, 수정할 수 있는데 가장 많이 쓰이는 방법은 Chrome 개발자 도구 문서 사이트이다.https://developers.google.com/web/tools/chrome-devtools 로 가면 다양한 기능을 살펴볼 수 있다.
요소에 id 속성이 있다면 위치에 상관없이 메서드 document.getElementById(id)를 이용해 접근할 수 있다.
혹은 id 속성값을 그대로 딴 전역 변수를 이용해 접근할 수도 있지만 이 방법은 예시로 보여주긴 하겠지만 추천하지 않는다. 전역 변수를 사용하는 것을 지양하기 때문이다.
예시
<!doctype html>
<body>
<!-- getElementById로 요소얻기 -->
<p id="firstP">안녕하세요</p>
<!-- id를 그대로 딴 전역 변수 이용하여 요소얻기 -->
<p id="secondP">반가워요</p>
<script>
// 요소 얻기
let p = document.getElementById('firstP');
// 배경색 변경하기
p.style.background = 'red';
secondP.style.background = 'yellow';
</script>
</body>
결과화면
🚨유의점
id는 유일무이해야 한다. 즉, 문서 내 요소의 id 속성값은 중복되어선 안 된다.
같은 id를 가진 요소가 여러 개 있으면 document.getElementById같이 id를 이용해 요소를 검색하는 메서드의 동작이 제대로 되지 않기 때문이다.
태그나 클래스 등을 이용해 원하는 노드를 찾아주는 메서드도 있다.
elem.getElementsByTagName(tag) – 주어진 태그에 해당하는 요소를 찾고, 대응하는 요소를 담은 컬렉션을 반환한다. 매개변수 tag에 "*"이 들어가면, '모든 태그’가 검색된다.
elem.getElementsByClassName(className) – class 속성값을 기준으로 요소를 찾고, 대응하는 요소를 담은 컬렉션을 반환한다.
이 방법은 2가지 특징을 가지고 있다.
1. 요소 하나가 아닌, 컬렉션을 반환한다.
만약에 문서에 여러 input요소가 있다면 컬렉션을 순회하거나 인덱스를 사용해 요소를 얻고 그 요소에 값을 할당해야 한다.
// (문서에 input 요소가 있다면) 아래 코드는 잘 동작하게 된다.
document.getElementsByTagName('input')[0].value = 5;
이 메서드는 elem의 자식 요소 중 주어진 선택자에 대응하는 요소 모두를 반환한다. 아래 예시는 마지막 li 요소를 모두 alert해주고 있다.
<!doctype html>
<body>
<ul>
<li>1-1</li>
<li>1-2</li>
</ul>
<ul>
<li>2-1</li>
<li>2-2</li>
</ul>
<script>
let elements = document.querySelectorAll('ul > li:last-child');
for (let elem of elements) {
alert(elem.innerHTML); // "1-2", "2-2"
}
</script>
</body>
이 메서드는 elem의 자식 요소 중 주어진 선택자에 대응하는 '첫번째'요소만 반환한다. 위의 예시를 활용하면 1-2만 반환하는 모습을 볼 수 있다.
<!doctype html>
<body>
<ul>
<li>1-1</li>
<li>1-2</li>
</ul>
<ul>
<li>2-1</li>
<li>2-2</li>
</ul>
<script>
let elements = document.querySelector('ul > li:last-child');
alert(elements.innerHTML); // "1-2"
</script>
</body>
matches : 요소 elem이 주어진 선택자와 일치하는지 여부를 판단해준다. 일치한다면 true, 아니라면 false를 반환한다.
closest : elem 자기 자신을 포함하여 선택자와 일치하는 가장 가까운 조상 요소를 찾을 수 있게 한다.
DOM 노드 중 일부만 설명할 것이다.
innerHTML
요소 안의 HTML을 알아낼 수 있다. 이 프로퍼티를 사용하면 요소 안의 HTML을 수정할 수도 있다.
hidden
true로 설정하면 CSS에서 display:none을 설정한 것과 동일하게 동작한다.
tagName/nodeName
tagName 프로퍼티는 요소 노드에만 존재한다.
nodeName은 모든 Node에 있다.
요소 노드를 대상으로 호출하면 tagName과 같은 역할을 한다.
텍스트 노드, 주석 노드 등에선 노드 타입을 나타내는 문자열을 반환한다.
속성은 HTML 안에 쓰인다면 프로퍼티는 DOM 객체 안에 쓰인다.
속성과 함께 쓰이는 메서드는 다음과 같이 있다.
- elem.hasAttribute(name) – 속성 존재 여부 확인
- elem.getAttribute(name) – 속성값을 가져옴
- elem.setAttribute(name, value) – 속성값을 변경함
- elem.removeAttribute(name) – 속성값을 지움
- elem.attributes – 속성의 컬렉션을 반환함
1️⃣ document.createElement(tag) : 태그 이름(tag)을 사용해 새로운 요소 노드를 만든다.
const link = document.createElement("div");
2️⃣ document.createTextNode(text) : 주어진 텍스트(text)를 사용해 새로운 텍스트 노드를 만든다.
let textNode = document.createTextNode('안녕하세요.');
요소 삽입
JS에서 지원하는 요소 삽입 메서드는 다음과 같이 있다.
- node.append(노드나 문자열) – 노드나 문자열을 node 끝에 삽입합니다.
- node.prepend(노드나 문자열) – 노드나 문자열을 node 맨 앞에 삽입합니다.
- node.before(노드나 문자열) –- 노드나 문자열을 node 이전에 삽입합니다.
- node.after(노드나 문자열) –- 노드나 문자열을 node 다음에 삽입합니다.
- node.replaceWith(노드나 문자열) –- node를 새로운 노드나 문자열로 대체합니다.
예시는 append와 prepend를 이용한 방법이다.<!doctype html> <body> <ol id="ol"> <li>0</li> <li>1</li> <li>2</li> </ol> <script> ol.before('before'); // <ol> 앞에 문자열 'before'를 삽입함 ol.after('after'); // <ol> 뒤에 문자열 'after를 삽입함 let liFirst = document.createElement('li'); liFirst.innerHTML = 'prepend'; ol.prepend(liFirst); // <ol>의 첫 항목으로 liFirst를 삽입함 let liLast = document.createElement('li'); liLast.innerHTML = 'append'; ol.append(liLast); // <ol>의 마지막 항목으로 liLast를 삽입함 </script> </body>
elem.insertAdjacentHTML(where, html)에서 첫 번째 매개변수는 elem을 기준으로 하는 상대 위치로, 다음 값 중 하나여야 한다.
'beforebegin' – elem 바로 앞에 html을 삽입
'afterbegin' – elem의 첫 번째 자식 요소 바로 앞에 html을 삽입
'beforeend' – elem의 마지막 자식 요소 바로 다음에 html을 삽입
'afterend' – elem 바로 다음에 html을 삽입
<!doctype html>
<body>
<div id="div"></div>
<script>
// <div id="div"></div> 앞에 삽입
div.insertAdjacentHTML('beforebegin', '<p>안녕하세요.</p>');
//<div id="div"></div> 뒤에 삽입
div.insertAdjacentHTML('afterend', '<p>안녕히 가세요.</p>');
</script>
</body>
node.remove() 사용하면 노드를 삭제할 수 있다.
elem.getBoundingClientRect() 메서드는 elem을 감싸는 가장 작은 네모의 창 기준 좌표를 DOMRect 클래스의 객체 형태로 반환한다.
elem.getBoundingClientRect()의 각 프로퍼티를 그림으로 표현하면 다음과 같이 나타난다.