<ul>
<li id="banana">Apple</li>
<li id="banana">Banana</li>
<li id="banana">Orange</li>
</ul>
<div id="foo">foo</div>
<script>
const $elem = document.getElementById('banana');
$elem.style.color = 'red'; // Apple 텍스트를 갖고 있는 요소 노드만 color 변경
const $elem2 = document.getElementById('nonono'); // 요소 없음 -> null 반환
// id 값과 동일한 전역 변수
console.log(foo === document.getElementById('foo')); // true
let foo = 1; // id 값과 동일한 전역 변수에 값 추가 -> 노드 객체 재할당x
console.log(foo); // 1
</script>
<ul id="fruits">
<li id="apple">Apple</li>
<li id="banana">Banana</li>
<li id="orange">Orange</li>
</ul>
<script>
// 태그 이름이 li인 요소 노드를 모두 탐색하여 color를 red로 설정
const $elems = document.getElementsByTagName('li');
[...$elems].forEach(elem => {elem.style.color = 'red';});
// 문서 내의 모든 요소 노드 취득
const $all = document.getElementsByTagName('*');
// Element.prototype.getElementsByTagName
const $fruits = document.getElementById('fruits');
const $listFromFruits = $fruits.getElementsByTagName('li');
console.log($listFromFruits); // HTMLCollection(3) [li, li, li]
</script>
// fruit 클래스를 가진 모든 노드 요소를 탐색
document.getElementsByClassName('fruit');
// fruit, apple 클래스를 가진 모든 노드 요소를 탐색
document.getElementsByClassName('fruit apple');
// fuits 요소의 apple 클래스를 가지는 자손 노드 탐색
const $fruits = document.getElementById('fruits');
const $listFromFruits = $fruits.getElementsByClassName('apple');
// 요소가 존재하지 않으면 빈 객체 반환
document.getElementsByClassName('nonono'); // []
/* 전체 선택자 : 모든 요소를 선택 */
* { ... }
/* 태그 선택자 : 모든 p 태그 요소를 모두 선택 */
p { ... }
/* id 선택자 : id 값이 foo인 요소를 모두 선택 */
#foo { ... }
/* class 선택자 : class 값이 foo인 요소를 모두 선택 */
.foo { ... }
/* 어트리뷰트 선택자 : input 요소 중에 type 어트리뷰트 값이 'text'인 요소를 모두 선택 */
input[type=text] { ... }
/* 후손 선택자 : div 요소의 후손 요소 중 p 요소를 모두 선택 */
div p { ... }
/* 자식 선택자 : div 요소의 자식 요소 중 p 요소를 모두 선택 */
div > p { ... }
/* 인접 형제 선택자 : p 요소의 형제 요소 중에 p 요소 바로 뒤에 위치하는 ul 요소를 선택 */
p + ul { ... }
/* 일반 형제 선택자 : p 요소의 형제 요소 중에 p 요소 뒤에 위치하는 ul 요소를 모두 선택 */
p ~ ul { ... }
/* 가상 클래스 선택자 : hover 상태인 a 요소를 모두 선택 */
a:hover { ... }
/* 가상 요소 선택자 : p 요소의 콘텐츠 앞에 위치하는 공간을 선택
일반적으로 content 프로퍼티와 함께 사용된다. */
p::before { content: ''; }
// banana 클래스를 가지는 요소 중 첫번째 요소 반환
document.querySelector('.banana');
// ul > li 에 해당하는 요소 모두 반환
document.querySelectorAll('ul > li');
<ul id="fruits">
<li class="apple">Apple</li>
<li class="banana">Banana</li>
<li class="orange">Orange</li>
</ul>
const $apple = document.querySelector('.apple');
console.log($apple.matches('#fruits > li.apple')); // true
console.log($apple.matches('#fruits > li.banana')); // false
HTMLCollection
<ul id="fruits">
<li class="red">Apple</li>
<li class="red">Banana</li>
<li class="red">Orange</li>
</ul>
const $elems = document.getElementsByClassName('red');
// red -> blue 클래스로 변경
for (let i = 0; i < $elems.length; i++) {
$elems[i].className = 'blue';
}
// 이때 이 모든 red 요소가 blue 요소로 바뀌지 않는다.
// 이유는, HTMLCollection이 살아 있는 객체 이기 때문에, $elems에서 실시간으로 삭제 되기 때문에 두번째 요소가 첫번째 요소로 바뀌게 된다.
// for문을 역순으로 순회하는 방법으로 회피할 수도 있고, while문을 사용하여 무한 반복하는 방법으로 회피할 수 있다.
// 더 간단한 해결책은 HTMLCollection 객체를 사용하지 않도록, HTMLCollection 객체를 배열로 변환하고 배열의 고차함수를 사용하면 쉽게 해결할 수 있다.
[...$elems].forEach(elem => elem.className = 'blue');
NodeList
const $fruits = document.getElementsById('fruits');
const { childNodes } = $fruits;
[...childNodes].forEach(childNode => {
$fruits.removeChild(childNode);
});
// 모든 자식 노드 삭제 완료.
console.log(chlidNode); // NodeList []
<ul id="fruits">
<li class="apple">Apple</li>
<li class="banana">Banana</li>
<li class="orange">Orange</li>
</ul>
const $fruits = document.getElementById('fruits');
console.log($fruits.childNodes); // [text, li.apple, text, li.banana, text, li.orange, text]
console.log($fruits.children); // [li.apple, li.banana, li.orange]
console.log($fruits.firstChild); // #text
console.log($fruits.lastChild); // #text
console.log($fruits.firstElementChild); // li.apple
console.log($fruits.lastElementChild); // li.orange
<ul id="fruits">
</ul>
const $fruits = document.getElementById('fruits');
console.log($fruits.hasChildNodes); // true
// 자식 노드 중에 텍스트 노드가 아닌 요소 노드가 존재하는지 확인한다.
console.log(!!$fruits.children.length); // 0 false
console.log(!!$fruits.children.length); // 0 false
<div id="foo">Hello</div>
console.log(document.getElementById('foo').firstChild); // #text
<ul id="fruits">
<li class="apple">Apple</li>
<li class="banana">Banana</li>
<li class="orange">Orange</li>
</ul>
const $banana = document.querySelector('.banana');
console.log($banana.parentNode); // ul#fruits
<ul id="fruits">
<li class="apple">Apple</li>
<li class="banana">Banana</li>
<li class="orange">Orange</li>
</ul>
const $fruits = document.getElemetById('fruits');
// fruits의 첫번째 자식 노드 탐색
const { firstChild } = $fruits;
console.log(firstChild); // #text
// fruits의 첫번째 자식 노드의 다음 형재 노드 탐색
const { nextSibling } = firstChild;
console.log(nextSiblings); // li.apple
// li.apple 요소의 이전 형제 노드 탐색
const { previousSibling } = nextSiblings;
console.log(previousSibling); // #text
// $fruits 요소의 첫번째 자식 요소 노드 탐색
const { firstElementChild } = $fruits;
console.log(firstElementChild); // li.apple
// #fruits 요소의 첫번째 자식 노드 다음 형제 노드 탐색
const { nextElementSibling } = firstElementChild;
console.log(nextElementSibling); // li.banana
// li.banana 요소의 이전 형제 요소 노드를 탐색
const { previousElementSibling } = nextElementSibling;
console.log(previousElementSibling); // li.apple
<div id="foo">Hello</div>
console.log(document.nodeType); // 9
console.log(document.nodeName); // #document
const $foo = document.getElementById('foo');
console.log($foo.nodeType); // 1
console.log($foo.nodeName); // DIV
const $textNode = $foo.firstChild;
console.log($textNode.nodeType); // 3
console.log($textNode.nodeName); // #text
<div id="foo">Hello</div>
// 문서 노드의 nodeValue 참조
console.log(document.nodeValue); // null
// 요소 노드의 nodeValue 참조
const $foo = document.getElementById('foo');
console.log($foo.nodeValue); // null
// 텍스트 노드의 nodeValue 참조
const $textNode = $foo.firstChild;
console.log($textNode.nodeValue); // Hello
// 텍스트 노드의 nodeValue 할당
$textNode.nodeValue = 'World';
console.log($textNode.nodeValue); // World
<div id="foo">Hello <span>world!</span></div>
// 요소 노드의 참조
console.log(document.getElementById('foo').textContent); // Hello world;
// 요소 노드의 할당
document.getElementById('foo').textContent = 'Hi <span>there!</span>';
<div id="foo">Hello <span>world!</span></div>
// 참조시
console.log(document.getElementById('foo').innerHTML); // 'Hello <span>world!</span>
const $foo = document.getElementById('foo');
// 노드 교체
$foo.innerHTML = 'Hi <span>there!</span>';
// 노드 추가
$foo.innerHTML += 'Hi~~ <span>there222!</span>';
// 위의 코드와 동일하다. $foo.innerHTML = $foo.innerHTML + 'Hi~~ <span>there222!</span>';
// 노드 삭제
$foo.innerHTMl = '';
'beforebegin'<div id="foo">'afterbegin' text 'beforeend'</div>'afterend'
<!-- beforebegin -->
<div id="foo">
<!-- afterbegin -->
text
<!-- beforeend -->
</div>
<!-- afterend -->
<script>
const $foo = document.getElementById('foo');
$foo.insertAdjacentHTML('beforebegin', '<p>beforebegin</p>');
$foo.insertAdjacentHTML('afterbegin', '<p>afterbegin</p>');
$foo.insertAdjacentHTML('beforeend', '<p>beforeend</p>');
$foo.insertAdjacentHTML('afterend', '<p>afterend</p>');
</script>
요소 노드 생성
텍스트 노드 생성
텍스트 노드를 요소 노드의 자식 노드로 추가
요소 노드를 DOM에 추가
// 요소 노드 생성
const $li = document.createElement('li');
// 텍스트 노드 생성
const textNode = document.createTextNode('Banana');
// 텍스트 노드를 요소 노드의 자식 노드로 추가
$li.appendChild(textNode);
// $li.textContent = 'Banana'; // 위의 코드와 동일하다.
// 요소 노드 추가
$fruits.appendChild($li);
<ul id="fruits"></ul>
<script>
const $fruits = document.getElementById('fruits');
// 컨테이너 요소 노드 생성
const $container = document.createElement('div');
// div 컨테이터 태그가 불필요할 경우(ul 안에 들어가는 경우 등등)
const $fragment = document.createDocumentFragment();
['Apple', 'Banana', 'Orange'].forEach(text => {
// 요소 노드 생성
const $li = document.createElement('li');
// 텍스트 노드 생성
const textNode = document.createTextNode(text);
// 텍스트 노드를 li 요소 노드의 자식 노드로 추가
$li.appendChild(textNode);
// li 요소 노드를 컨테이너 요소의 마지막 자식 노드로 추가
$container.appendChild($li);
// 혹은 프래그먼트 요소의 마지막 자식 노드로 추가
$fragment.appendChild($li);
});
// 컨테이너 요소 노드를 타겟 요소 노드의 마지막 자식 노드로 추가
$fruits.appendChild($container);
// 혹은 프래그먼트 요소 노드를 타겟 요소 노드의 마지막 자식 노드로 추가
$fruits.appendChild($fragment);
</script>
마지막 노드로 추가
const $li = document.createElement('li');
$li.appendChild(document.createTextNode('Orange'));
// fruits 요소 노드의 마지막에 li 추가
document.getElementById('fruits').appendChild($li);
지정한 위치에 노드 삽입
const $fruits = document.getElementById('fruits');
const $li = document.createElement('li');
$li.appendChild(document.createTextNode('Orange'));
// fruis 요소 노드의 마지막 자식 요소 앞에 li 삽입
$fruits.insertBefore($li, $fruits.lastElementChild);
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Orange</li>
</ul>
const $fruits = document.getElementById('fruits');
const [$apple, $banana, ] = $fruits.children;
$fruits.appendChild($apple); // Banana - Orange - Apple
$fruits.insertBefore($banana, $fruits.lastElementChild); // Orange - Banana - Apple
const $fruits = document.getElementById('fruits');
const $apple = $fruits.firstElementChild;
// 얕은 복사
const $shallowClone = $apple.cloneNode();
// 사본 요소 노드에 텍스트 추가
$shallowClone.textContent = 'Banana';
// #fruits 요소 노드의 마지막 노드로 추가
$fruits.appendChild($shallowClone);
// 깊은복사
const $deepClone = $fruits.clondNode(true);
// $fruits 요소 노드의 마지막 노드로 추가
$fruits.appendCHild($deepClone);
const $fruits = document.getElementById('fruits');
const $newChild = document.createElement('li');
$newChild.textContent = 'Banana';
// #fruits 요소 노드의 첫번째 자식 요소 노드를 newChild 요소 노드로 교체
$fruits.replaceChild($newChild, $fruits.firstElementChild);
const $fruits = document.getElementById('fruits');
// #fruits 요소 노드의 마지막 요소를 DOM에서 삭제
$fruits.removeChild($fruits.lastElementChild);
<input id="user" type="text" value="ungmo2">
<script>
const { attributes } = document.getElementById('user');
console.log(attributes.id.value); // user
console.log(attributes.type.value); // text
console.log(attributes.value.value); // ungmo2
</script>
<input id="user" type="text" value="ungmo2">
<script>
const $input = document.getElementById('user');
// attribute 속성 값 참조
const inputValue = $input.getAttribute('value');
console.log(inputValue); // ungmo2
// attribute 속성 값 변경
$input.setAttributes('value', 'foo');
console.log($input.getAttribute('value')); // foo
// attribute 값 존재 확인
console.log($input.hasAttribute('value')); // true
// attribute 삭제
$input.removeAttribute('value');
</script>
<input id="user" type="text" value="ungmo2">
를 예로 들자면,어트리뷰트 노드
<input id="user" type="text" value="ungmo2">
// 초기값 취득
document.getElementById('user').getAttribute('value'); // ungmo2
// 초기값 foo로 변경
document.getElementById('user').setAttribute('value', 'foo');
DOM 프로퍼티
const $input = document.getElementById('user');
// foo로 최신 상태 변경
$input.value = 'foo';
console.log($input.value); // foo
// HTML 어트리뷰트 값(초기 상태 값)에는 영향을 주지 않는다.
console.log($input.getAttribute('value')); // ungmo2
const $input = document.getElementById('user');
// id 값 foo로 변경
$input.id = 'foo';
console.log($input.id); // foo
console.log($input.getAttribute('id')); // foo
HTML 어트리뷰트와 DOM 프로퍼티의 대응 관계
DOM 프로퍼티 값의 타입
<input type="checkbox" checked>
const $checkbox = document.querySelector('input[type="checkbox"]');
console.log($checkbox.getAttribute('checked')); // ''
console.log($checkbox.checked); // true
<ul class="users">
<li id="1" data-user-id="7621" data-role="admin">Lee</li>
<li id="2" data-user-id="9524" data-role="subscriber">Kim</li>
</ul>
const users = [...document.querySelector('.user').children];
// user-id가 '7621'인 요소 노드를 취득
const user = users.find(user => user.dataset.userId === '7621');
console.log(user.dataset.role); // admin
// data-role 값 변경
user.dataset.role = 'subscriber';
console.log(user.dataset); // DOMStringMap {userId: '7621', role: 'subscriber'}
// data-test-name 추가
user.dataset.testName = 'test';
console.log(user.dataset); // DOMStringMap {userId: '7621', role: 'subscriber', testName: 'test'}
// <li id="1" data-user-id="7621" data-role="subscriber" data-test-name="test">Lee</li>
// 카멜 케이스
$div.style.backgroundColor = 'yellow';
// 케밥 케이스
$div.style['background-color'] = 'yellow';
// 단위 지정 필수
$div.style.width = '100px';
className
const $box = document.querySelector('.box');
console.log($box.className); // 'box red'
// red -> blue 클래스명 변경
$box.className = $box.className.replace('red', 'blue');
classList
// add
$box.classList.add('foo'); // class="box red foo"
$box.classList.add('bar', 'baz'); // class="box red foo bar baz"
// remove
$box.classList.remove('foo'); // class="box red bar baz"
$box.classList.remove('bar', 'baz'); // class="box red"
$box.classList.remove('x'); // class="box red"
// item
$box.classList.item(0); // 'box'
$box.classList.item(1); // 'red'
// contains
$box.classList.contains('box'); // true
$box.classList.contains('blue'); // false
// replace
$box.classList.replace('red', 'blue'); // class="box blue"
// toggle
$box.classList.toggle('foo'); // class="box blue foo"
$box.classList.toggle('foo'); // class="box blue"
$box.classList.toggle('foo', true); // class="box blue foo"
$box.classList.toggle('foo', false); // class="box blue"
<style>
body {color: red;}
.box {width: 100px; height: 50px; background-color: red; border: 1px solid black;}
.box::before {content: 'Hello';}
</style>
<div class="box">Box</div>
<script>
const $box = document.querySelector('.box');
// box 요소에 적용된 모든 CSS 스타일 취득
const computedStyle = window.getComputedStyle($box);
console.log(computedStyle); // CSSStyleDeclaration
// 임베딩 스타일
console.log(computedStyle.width); // 100px;
console.log(computedStyle.height); // 50px;
console.log(computedStyle.backgroundColor); // rgb(255, 0, 0);
console.log(computedStyle.border); // 1px solid rgb(0, 0, 0);
// 상속 스타일
console.log(computedStyle.color); // rgb(255, 0, 0)
// 기본 스타일
console.log(computedStyle.display); // block
// 의사 요소
const computedStyleBefore = window.getComputedStyle($box, ':before');
console.log(computedStyleBefore.content); // 'Hello'
</script>