WeniVooks

검색

JavaScript 에센셜

DOM 제어하기

1. 이벤트 기초

1.1 이벤트 등록

DOM 요소에는 이벤트를 등록할 수 있습니다. 이벤트는 사용자의 행동을 감지하여 특정 작업을 수행하는 기능입니다. 자바스크립트에서는 addEventListener() 메서드를 사용하여 이벤트를 추가할 수 있습니다. 이 메서드는 두 개의 인수를 받습니다. 첫 번째 인수는 이벤트 타입(예: click, mouseover, keydown 등)이고, 두 번째 인수는 이벤트가 발생했을 때 실행될 함수(리스너 함수 또는 핸들러 함수)입니다.

target.addEventListener(type, listener);
target.addEventListener(type, listener);
<button>Click me!</button>
 
<script>
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    alert('Hello World!');
  });
</script>
<button>Click me!</button>
 
<script>
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    alert('Hello World!');
  });
</script>
이벤트 타입

이벤트 타입은 사용자가 웹 페이지에서 발생시키는 다양한 행동을 나타냅니다. 자주 사용되는 이벤트 타입은 다음과 같습니다.

이벤트 유형이벤트 이름설명
마우스click요소를 클릭할 때
dblclick요소를 더블 클릭할 때
mousedown마우스 버튼을 누를 때
mouseup마우스 버튼을 놓을 때
mousemove마우스를 움직일 때
mouseover마우스가 요소 위로 올라갈 때
mouseout마우스가 요소에서 나갈 때
mouseenter마우스가 요소에 들어갈 때 (버블링없음)
mouseleave마우스가 요소를 떠날 때 (버블링없음)
키보드keydown키를 누를 때
keyup키를 놓을 때
submit폼이 제출될 때
reset폼이 초기화될 때
change요소 값이 변경되고 포커스가 빠져나갈 때
input요소 값이 변경될 때마다
focus요소에 포커스가 갈 때 (버블링없음)
blur요소에서 포커스가 빠져나갈 때 (버블링없음)
문서/윈도우load페이지 로딩이 완료될 때 (버블링없음)
DOMContentLoadedHTML 파싱 완료 시
resize브라우저 창 크기 변경 시 (버블링없음)
scroll스크롤 시 (버블링없음)
터치touchstart터치가 시작될 때
touchmove터치하며 움직일 때
touchend터치가 끝날 때
드래그dragstart드래그 시작
drag드래그 중
dragend드래그 종료
drop요소가 드롭될 때
1.2 클래스 제어

classList 객체를 사용하여 요소의 클래스 속성을 제어할 수 있습니다. 클래스 별로 스타일을 적용할 수 있기 때문에, 자바스크립트를 사용하여 동적으로 클래스를 추가하거나 제거하여 스타일을 변경할 수 있습니다.

  • add(className) : 클래스를 추가합니다.
  • remove(className) : 클래스를 제거합니다.
  • toggle(className) : 클래스가 있으면 제거하고, 없으면 추가합니다.
  • classList : 클래스 목록을 반환합니다.
    • classList.contains(className) : 클래스가 있는지 확인합니다.
<style>
  .blue {
    background-color: blue;
    color: white;
  }
</style>
 
<button>Make me BLUE!</button>
 
<script>
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    // myBtn.classList.add("blue"); // 클래스를 추가합니다.
    // myBtn.classList.remove("blue"); // 클래스를 제거합니다.
    myBtn.classList.toggle('blue'); // 클래스를 토글합니다.
    console.log(myBtn.classList.contains('blue')); // 클래스가 있는지 확인합니다.
  });
</script>
<style>
  .blue {
    background-color: blue;
    color: white;
  }
</style>
 
<button>Make me BLUE!</button>
 
<script>
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    // myBtn.classList.add("blue"); // 클래스를 추가합니다.
    // myBtn.classList.remove("blue"); // 클래스를 제거합니다.
    myBtn.classList.toggle('blue'); // 클래스를 토글합니다.
    console.log(myBtn.classList.contains('blue')); // 클래스가 있는지 확인합니다.
  });
</script>
1.3 스타일 제어

요소는 그 안에 CSSStyleDeclaration 객체라 불리는 style 객체가 존재합니다. 이 객체는 요소의 스타일 정보를 가지고 있으며, 스타일과 관련한 프로퍼티와 메소드를 지원합니다.

