주요 노드 프로퍼티, 속성과 프로퍼티, 문서 수정하기, 스타일과 클래스
주요 노드 프로퍼티
DOM 노드 클래스
DOM 노드
- 프로토타입을 기반으로 상속 관계를 갖는 일반 자바스크립트 객체
- 모든 DOM 노드는 공통 조상으로부터 생성되어 공통된 프로퍼티와 메서드 지원
- 종류에 따라 각각 다른 프로퍼티 지원
- DOM 노드는 종류에 따라 대응하는 내장 클래스가 다름
console.dir(elem), console.log(elem)
elem이 자바스크립트 객체이면 대개 같은 결과 출력elem이 DOM 요소이면,console.log(elem): 요소의 DOM 트리 출력console.dir(elem): 요소를 DOM 객체처럼 취급해 출력. 프로퍼티 확인 쉬움
1
2
3
4
5
6
7
8
9
| [ EventTarget ]
[ Node ]
[ Text ] [ Element ] [ Comment ]
[ HTMLElement ] [ SVGElement ]
[ HTMLInputElement ] [ HTMLBodyElement ] [ HTMLAnchorElement ]
|
EventTarget
- 루트에 있는 추상(abstract) 클래스. 이 클래스의 객체는 실제로 생성되지 않음
- 이벤트 관련 기능 제공. 모든 DOM 노드의 베이스에 있기 때문에 DOM 노드에서 이벤트 사용 가능
Node
- 추상 클래스로, 해당하는 객체는 절대 생성되지 않음
- DOM 노드의 베이스 역할. 공통 DOM 노드 프로퍼티와 주요 트리 탐색 기능 제공
parentNode, nextSibling, childNodes 등
Text, Element, Comment 클래스에게 상속
Element
- DOM 요소를 위한 베이스 클래스. 요소 전용 탐색을 도와주는 프로퍼티, 메서드가 기반함
nextElementSibling, children, getElementsByTagName, querySelector 등
SVGElement, XMLElement, HTMLElement 클래스의 베이스 역할 (브라우저는 XML, SVG도 지원)
HTMLElement
- HTML 요소 노드의 베이스 클래스. HTML 요소 메서드와 getter, setter 제공
- 각 태그에 해당하는 클래스에 고유한 프로퍼티와 메서드 지원
예시: <input> 요소
- HTMLInputElement 클래스를 기반으로 생성되고 아래 클래스들에서 프로퍼티와 메서드를 상속받음
HTMLInputElement: 입력 관련 프로퍼티 제공HTMLElement: HTML 요소 메서드와 getter, setter 제공Element: 요소 노드 메서드 제공Node: 공통 DOM 노드 프로퍼티 제공EventTarget: 이벤트 관련 기능 제공Object: 일반 객체 메서드 제공
DOM 노드 클래스 이름, 상속 여부 확인하기
constructor.name, toStringinstanceof
1
2
3
4
5
6
7
8
| alert(document.body.constructor.name); // HTMLBodyElement
alert(document.body); // [object HTMLBodyElement]
alert(document.body instanceof HTMLBodyElement); // true
alert(document.body instanceof HTMLElement); // true
alert(document.body instanceof Element); // true
alert(document.body instanceof Node); // true
alert(document.body instanceof EventTarget); // true
|
Interface Description Language(IDL)
- 명세서에서는 IDL을 이용해 DOM 클래스를 설명
‘nodeType’ 프로퍼티
nodeType: DOM 노드의 타입을 알아내는 구식 프로퍼티- 각 노드 타입은 상수값을 가짐. 타입을 변경하는 데 사용은 불가
1
2
3
4
5
6
7
8
| <body>
<script>
let elem = document.body;
alert(elem.nodeType); // 1. 요소 노드
alert(elem.firstChild.nodeType); // 3. 텍스트 노드
alert(document.nodeType); // 9. 문서 객체
</script>
</body>
|
nodeName과 tagName으로 태그 이름 확인하기
- DOM 노드의 태그 이름 확인
tagName: 요소 노드에만 존재하는 프로퍼티nodeName: 모든 노드에 존재하는 프로퍼티- 요소 노드를 대상으로 하면
tagName과 같음 - 텍스트 노드, 주석 노드 등에서는 노드 타입을 나타내는 문자열 반환
태그 이름은 항상 대문자
- XML 모드는 제외. 브라우저에서 HTML과 XML을 처리하는 모드는 다름
- 헤더가
Content-Type: application/xml+xhtml인 HTML 문서를 받으면 XML 모드로 문서 처리 - 웹 페이지는 대개 HTML 모드로 처리됨. HTML 모드에서는
tagName, nodeName이 대문자로 변경 - XML 모드에서는 케이스가 그대로 유지되지만 XML 모드는 요즘에는 거의 사용되지 않음
1
2
3
4
5
6
7
8
9
10
11
12
13
| <body>
<!-- 주석 -->
<script>
alert(document.body.nodeName); // BODY
alert(document.body.tagName); // BODY
// 주석 노드를 대상으로 두 프로퍼티 비교
alert(document.body.firstChild.tagName); // undefined (요소가 아님)
alert(document.body.firstChild.nodeName); // #comment
// 문서 노드를 대상으로 두 프로퍼티 비교
alert(document.tagName); // undefined (요소가 아님)
alert(document.nodeName); // #document
</script>
</body>
|
innerHTML로 내용 조작하기
innerHTML: 요소 안의 HTML을 문자열 형태로 받을 수 있고 수정도 할 수 있는 프로퍼티- 요소 노드에만 사용 가능하고 문법이 틀린 HTML을 넣으면 브라우저가 자동으로 수정
<script> 태그를 삽입하면 해당 태그는 HTML의 일부가 되나 실행은 되지 않음
elem.innerHTML += "추가 html"
- 요소에 HTML 추가가 아니라 내용을 덮어씀
elem.innerHTML = elem.innerHTML + "추가 html"의 축약- 기존 내용을 완전히 삭제하고 기존 내용과 새로운 내용을 합친 새로운 내용을 밑바닥부터 씀
- 이미지 등의 리소스 전부 다시 로딩
- 텍스트와 이미지가 많았다면 버벅이고, 입력 태그에 입력한 값이 있었다면 없어짐 등의 부작용
innerHTML 말고 HTML을 추가하는 방법으로 부작용을 없앨 수 있음
1
2
3
4
5
6
7
8
| <body>
<p>p 태그</p>
<div>div 태그</div>
<script>
alert(document.body.innerHTML); // 내용 읽기
document.body.innerHTML = "새로운 BODY!"; // 교체
</script>
</body>
|
outerHTML로 요소의 전체 HTML 보기
outerHTML: 요소 전체 HTML이 담긴 프로퍼티innerHTML에 요소 자체를 더한 것이라 봐도 됨innerHTML과 달리 outerHTML로 HTML을 쓰면 요소 자체가 바뀌지 않고 DOM 안의 요소를 교체outerHTML에 하는 할당 연산이 DOM 요소를 수정하지 않기 때문outerHTML 연산의 대상으로, 아래에서는 변수 div
- 할당 연산은 요소를 DOM에서 제거하고 새로운 HTML 조각을 넣음
1
2
3
4
5
6
7
8
| <div id="elem">Hello <b>World</b></div>
<div>Hello, world!</div>
<script>
alert(elem.outerHTML); // <div id="elem">Hello <b>World</b></div>
let div = document.querySelector("div");
div.outerHTML = "<p>새로운 요소</p>";
alert(div.outerHTML); // <div>Hello, world!</div>
</script>
|
div.outerHTML = ...이 하는 일- 문서에서
div 삭제를 삭제하고 새로운 HTML 조각인 <p>...</p>를 삭제 후 생긴 공간에 삽입 div에는 여전히 기존값이 저장되어 있고 새로운 HTML 조각은 어디에도 저장되어 있지 않음
nodeValue/data로 텍스트 노드 내용 조작하기
nodeValue, data 프로퍼티- 텍스트 노드 같은 다른 타입의 노드에
innerHTML과 유사한 역할 - 두 프로퍼티는 거의 유사하나 명세서상의 작은 차이가 있음
innerHTML 프로퍼티는 요소 노드에만 사용 가능
1
2
3
4
5
6
7
8
9
10
| <body>
안녕하세요.
<!-- 주석 -->
<script>
let text = document.body.firstChild;
alert(text.data); // 안녕하세요.
let comment = text.nextSibling;
alert(comment.data); // 주석
</script>
</body>
|
1
2
3
| <!-- if isAdmin -->
<div>관리자로 로그인하였습니다!</div>
<!-- /if -->
|
data로 주석 노드의 내용을 읽고 삽입된 지시사항을 처리하면 유용
textContent로 순수한 텍스트만
textContent: 요소 내의 텍스트에 접근해 태그는 제외하고 텍스트만 추출- 텍스트를 안전한 방법으로 쓸 수 있기 때문에 유용
1
2
3
4
5
6
7
| <div id="news">
<h1>주요 뉴스!</h1>
<p>화성인이 지구를 침공하였습니다!</p>
</div>
<script>
alert(news.textContent); // 주요 뉴스! 화성인이 지구를 침공하였습니다!
</script>
|
innerHTML, innerText, textContent
innerHTML: Element의 속성- 사용자가 입력한 문자열이 HTML 형태로 태그와 함께 저장
innerText: Element의 속성textContent: Node의 속성innerText와 달리 해당 노드가 가진 텍스트 값을 그대로 읽음- 사용자가 입력한 문자열이 순수 텍스트 형태로 저장
- 태그를 구성하는 특수문자들이 문자열로 처리되어 예상치 못한 HTML이 사이트에 침투하는 것을 방지
hidden 프로퍼티
hidden: 요소를 보여줄지 말지 지정- HTML의
hidden 속성, JS의 hidden 프로퍼티 - 기술적으로
style="display:none"과 동일
1
2
3
4
5
6
| <div>아래 두 div를 숨겨봅시다.</div>
<div hidden>HTML의 hidden 속성 사용하기</div>
<div id="elem">자바스크립트의 hidden 프로퍼티 사용하기</div>
<script>
elem.hidden = true;
</script>
|
기타 프로퍼티
value: <input>, <select>, <textarea>의 값 저장href: <a href="...">의 href 속성값 저장id: id 속성값 저장- 기타 등등
console.dir(elem)으로 해당 요소에서 지원하는 프로퍼티 목록 확인 가능- 대부분의 표준 HTML 속성은 대응하는 DOM 프로퍼티를 가지나 HTML 요소와 DOM 프로퍼티가 항상 같은 것은 아님
예제
노드 타입 맞추기
1
2
3
4
5
6
7
| <html>
<body>
<script>
alert(document.body.lastChild.nodeType); // 1
</script>
</body>
</html>
|
<script>가 실행되는 시점에는 브라우저가 <script> 아래 문서를 처리하지 못했음- 가장 마지막 노드는
<script> 자기 자신
주석 안의 태그
1
2
3
4
5
| <script>
let body = document.body;
body.innerHTML = "<!--" + body.tagName + "-->";
alert(body.firstChild.data); // BODY
</script>
|
<body>의 컨텐츠가 <!--BODY-->로 대체됨- 주석이 유일한 자식 노드가 됨
- 주석 노드의
data 프로퍼티에는 주석 내용("BODY")이 저장됨
DOM 계층 구조와 ‘document’
document는 HTMLDocument 클래스의 인스턴스HTMLDocument 클래스는 DOM 계층 구조에서 어디에 있을까?
1
2
3
4
5
6
| alert(document); // [object HTMLDocument]
alert(document.constructor.name); // HTMLDocument
alert(HTMLDocument.prototype.constructor === HTMLDocument); // true
alert(HTMLDocument.prototype.constructor.name); // HTMLDocument
alert(HTMLDocument.prototype.__proto__.constructor.name); // Document
alert(HTMLDocument.prototype.__proto__.__proto__.constructor.name); // Node
|
1
2
3
4
| [ Node ]
[ Element ] [ Document ] [ CharacterData ] [ Attr ]
[ HTMLElement ] [ HTMLDocument ] [ Text ]
[ Comment ]
|
속성과 프로퍼티
브라우저가 웹 페이지를 만날 때
- HTML을 읽음(파싱, parsing)
- DOM 객체 생성
- 요소 노드에서 대부분의 표준 속성(attribute)은 DOM 객체의 프로퍼티(property)가 됨
- 그러나 속성-프로퍼티가 항상 일대일 매핑되지는 않음
HTML 속성
- HTML 안에 쓰임
- 문자열만 가능
- 대소문자 가리지 않음
DOM 프로퍼티
- DOM 객체 안에 쓰임
- 모든 값 가능
- 대소문자 가림
- HTML 속성보다 DOM 프로퍼티를 사용하는 것을 권장
DOM 프로퍼티
- 자신만의 DOM 프로퍼티 생성 가능
- 일반 자바스크립트 객체처럼 행동
- 어떤 값이든 가능
- 대소문자를 가림
1
2
3
4
5
6
7
8
9
10
11
12
13
| document.body.myData = { name: "Caesar", title: "Imperator" };
alert(document.body.myData.title); // Imperator
document.body.sayTagName = function () {
alert(this.tagName);
};
document.body.sayTagName(); // BODY. sayTagName의 'this'에 document.body가 저장됨
Element.prototype.sayHi = function () {
alert(`Hello, I'm ${this.tagName}`);
};
document.documentElement.sayHi(); // Hello, I'm HTML
document.body.sayHi(); // Hello, I'm BODY
|
HTML 속성
- HTML 속성의 특징
- HTML 태그는 복수의 속성을 가질 수 있음
- 대소문자를 가리지 않음
- 값은 항상 문자열
- HTML 표준 속성
- 브라우저가 HTML을 파싱해 DOM 객체를 만들 때 HTML 표준 속성을 인식하고 이것을 사용해 DOM 프로퍼티 생성
- 비표준 속성
- 비표준 속성은 프로퍼티로 전환되지 않음. 이에 매핑하는 DOM 프로퍼티가 생성되지 않음
- 한 요소에서는 표준인 속성이 다른 요소에서는 표준이 아닐 수 있음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <body id="test" something="non-standard">
<script>
alert(document.body.id); // test
alert(document.body.something); // undefined (비표준 속성은 프로퍼티로 전환되지 않음)
</script>
</body>
<body id="body" type="...">
<input id="input" type="text" />
<script>
alert(input.type); // text
alert(body.type); // undefined (type은 body의 표준 속성이 아니므로 DOM 프로퍼티가 생성되지 않음)
</script>
</body>
|
비표준 속성에도 접근할 수 있는 메서드들
elem.hasAttribute(name): 속성 존재 여부 확인elem.getAttibute(name): 속성값 가져오기elem.setAttribute(name, value): 속성값 변경elem.removeAttribute(name): 속성값 삭제elem.attributes: 모든 속성값 읽기- 내장 클래스
Attr을 구현한 객체들이 담긴 열거 가능한 컬렉션 반환 - 각 객체에는
name, value 프로퍼티 존재
outerHTML로 직접 추가한 속성을 포함한 모든 속성을 볼 수 있음
1
2
3
4
5
| <body something="non-standard">
<script>
alert(document.body.getAttribute("something")); // non-standard. 비표준 속성에 접근
</script>
</body>
|
프로퍼티-속성 동기화
표준 속성이 변하는 경우
- 대응하는 프로퍼티는 자동 갱신
- 몇몇 경우를 제외하고 프로퍼티가 변하면 속성도 자동 갱신
input.value처럼 동기화가 속성에서 프로퍼티 방향으로만 일어나는 경우- 속성
value 수정 -> 프로퍼티 수정 - 프로퍼티 수정 -> 속성 수정 X
- 유저의 어떤 행동 때문에
value가 수정되었을 때, 속성에 저장된 값을 가져와 수정 전의 원래 값으로 복구 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
| <input />
<script>
let input = document.querySelector("input");
input.setAttribute("id", "id"); // 속성 추가 -> 프로퍼티 갱신
alert(input.id); // id
input.id = "newId"; // 프로퍼티 변경 -> 속성 갱신
alert(input.getAttribute("id")); // newId
input.setAttribute("value", "text"); // 속성 추가 -> 프로퍼티 갱신
alert(input.value); // text
input.value = "newValue"; // 프로퍼티를 변경해도 속성이 갱신되지 않음
alert(input.getAttribute("value")); // text. 갱신되지 않음
</script>
|
DOM 프로퍼티 값의 타입
- DOM 프로퍼티는 항상 문자열이 아님
- 대부분의 프로퍼티의 값은 문자열
- 체크 박스에 사용되는
input.checked 프로퍼티는 불린값 가짐 style 속성은 문자열이지만 style 프로퍼티는 객체
- DOM 프로퍼티 값이 문자열이더라도 속성값과 다른 경우
href 속성이 상대 URL이나 #hash더라도 href DOM 프로퍼티에는 항상 URL 전체가 저장됨- HTML 내에 명시된
href 속성을 정확히 얻고 싶다면 getAttribute 사용
1
2
3
4
5
6
7
8
9
10
11
12
| <div id="div" style="color:red;font-size:120%">Hello</div>
<script>
alert(div.getAttribute("style")); // color:red;font-size:120%. 문자열
alert(div.style); // [object CSSStyleDeclaration]. 객체
alert(div.style.color); // red
</script>
<a id="a" href="#hello">link</a>
<script>
alert(a.getAttribute("href")); // #hello. 속성
alert(a.href); // 실행되는 사이트 주소에 따라 http://site.com/page#hello 형태로 값이 저장됨. 프로퍼티
</script>
|
비표준 속성, dataset
- 사용자가 직접 지정한 데이터를 HTML에서 자바스크립트로 넘기고 싶은 경우
- 자바스크립트를 사용해 조작할 HTML 요소를 표시하기 위해 사용하는 경우
- 요소에 스타일을 적용하는 경우
- 새 클래스를 추가하거나 지우는 것보다 속성을 사용해 더 쉽게 상태 변경 가능
dataset: data-로 시작하는 속성을 사용할 수 있는 프로퍼티data-로 시작하는 속성 전체는 개발자가 용도에 맞게 사용하도록 별도로 예약됨
1
2
3
4
5
6
7
8
9
| <div show-info="name"></div>
<div show-info="age"></div>
<script>
let user = { name: "Pete", age: 25 };
for (let div of document.querySelectorAll("[show-info]")) {
let field = div.getAttribute("show-info"); // 원하는 정보를 필드 값에 입력해 줌
div.innerHTML = user[field]; // Pete -> 'name', 25 -> 'age'
}
</script>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <style>
.order[order-state="new"] {
color: green;
}
.order[order-state="pending"] {
color: blue;
}
.order[order-state="canceled"] {
color: red;
}
</style>
<div class="order" order-state="new">A new order.</div>
<div class="order" order-state="pending">A pending order.</div>
<div class="order" order-state="canceled">A canceled order.</div>
|
1
2
3
4
5
6
7
| <body data-about="Elephants">
<div data-order-state="new"></div>
<script>
alert(document.body.dataset.about); // Elephants
alert(document.body.dataset.orderState); // new
</script>
</body>
|
문서 수정하기
적시에 요소를 새롭게 생성하거나 페이지에 있는 기존 컨텐츠를 수정하는 방법
예제: 메시지 보여주기
1
2
3
4
5
6
7
8
9
10
11
12
| <style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<div class="alert">
<strong>안녕하세요!</strong> 중요 메시지를 확인하셨습니다.
</div>
|
자바스크립트를 이용해보기
요소 생성하기
1
2
| let tag = document.createElement("tag"); // 태그 이름으로 새로운 요소 노드 생성
let textNode = document.createTextNode("text"); // 텍스트를 이용해 새로운 텍스트 노드 생성
|
1
2
3
4
| let div = document.createElement("div");
div.className = "alert";
div.innerHTML = "<strong>안녕하세요!</strong> 중요 메시지를 확인하셨습니다.";
document.body.append(div); // 삽입해야 페이지에 비로소 나타남
|
삽입 메서드
node.append(노드 or 문자열): node 끝에 노드나 문자열 삽입node.prepend(노드 or 문자열): node 맨 앞에 노드나 문자열 삽입node.before(노드 or 문자열): node 이전에 노드나 문자열 삽입node.after(노드 or 문자열): node 다음에 노드나 문자열 삽입node.replaceWith(노드 or 문자열): node를 새로운 노드나 문자열로 대체- 문자열을 넘기면 자동으로 텍스트 노드 생성.
elem.textContent처럼 안전한 방법으로 삽입됨- HTML이 아닌 넘긴 문자열 그 형태로 삽입됨. 특수문자는 이스케이프 처리
- 복수의 노드와 문자열 한번에 삽입 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <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>
|
1
2
3
4
5
6
7
| before
1. prepend
2. 0
3. 1
4. 2
5. append
after
|
1
2
3
4
5
6
7
8
9
| before
<ol id="ol">
<li>prepend</li>
<li>0</li>
<li>1</li>
<li>2</li>
<li>append</li>
</ol>
after
|
insertAdjacentHTML/Text/Element
- HTML 그 자체를 삽입하고 싶은 경우 사용.
elem.innerHTML을 사용한 것처럼 태그가 정상적으로 동작 elem.insertAdjacentHTML(where, html): elem을 기준으로 하는 상대 위치 where에 HTML 문자열 html을 삽입'beforebegin': elem 바로 앞'afterbegin': elem의 첫 번째 자식 요소 바로 앞'beforeend': elem의 마지막 자식 요소 바로 다음'afterend': elem 바로 다음- 이스케이프 처리되지 않고 그대로 삽입
elem.insertAdjacentText(where, text): HTML 대신 text를 문자 그대로 삽입elem.insertAdjacentElement(where, elem): 요소를 삽입
노드 삭제하기
node.remove()- 요소 노드를 다른 곳으로 옮길 때, 기존에 있던 노드를 지울 필요 없음
- 모든 노드 삽입 메서드는 자동으로 기존에 있던 노드를 삭제하고 새로운 곳으로 노드를 옮김
cloneNode로 노드 복제하기
elem.cloneNode(true): elem의 깊은 복제본 생성. 속성 전부와 자손 요소 전부 복사false를 전달하면 후손 노드 없이 elem만 복제
DocumentFragment
1
| let fragment = new DocumentFragment();
|
- 특별한 DOM 노드 타입
- 여러 노드로 구성된 그룹을 감싸 다른 곳으로 전달하게 해주는 래퍼처럼 동작
- 문서에 있는 다른 노드를
DocumentFragment에 추가하고 그것을 문서 어딘가에 삽입하는 경우 DocumentFragment는 사라지고 DocumentFragment에 추가한 노드만 남음
구식 삽입·삭제 메서드
- 하위 호환성을 위해 남은 구식 DOM 조작 메서드
parentElem.appendChild(node): parentElem의 마지막 자식으로 node 추가parentElem.insertBefore(node, nextSibling): parentElem 안의 nextSibling 앞에 node 추가parentElem.replaceChild(node, oldChild): parentElem의 자식 노드 중 oldChild를 node로 교체parentElem.removeChild(node): parentElem에서 node를 삭제node가 parentElem의 자식이라는 가정 하- 위 메서드들은 모두 삽입하거나 삭제한 노드 반환
‘document.write’에 대한 첨언
document.write(html)html이 페이지 그 자리에 즉시 추가됨- DOM도 없고 그 어떤 표준도 존재하지 않았던 과거에 만들어진 메서드. 표준에 정의된 메서드가 아님
- 페이지를 불러오는 도중에만 작동
- 페이지가 다 로드된 후
document.write를 호출하면 기존에 있던 문서 내용이 사라짐- 그래서 페이지 로드가 다 끝난 후에는 사용 불가
- 브라우저는 HTML을 읽는(파싱하는) 도중에
document.write(HTML)를 만나면 텍스트 형식의 HTML을 마치 원래 페이지에 있었던 것처럼 해석- DOM 구조가 완성되기 전에 페이지에 내용이 삽입되어 중간에 DOM 조작을 하지 않기 때문에 속도가 아주 빨라지는 장점
- 엄청나게 많은 글자를 HTML에 동적으로 추가해야 하는데 아직 페이지를 불러오는 중이고, 속도가 필요한 상황이면 유용
- 하지만 이런 상황은 드물어서 잘 쓰지 않음
1
2
3
4
5
| <p>페이지 어딘가...</p>
<script>
document.write("<b>자바스크립트를 사용해 Hello 입력</b>");
</script>
<p>끝</p>
|
1
2
3
4
| <p>일 초 후, 이 페이지의 내용은 전부 교체됩니다.</p>
<script>
setTimeout(() => document.write("<b>...사라졌습니다.</b>"), 1000); // 페이지 로드가 끝난 후이므로 기존 내용 사라짐
</script>
|
예제
createTextNode vs innerHTML vs textContent
elem.append(document.createTextNode(text))elem.innerHTML = textelem.textContent = text (1과 3은 같은 동작을 수행)
요소 삭제하기
1
2
3
4
5
6
7
8
9
10
11
| <ol id="elem">
<li>Hello</li>
<li>World</li>
</ol>
<script>
function clear(elem) {
for (let i = 0; i < elem.childNodes.length; i++)
elem.childNodes[i].remove();
}
clear(elem); // elem 내부 리스트를 삭제
</script>
|
- 잘못된 방법
remove()는 elem.childNodes를 변화시키기 때문에 반복문을 실행할 때마다 0번째 인덱스부터 시작해야 함- 그러나
i는 계속해서 증가하기 때문에 일부 원소들을 지나침 for..of 반복문도 동일한 문제가 있음
1
2
3
4
5
6
7
8
9
| function clear(elem) {
while (elem.firstChild) {
elem.firstChild.remove();
}
}
function clear(elem) {
elem.innerHTML = "";
}
|
왜 ‘aaa’가 남아 있을까요
1
2
3
4
5
6
7
8
9
10
| <table id="table">
aaa
<tr>
<td>Test</td>
</tr>
</table>
<script>
alert(table); // table은 삭제할 테이블의 id
table.remove(); // 삭제해도 문서 안에 aaa가 남아있음
</script>
|
- 주어진 HTML이 잘못되었기 때문
- 브라우저는 이를 자동으로 고침
- 그러나 명세서에 따르면
<table> 안에는 표와 관련된 특정 태그만이 존재할 수 있어 텍스트가 있어서는 안 됨 - 따라서 브라우저는
aaa를 <table> 앞에 추가 - 그래서 테이블을 삭제해도 텍스트가 남아있음
스타일과 클래스
요소에 스타일을 적용할 수 있는 방법 두 가지
- CSS에 클래스를 만들고 요소에 클래스 추가하기
- 프로퍼티를
style에 바로 쓰기
자바스크립트로 클래스와 style 프로퍼티 둘 다 수정 가능
style보다 CSS 클래스 수정을 더 우선시해야 함style은 클래스를 다룰 수 없을 때만 사용할 것- 자바스크립트를 사용해 요소의 좌표를 동적으로 계산하고 사용할 때
style을 사용하면 좋음 - CSS 관련 스타일을 명시한 클래스를 만들고, 자바스크립트로 이 클래스를 요소에 추가하는 방식 권장
className과 classList
elem.class- 과거 오래된 자바스크립트에는
class 같은 예약어는 객체의 프로퍼티로 사용 불가했음 - 지금은 이런 제약사항은 없음
elem.className- 클래스를 위한 프로퍼티로
"class" 속성에 대응 - 무언가를 대입하면 전체가 바뀜
elem.classList- 클래스 하나만 추가하거나 제거하고 싶을 경우 사용하는 프로퍼티
elem.classList.add/remove("class"): class를 추가하거나 제거elem.classList.toggle("class"): class가 존재할 경우 class를 제거하고, 그렇지 않은 경우 추가elem.classList.contains("class"): class 존재 여부 반환- 이터러블 객체이므로
for..of 사용 가능
1
2
3
4
5
6
7
8
| <body class="main page">
<script>
alert(document.body.className); // main page
document.body.classList.add("article");
alert(document.body.className); // main page article
for (let name of document.body.classList) alert(name); // main, page, article
</script>
</body>
|
요소의 스타일
elem.style: 속성 "style"에 쓰인 값과 대응되는 객체- 여러 단어를 이어 만든 프로퍼티는 카멜 케이스 사용
style 프로퍼티 재지정하기
delete로 프로퍼티를 삭제하는 대신 빈 문자열 할당- 빈 문자열을 할당하면 브라우저는 마치 프로퍼티가 없었던 것처럼 CSS 클래스와 브라우저 내장 스타일을 페이지에 적용
style.cssText: 문자열을 사용해 전체 스타일을 설정- 기존 스타일에 스타일을 추가하는 것이 아닌 전체를 교체
elem.setAttribute('style', '...')로 속성을 설정해도 같은 효과
1
2
3
4
5
6
7
8
| <div id="div">버튼</div>
<script>
div.style.cssText = `color: red !important;
background-color: yellow;
width: 100px;
text-align: center;
`;
</script>
|
단위에 주의하기
자바스크립트로 스타일 값을 설정할 때는 단위를 붙여야 함
getComputedStyle로 계산된 스타일 얻기
1
| getComputedStyle(element, [pseudo]);
|
- 프로퍼티의 결정값 반환. 프로퍼티 전체 이름이 필요
- 계산값을 얻기 위해 만들어진 오래된 메서드이나 결정값이 더 편하기 때문에 표준이 개정됨
element: 값을 읽을 요소pseudo: 의사 요소가 필요할 경우 명시. 값이 없거나 빈 문자열이면 요소 자체를 의미elem.style 같이 스타일 정보가 들어 있는 객체를 반환하지만 elem.style과 달리 전체 CSS 클래스 정보도 함께 담김:visited 링크 관련 스타일은 숨겨짐- 방문한 적 있는 링크에
:visited CSS 의사 클래스 사용 가능 - 자바스크립트로는
:visited에 적용된 스타일을 얻을 수 없음 - 악의를 가진 페이지가 사용자가 링크를 방문했는지 여부를 테스트하고 사생활 침해를 방지하기 위함
style 프로퍼티는 "style" 속성의 값을 읽을 때만 사용 가능style 프로퍼티만으로는 CSS 종속(CSS cascade) 값을 다룰 수 없음elem.style만으로는 CSS 클래스를 사용해 적용한 스타일을 읽을 수 없음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| <head>
<style>
body {
color: red;
margin: 5px;
}
</style>
</head>
<body>
붉은 글씨
<script>
alert(document.body.style.color); // 빈 문자열
alert(document.body.style.marginTop); // 빈 문자열
let computedStyle = getComputedStyle(document.body);
alert(computedStyle.marginTop); // 5px
alert(computedStyle.color); // rgb(255, 0, 0)
</script>
</body>
|
CSS 속성과 관련된 두 가지 개념
- 계산값(computed style value): CSS 규칙, CSS 상속이 모두 적용된 값
height:1em, font-size:125% 등
- 결정값(resolved style value): 요소에 최종적으로 적용되는 값
- 브라우저는 계산값을 받아 고정 단위를 사용하는 절댓값으로 변환
height:20px, font-size:16px 등
참고
문서