WeniVooks

검색

JavaScript 베이스캠프

DOM 제어하기

1. DOM 제어하기

DOM을 제어하는 것은 웹 페이지의 동적 콘텐츠를 생성하고 변경하는 데 필수적입니다. 여기에서는 이벤트 추가, 클래스 제어, 요소 생성 및 삭제, 속성 제어 등 다양한 DOM 제어 방법을 살펴보겠습니다.

1.1 이벤트 삽입

target.addEventListener(type, listener) 메서드를 사용하여 요소에 이벤트를 추가할 수 있습니다. 아래 코드는 버튼을 클릭할 때마다 콘솔에 'hello world'를 출력합니다. 여기서 click은 이벤트 타입이고, function () { console.log('hello world'); }는 리스너 함수(또는 이벤트 핸들러 함수)입니다. 이 함수는 이벤트가 발생했을 때 실행됩니다. 핸들러 함수라는 용어는 실무에서 대화할 때에도 자주 등장하니 잘 기억해두세요.

HTML 파일을 만들어서 아래 코드를 실행해보고 콘솔에 출력되는 값을 확인해보세요.

<button>HELLO!</button>
<script>
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    console.log('hello world');
  });
</script>
<button>HELLO!</button>
<script>
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    console.log('hello world');
  });
</script>

이벤트의 타입에는 click, mouseover, mouseout, wheel 등 다양한 이벤트가 있습니다. 리스너 함수의 인수에는 이벤트에 대한 정보가 담겨 있습니다.

1.2 클래스 제어

classList 객체를 사용하여 요소의 클래스 속성을 제어할 수 있습니다. 토글은 클래스가 없으면 추가하고, 있으면 제거합니다. 아래 코드를 html 파일로 만들어 실행해보세요. 버튼을 클릭할 때마다 버튼 색상이 변경됩니다.

<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 요소 제어

DOM api를 이용하면 요소를 새롭게 생성하고, 위치하고, 제거할 수 있습니다.

  1. document.createElement(target) : target 요소를 생성합니다.
  2. document.createTextNode(target) : target 텍스트를 생성합니다.
  3. element.appendChild(target) : target 요소를 element의 자식으로 위치합니다.
  4. element.removeChild(target) : element의 target 자식 요소를 제거합니다.
  5. element.append(target) : target 요소를 element의 자식으로 위치합니다. appendChild 와 다른점은 노드 뿐만 아니라 여러개의 노드를 한번에, 그리고 텍스트도 자식 노드로 포함시킬 수 있다는것 입니다.
  6. target.remove() : target 요소를 제거합니다.
1.3.1 요소 생성 및 추가

document.createElement() 메서드를 사용하여 새로운 요소를 생성하고, element.appendChild() 메서드를 사용하여 생성한 요소를 추가할 수 있습니다.

아래 코드를 html 파일로 만들어 실행해보세요. 버튼을 클릭할 때마다 리스트 아이템이 추가됩니다.

<ul></ul>
<button>Make me MORE!</button>
 
<script>
  const myBtn = document.querySelector('button');
  const myUl = document.querySelector('ul');
 
  myBtn.addEventListener('click', function () {
    for (let i = 0; i < 5; i++) {
      const myLi = document.createElement('li');
      myLi.textContent = `Item ${myUl.children.length + 1}`;
      myUl.appendChild(myLi);
    }
  });
</script>
<ul></ul>
<button>Make me MORE!</button>
 
<script>
  const myBtn = document.querySelector('button');
  const myUl = document.querySelector('ul');
 
  myBtn.addEventListener('click', function () {
    for (let i = 0; i < 5; i++) {
      const myLi = document.createElement('li');
      myLi.textContent = `Item ${myUl.children.length + 1}`;
      myUl.appendChild(myLi);
    }
  });
</script>
1.3.2 요소 제거

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

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</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>
</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>
1.4 요소 값 제어

DOM API를 이용하면 요소 안의 값에 접근하여 값을 가져오거나, 변경할 수 있습니다. 아래 코드를 html 파일을 만들어 실행해보세요. 입력창에 값을 입력하고 버튼을 클릭하면 입력한 값이 p 태그에 출력됩니다. 주석을 해제하면 실시간으로 값이 반영됩니다.

<p></p>
<input type="text" />
<button>Write Something!</button>
 
<script>
  const myBtn = document.querySelector('button');
  const myP = document.querySelector('p');
  const myInput = document.querySelector('input');
 
  myBtn.addEventListener('click', function () {
    myP.textContent = myInput.value;
  });
 
  // 실시간으로 값 반영하기
  //   myInput.addEventListener('input', function () {
  //     myP.textContent = myInput.value;
  //   });
 
  // HTML을 삽입하기
  myP.innerHTML = "<strong>I'm Strong!!</strong>";