<p>Hello World!</p>
<button>Change Style</button>
 
<script>
  const myP = document.querySelector('p');
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    myP.style.color = 'red'; // 현재 스타일 정보를 변경합니다.
    myP.style.fontWeight = 'bold'; // 현재 스타일 정보에 font-weight 속성이 없다면 추가합니다.
  });
 
  // 현재 스타일 정보를 가져옵니다.
  // const txtColor = myP.style.color;
  // console.log(txtColor); // 빈 문자열 (초기 상태에서는 스타일이 직접 설정되지 않았기 때문)
 
  // 현재 스타일 정보를 제거(초기화)합니다.
  // myP.style.color = null;
</script>
<p>Hello World!</p>
<button>Change Style</button>
 
<script>
  const myP = document.querySelector('p');
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    myP.style.color = 'red'; // 현재 스타일 정보를 변경합니다.
    myP.style.fontWeight = 'bold'; // 현재 스타일 정보에 font-weight 속성이 없다면 추가합니다.
  });
 
  // 현재 스타일 정보를 가져옵니다.
  // const txtColor = myP.style.color;
  // console.log(txtColor); // 빈 문자열 (초기 상태에서는 스타일이 직접 설정되지 않았기 때문)
 
  // 현재 스타일 정보를 제거(초기화)합니다.
  // myP.style.color = null;
</script>

style 객체의 속성 식별자 규칙

  • 속성 이름이 한 글자라면 그대로 사용합니다. (height, color 등)
  • 속성 이름이 대쉬(-) 를 통해 여러 단어로 나눠져있는 경우는 카멜케이스로 사용합니다. (background-image ⇒  backgroundImage)
  • float 속성의 경우 이미 자바스크립트의 예약어로 존재하기 때문에 cssFloat으로 사용됩니다.

style 객체를 통해 설정된 스타일은 CSS inline 스타일과 동일한 가중치를 가집니다. 때문에 CSS를 통해 수정의 여지가 있는 스타일에는 많이 사용되지 않는 편입니다. 이럴경우 classList를 이용한 클래스 제어가 더 효과적입니다.

1.4 속성 제어

요소의 속성을 설정하기 위해서 setAttribute() 메서드를 사용할 수 있습니다. 아래 코드를 html 파일로 만들어 실행해보세요. 버튼을 클릭할 때마다 이미지의 속성이 변경됩니다. 속성을 제거할 때는 removeAttribute() 메서드에 제거하고자 하는 속성명을 전달합니다.

이미지가 로딩되는 시간이 있기 때문에 이미지가 변경되는 것을 확인하기 위해서는 버튼을 바로 누르지 마시고 로딩이 끝난 후 버튼을 클릭해주세요.

<button>Change Image</button>
<img
  src="https://paullab.co.kr/images/weniv-licat.png"
  alt="라이캣"
  id="image"
/>
 
<script>
  const myImg = document.getElementById('image');
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    myImg.setAttribute('src', 'https://paullab.co.kr/images/weniv-soulgom.png');
    myImg.setAttribute('alt', '소울곰');
  });
 
  // alt 속성 제거
  // myImg.removeAttribute('alt');
</script>
<button>Change Image</button>
<img
  src="https://paullab.co.kr/images/weniv-licat.png"
  alt="라이캣"
  id="image"
/>
 
<script>
  const myImg = document.getElementById('image');
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    myImg.setAttribute('src', 'https://paullab.co.kr/images/weniv-soulgom.png');
    myImg.setAttribute('alt', '소울곰');
  });
 
  // alt 속성 제거
  // myImg.removeAttribute('alt');
</script>
data 속성

data-* 속성을 사용하면 HTML 요소에 추가적인 정보를 저장하여 마치 프로그램 가능한 객체처럼 사용할 수 있게 합니다. 단, data 속성의 이름에는 콜론(:) 이나 영문 대문자가 들어가서는 안됩니다. 자바스크립트로 data 속성을 가져오기 위해서는 dataset 객체를 사용합니다.

<img
  class="terran battle-cruiser"
  src="battle-cruiser.png"
  data-ship-id="324"
  data-weapons="laser"
  data-health="400"
  data-mana="250"
/>
<script>
  const img = document.querySelector('img');
  console.log(img.dataset);
  console.log(img.dataset.shipId);
</script>
<img
  class="terran battle-cruiser"
  src="battle-cruiser.png"
  data-ship-id="324"
  data-weapons="laser"
  data-health="400"
  data-mana="250"
/>
<script>
  const img = document.querySelector('img');
  console.log(img.dataset);
  console.log(img.dataset.shipId);
</script>
1.5 콘텐츠 수정
innerHTML

innerHTML은 요소 내에 포함된 HTML 마크업을 가져오거나 설정합니다.

<div id="example">
  이것은 <strong>굵은</strong> 텍스트입니다.
  <span style="display: none;">숨겨진 텍스트</span>
  <script>
    console.log('스크립트');
  </script>
</div>
 
<script>
  const example = document.getElementById('example');
  console.log(example.innerHTML);
</script>
<div id="example">
  이것은 <strong>굵은</strong> 텍스트입니다.
  <span style="display: none;">숨겨진 텍스트</span>
  <script>
    console.log('스크립트');
  </script>
</div>
 
<script>
  const example = document.getElementById('example');
  console.log(example.innerHTML);
</script>

innerHTML에 값을 할당했을 때 마크업으로 변환할 수 있는 문자열이 있으면 실제 요소로 렌더링하여 화면에 출력합니다.

<input type="text" id="inp-text" />
<button type="button" class="submit-btn">요소 추가하기</button>
<ul id="result"></ul>
 
<script>
  const result = document.getElementById('result');
  const inpText = document.getElementById('inp-text');
  const submitBtn = document.querySelector('.submit-btn');
 
  submitBtn.addEventListener('click', () => {
    result.innerHTML += `<li>${inpText.value}</li>`;
  });
</script>
<input type="text" id="inp-text" />
<button type="button" class="submit-btn">요소 추가하기</button>
<ul id="result"></ul>
 
<script>
  const result = document.getElementById('result');
  const inpText = document.getElementById('inp-text');
  const submitBtn = document.querySelector('.submit-btn');
 
  submitBtn.addEventListener('click', () => {
    result.innerHTML += `<li>${inpText.value}</li>`;
  });
</script>

innerHTML을 사용하면 HTML 마크업을 문자열로 작성하여 요소에 삽입할 수 있습니다. 위의 예시에서는 사용자가 입력한 값을 <li> 태그로 감싸서 result 요소에 추가합니다. 이때, innerHTML은 기존의 HTML 마크업을 덮어쓰지 않고, 새로운 마크업을 추가합니다.

이처럼 입력된 문자열을 HTML로 파싱하기 때문에 신뢰할 수 없는 사용자의 데이터가 삽입되어 악성 스크립트가 실행될 위험이 있습니다. HTML Living Standard에서는 innerHTML을 통해 삽입된 <script> 요소는 실행하지 않도록 정의되어 있습니다. 하지만 다음과 같은 방법으로도 자바스크립트를 실행할 수 있습니다. 아래 코드를 입력하고 버튼을 클릭해보세요.

<img src="" onerror='alert("Hello User 😈")' />
<img src="" onerror='alert("Hello User 😈")' />

템플릿 리터럴과 함께 조합하여 복잡한 HTML 구조를 동적으로 생성할 수 있다는 장점이 있으나 보안 상의 위험을 방지하기 위해서 innerText 또는 textContent를 사용하는 것을 권장합니다.

innerHTML 사용시 주의 사항
innerText

innerText는 요소의 렌더링된 텍스트 콘텐츠를 나타냅니다. 즉, 화면에 실제로 표시되는 모든 텍스트 콘텐츠를 표현합니다. HTML 태그를 제외한 순수한 텍스트만 반환하며, CSS에 의해 숨겨진 텍스트는 반환하지 않습니다. innerText와 textContent는 할당된 값은 순수 텍스트로 처리됩니다.

<div id="example">
  이것은 <strong>굵은</strong> <br />텍스트입니다.
  <span style="display: none;">숨겨진 텍스트</span>
  <script>
    console.log('스크립트');
  </script>
</div>
 
<script>
  const example = document.getElementById('example');
  console.log(example.innerText);