</script>
<p></p>
<input type="text" />
<button>Write Something!</button>
 
<script>
  const myBtn = document.querySelector('button');
  const myP = document.querySelector('p');
  const myInput = document.querySelector('input');
 
  myBtn.addEventListener('click', function () {
    myP.textContent = myInput.value;
  });
 
  // 실시간으로 값 반영하기
  //   myInput.addEventListener('input', function () {
  //     myP.textContent = myInput.value;
  //   });
 
  // HTML을 삽입하기
  myP.innerHTML = "<strong>I'm Strong!!</strong>";
</script>
1.5 속성 제어하기

자바스크립트를 사용하여 요소의 속성을 제어하는 방법은 다양합니다. 몇 가지 방법을 알아보겠습니다.

  1. 요소의 스타일을 제어하는 style 객체
  2. 요소의 속성을 제어하는 setAttribute() 메서드
  3. 요소의 속성을 제거하는 removeAttribute() 메서드
1.5.1 style 객체

요소는 그 안에 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.5.2 setAttribute() 메서드

setAttribute() 메서드를 사용하여 요소의 속성을 설정할 수 있습니다. 아래 코드를 html 파일로 만들어 실행해보세요. 버튼을 클릭할 때마다 이미지의 속성이 변경됩니다.

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

<img src="https://via.placeholder.com/150" alt="placeholder" id="image" />
<button>Change Image</button>
 
<script>
  const myImg = document.getElementById('image');
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    myImg.setAttribute('src', 'https://via.placeholder.com/300');
    myImg.setAttribute('alt', 'new placeholder');
  });
 
  // 속성을 제거할 때는 removeAttribute() 메서드를 사용합니다.
  // myImg.removeAttribute('alt');
</script>
<img src="https://via.placeholder.com/150" alt="placeholder" id="image" />
<button>Change Image</button>
 
<script>
  const myImg = document.getElementById('image');
  const myBtn = document.querySelector('button');
 
  myBtn.addEventListener('click', function () {
    myImg.setAttribute('src', 'https://via.placeholder.com/300');
    myImg.setAttribute('alt', 'new placeholder');
  });
 
  // 속성을 제거할 때는 removeAttribute() 메서드를 사용합니다.
  // myImg.removeAttribute('alt');
</script>
1.6 위니북스 예제

위니북스에서 위에서 배운 것을 활용하여 간단한 제품 소개 카드를 만들어보도록 하겠습니다. 설명은 코드의 주석으로 대체하겠습니다.

// JSON 데이터 // 실제 데이터는 서버(https://test.api.weniv.co.kr/mall)에서 받아오는 것이 일반적입니다. const jsonData = { "productName": "버그를 Java라 버그잡는 개리씨 키링 개발자키링 금속키링", "price": 10000, "thumbnailImg": "asset/img/1/thumbnailImg.jpg" }; // 각 요소 생성 const main = document.createElement('main'); const ProductCard = document.createElement('article'); const productName = document.createElement('h2'); const productPrice = document.createElement('p'); const productImg = document.createElement('img'); // 각 요소에 데이터 삽입 productName.textContent = `상품명 : ${jsonData.productName}`; productPrice.textContent = `가격 : ${jsonData.price}`; productImg.src = `https://test.api.weniv.co.kr/${jsonData.thumbnailImg}`; // 각 요소에 간단한 스타일링 ProductCard.style.border = '1px solid #000'; ProductCard.style.borderRadius = '10px'; ProductCard.style.padding = '10px'; productImg.style.width = '300px'; productImg.style.borderRadius = '10px'; main.style.width = '400px'; main.style.display = 'flex'; main.style.flexDirection = 'column'; // 각 요소를 부모 요소에 추가 ProductCard.appendChild(productImg); ProductCard.appendChild(productName); ProductCard.appendChild(productPrice); // 부모 요소를 DOM에 추가 main.appendChild(ProductCard); // 결과를 출력하는 곳에 main요소 추가 this.querySelector('.codeblock-result').appendChild(main);

위와 같이 코드가 작성되었을 때 아래와 같은 의문을 가질 수 있습니다. 우리는 정적으로 페이지를 만드는 것 뿐만 아니라 동적으로도 만들 수 있어야 합니다. 동적이라 함은 서버에서 주는 데이터가 다르다면 다른 페이지를 만들 수도 있어야 한다는 것입니다. 매진이면 매진이라고 떠야 하고요. 다만 이 동적에 의미는 지금은 이해하기가 어렵고 10장의 비동기 프로그래밍 이후 이해하실 수 있게 됩니다.

  • 왜 CSS로 쓰지 않고 이렇게 JS로 컨트롤 할까요?
  • 이렇게 하면 유지보수가 어렵지 않을까요?
  • html로 작성하면 안될까요?
8.1 DOM API와 DOM에 접근하기8.3 DOM의 이벤트 흐름