</scrip>
<div id="example">
  이것은 <strong>굵은</strong> <br />텍스트입니다.
  <span style="display: none;">숨겨진 텍스트</span>
  <script>
    console.log('스크립트');
  </script>
</div>
 
<script>
  const example = document.getElementById('example');
  console.log(example.innerText);
</scrip>
textContent

textContent 속성은 노드의 모든 텍스트 콘텐츠를 가져옵니다. innerText와 비슷하지만, textContent는 화면 렌더링과 상관없이 숨겨진 텍스트를 포함하여 요소의 모든 텍스트 콘텐츠를 반환합니다.

<div id="example">
  이것은 <strong>굵은</strong> <br />텍스트입니다.
  <span style="display: none;">숨겨진 텍스트</span>
  <script>
    console.log('스크립트');
  </script>
</div>
 
<script>
  const element = document.getElementById('example');
 
  console.log(element.textContent);
</script>
<div id="example">
  이것은 <strong>굵은</strong> <br />텍스트입니다.
  <span style="display: none;">숨겨진 텍스트</span>
  <script>
    console.log('스크립트');
  </script>
</div>
 
<script>
  const element = document.getElementById('example');
 
  console.log(element.textContent);
</script>
innerText 와 textContent의 차이
1.6 요소 생성 및 조작
createElement

createElement(tagName) 메서드를 사용하여 새로운 요소를 생성할 수 있습니다. 이 메서드는 HTML 태그 이름을 인수로 받아 해당 태그의 요소를 생성합니다. 생성된 요소는 DOM에 추가되기 전까지는 화면에 표시되지 않습니다.

<input type="text" id="inp-text" />
<button type="button" class="submit-btn">요소 추가하기</button>
 
<ul id="result"></ul>
<input type="text" id="inp-text" />
<button type="button" class="submit-btn">요소 추가하기</button>
 
<ul id="result"></ul>
const result = document.getElementById('result');
const inpText = document.getElementById('inp-text');
const submitBtn = document.querySelector('.submit-btn');
 
submitBtn.addEventListener('click', () => {
  const li = document.createElement('li');
  li.textContent = inpText.value;
  result.appendChild(li);
});
const result = document.getElementById('result');
const inpText = document.getElementById('inp-text');
const submitBtn = document.querySelector('.submit-btn');
 
submitBtn.addEventListener('click', () => {
  const li = document.createElement('li');
  li.textContent = inpText.value;
  result.appendChild(li);
});
appendChild

appendChild() 메서드를 사용하여 생성된 요소를 DOM에 추가할 수 있습니다. 이 메서드는 부모 요소의 마지막에 자식 요소를 추가합니다. appendChild() 메서드는 추가된 요소를 반환합니다.

submitBtn.addEventListener('click', () => {
  const li = document.createElement('li');
  li.textContent = inpText.value;
  result.appendChild(li);
});
submitBtn.addEventListener('click', () => {
  const li = document.createElement('li');
  li.textContent = inpText.value;
  result.appendChild(li);
});
append

여러 개의 요소를 추가할 때는 append() 메서드를 사용할 수 있습니다. 이 메서드는 여러 개의 요소를 한 번에 추가할 수 있습니다.

submitBtn.addEventListener('click', () => {
  const li1 = document.createElement('li');
  li1.textContent = inpText.value;
  const li2 = document.createElement('li');
  li2.textContent = '추가된 리스트 아이템';
  result.append(li1, li2);
});
submitBtn.addEventListener('click', () => {
  const li1 = document.createElement('li');
  li1.textContent = inpText.value;
  const li2 = document.createElement('li');
  li2.textContent = '추가된 리스트 아이템';
  result.append(li1, li2);
});
insertBefore

특정 위치에 요소를 추가할 수도 있습니다. insertBefore() 메서드를 사용하여 특정 요소 앞에 새로운 요소를 추가할 수 있습니다. 이 메서드는 두 개의 인수를 받습니다. 첫 번째 인수는 추가할 요소이고, 두 번째 인수는 기준이 되는 요소입니다. 두 번째 인수가 null이면 appendChild()처럼 동작하여 부모 요소의 마지막 자식 노드로 추가됩니다.

<input type="text" id="inp-text" />
<button type="button" class="submit-btn">요소 추가하기</button>
 
<ul id="result">
  <li class="target">📌 기준 아이템</li>
</ul>
<input type="text" id="inp-text" />
<button type="button" class="submit-btn">요소 추가하기</button>
 
<ul id="result">
  <li class="target">📌 기준 아이템</li>
</ul>
const result = document.getElementById('result');
const inpText = document.getElementById('inp-text');
const submitBtn = document.querySelector('.submit-btn');
const targetNode = result.querySelector('li.target');
 
submitBtn.addEventListener('click', () => {
  const li = document.createElement('li');
  li.textContent = inpText.value;
  result.insertBefore(li, targetNode);
});
const result = document.getElementById('result');
const inpText = document.getElementById('inp-text');
const submitBtn = document.querySelector('.submit-btn');
const targetNode = result.querySelector('li.target');
 
submitBtn.addEventListener('click', () => {
  const li = document.createElement('li');
  li.textContent = inpText.value;
  result.insertBefore(li, targetNode);
});
insertAdjacentHTML

inserAdjacentHTML()을 사용하여 특정 위치에 요소를 추가할 수 있습니다. 첫 번째 인수는 삽입할 위치를 나타내는 문자열이고, 두 번째 인수는 삽입할 HTML 문자열입니다.

target.insertAdjacentHTML('beforebegin', newElement);
target.insertAdjacentHTML('beforebegin', newElement);
위치설명
beforebegin시작 태그의 바로 앞에 삽입
afterbegin시작 태그의 바로 뒤에 삽입
beforeend끝 태그의 바로 앞에 삽입
afterend끝 태그의 바로 뒤에 삽입
<p id="target">--target--</p>
 
<script>
  const target = document.getElementById('target');
  target.insertAdjacentHTML('beforebegin', '<span>안녕하세요</span>');
  target.insertAdjacentHTML('afterbegin', '<span>위니브입니다.</span>');
  target.insertAdjacentHTML('beforeend', '<span>제주도로</span>');
  target.insertAdjacentHTML('afterend', '<span>놀러오세요!</span>');
</script>
<p id="target">--target--</p>
 
<script>
  const target = document.getElementById('target');
  target.insertAdjacentHTML('beforebegin', '<span>안녕하세요</span>');
  target.insertAdjacentHTML('afterbegin', '<span>위니브입니다.</span>');
  target.insertAdjacentHTML('beforeend', '<span>제주도로</span>');
  target.insertAdjacentHTML('afterend', '<span>놀러오세요!</span>');
</script>

DocumentFagment
DOM 요소에 여러 개의 자식 요소를 추가할 때, DocumentFragment를 사용하면 성능을 향상시킬 수 있습니다. DocumentFragment는 메모리 상에 존재하는 가상의 DOM 노드입니다. 이 노드는 실제 DOM에 추가되지 않으며, 여러 개의 요소를 그룹화하여 한 번에 DOM에 추가할 수 있습니다.

<ul id="result"></ul>
 
<script>
  const members = ['라이캣', '빙키', '뮤라', '소울곰'];
  const ul = document.getElementById('result');
 
  members.forEach((member) => {
    const li = document.createElement('li');
    li.textContent = member;
    ul.appendChild(li);
  });
</script>
<ul id="result"></ul>
 
<script>
  const members = ['라이캣', '빙키', '뮤라', '소울곰'];
  const ul = document.getElementById('result');
 
  members.forEach((member) => {
    const li = document.createElement('li');
    li.textContent = member;
    ul.appendChild(li);
  });
</script>

위와 같이 반복적으로 DOM에 요소를 추가할 경우 성능이 저하될 수 있습니다. 대신 DocumentFragment를 사용하여 성능을 향상시킬 수 있습니다.

const members = ['라이캣', '빙키', '뮤라', '소울곰'];
const ul = document.getElementById('result');
const fragment = document.createDocumentFragment();
members.forEach((member) => {
  const li = document.createElement('li');
  li.textContent = member;
  fragment.appendChild(li);
});
ul.appendChild(fragment);
const members = ['라이캣', '빙키', '뮤라', '소울곰'];
const ul = document.getElementById('result');
const fragment = document.createDocumentFragment();
members.forEach((member) => {
  const li = document.createElement('li');
  li.textContent = member;
  fragment.appendChild(li);
});
ul.appendChild(fragment);
1.7 요소 제거하기
removeChild

element.removeChild() 메서드를 사용하여 부모 노드에서 자식 노드를 제거할 수 있습니다. 아래 코드를 html 파일로 만들어 실행해보세요. 버튼을 클릭할 때마다 마지막 리스트 아이템이 제거됩니다.

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
</ul>
 
<button id="remove">Remove Last Item</button>
 
<script>
  const removeBtn = document.getElementById('remove');
  const myUl = document.querySelector('ul');
 
  removeBtn.addEventListener('click', function () {
    if (myUl.lastElementChild) {
      myUl.removeChild(myUl.lastElementChild);
    }
  });
</script>
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
</ul>
 
<button id="remove">Remove Last Item</button>
 
<script>
  const removeBtn = document.getElementById('remove');
  const myUl = document.querySelector('ul');
 
  removeBtn.addEventListener('click', function () {
    if (myUl.lastElementChild) {
      myUl.removeChild(myUl.lastElementChild);
    }
  });
</script>

모든 자식 요소를 삭제하고자 할 때, 반복문을 활용할 수 있습니다.

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
</ul>
<button id="remove">Remove All Items</button>
 
<script>
  const removeBtn = document.getElementById('remove');
  const myUl = document.querySelector('ul');
 
  removeBtn.addEventListener('click', function () {
    while (myUl.firstChild) {
      myUl.removeChild(myUl.firstChild);
    }
  });
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
</ul>
<button id="remove">Remove All Items</button>
 
<script>
  const removeBtn = document.getElementById('remove');
  const myUl = document.querySelector('ul');
 
  removeBtn.addEventListener('click', function () {
    while (myUl.firstChild) {
      myUl.removeChild(myUl.firstChild);
    }
  });

removeChild() 메서드 사용 시 주의 사항
removeChild() 메서드는 부모 요소에서 자식 요소를 제거할 때 사용됩니다. 이 메서드는 제거된 요소를 반환합니다. 만약 제거하려는 요소가 부모 요소의 자식이 아니라면 오류가 발생합니다. 따라서, removeChild() 메서드를 사용할 때는 반드시 해당 요소가 부모 요소의 자식인지 확인해야 합니다.

innerHTML

innerHTML을 이용하여 모든 자식 요소를 삭제할 수도 있습니다.

myUl.innerHTML = '';
myUl.innerHTML = '';

remove() 메서드를 사용하여 요소 자체를 제거할 수 있습니다. 이 메서드는 요소를 DOM에서 제거합니다.

const result = document.getElementById('result');
result.remove();
const result = document.getElementById('result');
result.remove();

2. 요소 탐색

DOM 트리에서 특정 요소를 선택한 후, 해당 요소의 자식, 부모, 형제 요소에 접근할 수 있는 메서드들이 있습니다. 이러한 메서드를 사용하여 DOM 트리를 탐색할 수 있습니다.

2.1 부모 요소 탐색하기

parentElement를 사용하여 부모 요소에 접근할 수 있습니다. parentElement는 선택한 요소의 부모 요소를 반환합니다. 만약 선택한 요소가 최상위 요소라면 null을 반환합니다.

<div id="parent">
  <!-- 주석입니다. -->
  텍스트입니다.
  <div class="child">Hello</div>
  <div class="child">World</div>
</div>
<div id="parent">
  <!-- 주석입니다. -->
  텍스트입니다.
  <div class="child">Hello</div>
  <div class="child">World</div>
</div>
const childElement = document.querySelector('.child');
const parentElement = childElement.parentElement;
console.log(parentElement); // <div class="parent">...</div>
const childElement = document.querySelector('.child');
const parentElement = childElement.parentElement;
console.log(parentElement); // <div class="parent">...</div>
2.2 자식 요소 탐색하기
children

children을 사용하여 자식 요소에 접근할 수 있습니다. children은 선택한 요소의 자식 요소를 HTMLCollection 형태로 반환합니다.

const parentElement = document.querySelector('.parent');
const childElements = parentElement.children;
console.log(childElements); // HTMLCollection(2) [div.child, div.child]
const parentElement = document.querySelector('.parent');
const childElements = parentElement.children;
console.log(childElements); // HTMLCollection(2) [div.child, div.child]
firstElementChild와 lastElementChild

firstElementChildlastElementChild를 사용하여 첫 번째 자식 요소와 마지막 자식 요소에 접근할 수 있습니다. 이 메서드는 선택한 요소의 첫 번째 또는 마지막 자식 요소를 반환합니다.

const parentElement = document.querySelector('.parent');
const firstChild = parentElement.firstElementChild;
const lastChild = parentElement.lastElementChild;
console.log(firstChild); // <div class="child">Hello</div>
console.log(lastChild); // <div class="child">World</div>
const parentElement = document.querySelector('.parent');
const firstChild = parentElement.firstElementChild;
const lastChild = parentElement.lastElementChild;
console.log(firstChild); // <div class="child">Hello</div>
console.log(lastChild); // <div class="child">World</div>
childNodes

childNodes를 사용하면 모든 자식 노드를 NodeList로 반환합니다. 이 때, NodeList는 동적으로 변경됩니다. 즉, 자식 노드가 추가되거나 삭제되면 NodeList도 자동으로 업데이트됩니다.

const parentElement = document.querySelector('.parent');
const childNodes = parentElement.childNodes;
console.log(childNodes); // NodeList(7) [#text, #comment, #text, div.child, #text, div.child, #text]
const parentElement = document.querySelector('.parent');
const childNodes = parentElement.childNodes;
console.log(childNodes); // NodeList(7) [#text, #comment, #text, div.child, #text, div.child, #text]
2.3 형제 요소 탐색하기

nextElementSiblingpreviousElementSibling을 사용하여 형제 요소에 접근할 수 있습니다. nextElementSibling은 선택한 요소의 다음 형제 요소를 반환하고, previousElementSibling은 이전 형제 요소를 반환합니다.

<div id="parent">
  <!-- 주석입니다. -->
  텍스트입니다.
  <div class="child">Hello</div>
  <div class="child">World</div>
  <div>Hello</div>
  <div>Weniv</div>
</div>
<div id="parent">
  <!-- 주석입니다. -->
  텍스트입니다.
  <div class="child">Hello</div>
  <div class="child">World</div>
  <div>Hello</div>
  <div>Weniv</div>
</div>
const childElement = document.querySelector('.child');
const previousSibling = childElement.previousElementSibling;
const nextSibling = childElement.nextElementSibling;
 
console.log(previousSibling); // null
console.log(nextSibling); // <div class="child">World</div>
const childElement = document.querySelector('.child');
const previousSibling = childElement.previousElementSibling;
const nextSibling = childElement.nextElementSibling;
 
console.log(previousSibling); // null
console.log(nextSibling); // <div class="child">World</div>

모든 형제 요소 탐색하기
parentElementchildren을 조합하여 모든 형제 요소를 탐색할 수 있습니다.

const childElement = document.querySelector('.child');
const parentElement = childElement.parentElement;
const siblings = parentElement.children;
for (let i = 0; i < siblings.length; i++) {
  if (siblings[i] !== childElement) {
    console.log(siblings[i]);
  }
}
const childElement = document.querySelector('.child');
const parentElement = childElement.parentElement;
const siblings = parentElement.children;
for (let i = 0; i < siblings.length; i++) {
  if (siblings[i] !== childElement) {
    console.log(siblings[i]);
  }
}
2.4 closest

closest 메서드는 선택한 요소에서 가장 가까운 조상 요소를 찾습니다. 이 메서드는 선택한 요소부터 시작하여 부모 요소를 거슬러 올라가며, 주어진 선택자와 일치하는 첫 번째 조상 요소를 반환합니다. 만약 일치하는 조상 요소가 없다면 null을 반환합니다.

<section class="first">
  <div>Hello</div>
  <div class="target">World</div>
</section>
<section class="second">
  <div>Hello</div>
  <div>Weniv</div>
</section>
<section class="first">
  <div>Hello</div>
  <div class="target">World</div>
</section>
<section class="second">
  <div>Hello</div>
  <div>Weniv</div>
</section>
const childElement = document.querySelector('.target');
const closestElement = childElement.closest('section');
console.log(closestElement); // <section class="first">...</section>
const childElement = document.querySelector('.target');
const closestElement = childElement.closest('section');
console.log(closestElement); // <section class="first">...</section>
7.1 DOM API와 DOM에 접근하기7.3 DOM의 이벤트 흐름