DOM으로 HTML 조작하기

정관우·2022년 2월 23일
1
post-thumbnail

DOM이란 무엇인가?

DOM (Document Object Model)

: HTML 요소를 자바스크립트 객체 (JavaScript Object)처럼 조작 (Manipulate)할 수 있는 Model.

Create - createElement

// div 요소 만들기
document.createElement('div')

zzQEJU2F0-1597040532407.gif

현재 tweetDiv 라는 div 요소는 createElement에 의해 노드가 생성됐다. 하지만, DOM 트리에 연결되어 있지 않아서 화면에서는 보이지 않는 상태다.

READ - querySelector, querySelectorAll

DOM으로 HTML 엘리먼트 정보를 조회하기 위해선 querySelector 메서드를 이용한다. 여러 엘리먼트를 한 번에 가져오기 위해서는 querySelectorAll 메서드를 사용하면 유사 배열로서 조회할 수 있다.

// 클래스 이름이 tweet인 HTML 엘리먼트 중 첫 번째를 조회
const oneTweet = document.querySelector('.tweet')

// 클래스 이름이 tweet인 모든 HTML 엘리먼트를 유사 배열로 조회
const tweets = document.querySelectorAll('.tweet')

// 가장 많이 쓰이는 Selector 태그
HTML : "div"
id : "#tweetList"
class : ".tweet"

querySelector는 이전 버전 브라우저와 호환되지 않을 수 있다. 예전 방식의 DOM 조작법은 다음과 같다.

// id가 container인 HTML 엘리먼트를 조회
const getOneTweet = document.getElementById('container')

// 위와 동일
const queryOneTweet = document.querySelector('#container')

// 둘은 완벽하게 같다
console.log(getOneTweet === queryOneTweet) // true

노드를 DOM 트리에 연결시키기 위해서는 append라는 메서드를 사용해야한다.

// 변수 tweetDiv를 container에 할당하기
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)

VnqXiZ-_4-1618885682009.gif

PHmvd-SCC-1597040922206.gif

append 메서드에 의해 DOM 트리에 잘 연결되었으나, div 태그 안에 아무 내용도 없기 때문에 아무것도 보이지 않은 상태다.

UPDATE - textContent, classList.add

textContent

textContent 를 사용하여, 비어있는 div 엘리먼트에 문자열을 입력할 수 있다.

console.log(oneDiv) // <div></div>
oneDiv.textContent = 'dev';
console.log(oneDiv) // <div>dev</div>

classList.add

하지만, 현재 div 엘리먼트에 클래스 이름이 없기 때문에 CSS 스타일링이 적용되지 않는다. div 엘리먼트에 class를 추가하기 위해선 classList.add 를 사용한다.

oneDiv.classList.add('tweet')
console.log(oneDiv) // <div class="tweet">dev</div>

이제 append로 class가 생성된 div를 container의 자식 요소로 추가한다

const container = document.querySelector('#container')
container.append(oneDiv)

mKIbuWsrM-1597041046326.gif

setAttribute

위 방식 이외에도 setAttribute 메서드를 사용하면, class와 id 그리고 다른 속성까지 할당할 수 있다.

// HTML
<button>This is Button</button>

// JS (DOM 조작)
var b = document.querySelector("button");
b.setAttribute("name", "helloButton");

// 이후 HTML
<button name="helloButton">This is Button</button>

DELETE - remove, removeChild

다음은 DOM을 이용하여 엘리먼트를 삭제하는 법이다. 먼저, 삭제하려는 엘리먼트의 위치를 아는 경우 remove 메서드로 해당 엘리먼트를 삭제한다.

// id가 container인 엘리먼트 선택
const container = document.querySelector('#container')

// 아래 tweetDiv를 추가
const tweetDiv = document.createElement('div')
container.append(tweetDiv)

// ** tweetDiv를 제거
tweetDiv.remove()

-xqqRNSO8-1597041273061.gif

innerHTML

여러 개의 자식 엘리먼트를 삭제하는 방법으로 여러가지가 있다. innerHTML 을 이용하면 쉽게 구현할 수 있지만 권장되지 않는 방법이다.

// id가 container인 엘리먼트의 모든 자식을 삭제
document.querySelector('#container').innerHTML = '';

innerHTML 은 XSS(Cross-Site Scripting) 공격에 취약하기 때문에 사용을 지양해야한다. XSS 공격이란 게시판이나 웹 메일 등에 스크립트 코드를 삽입하여 개발자가 의도하지 않은 악의적인 기능이 작동하게 하는 치명적인 공격이다. HTML5에서 innerHTML 안에 삽입된 <script> 태그가 실행되지 않도록 수정했지만, 여전히 다른 공격 루트가 존재한다.

removeChild

대신, 다른 삭제하는 방법들이 존재한다. removeChild를 반복문을 통해 여러 엘리먼트를 삭제할 수 있다.

const container = document.querySelector('#container');

// 첫 번째 자식 엘리먼트가 존재하면, container의 첫 번째 자식 엘리먼트를 제거
while (container.firstChild) {
  container.removeChild(container.firstChild);
}

cTVRfWv-J-1597041289625.gif

모든 자식 엘리먼트가 제거됐지만, “Tweet List”라는 제목까지 없어지는 부작용이 있다. 이를 해결하기 위해서 여러 방법이 있다.

  1. 첫 번째 자식 엘리먼트만 남겨두고 뒤에서부터 자식 엘리먼트 제거
const container = document.querySelector('#container');
while (container.children.length > 1) {
  container.removeChild(container.lastChild);
}
  1. 직접 클래스 이름이 tweet인 엘리먼트만 찾아서 지우기
const tweets = document.querySelectorAll('.tweet')
tweets.forEach(function(tweet){
    tweet.remove();
})
// or
for (let tweet of tweets){
    tweet.remove()
}

vvHWnfLjb-1597041368267.gif

DOM으로 유효성 검사 만들기

CodeSandbox에서 구경하기

항상 React로만 웹 개발을 하다가 정말 오랜만에 DOM을 이용하여 간단한 회원가입 페이지를 구현해보았다. state라는 개념 없이, HTML / CSS를 조작하는 방식으로 개발을 하니 너무 적응이 안되고 불편했다. 각각의 HTML 엘리먼트를 조작하기 위해, Selector로 선택을 해야하고 classList.addremove 와 같은 메서드를 호출하니 간단한 기능이지만 코드가 꽤나 길어졌다.

코드를 조금이라도 줄이기 위해서 유효성 검사 시, 클래스 이름을 조작하는 메서드의 코드들을 하나의 함수로 만들었다.

// 유효성 검사 실패 시, 실행하는 함수
const showFailure = (inputSelector, errorSelector) => {
	// 인풋창 테두리를 빨간색으로 변경
  inputSelector.classList.add("failure");
	// 성공 시, 파란색이었던 인풋창 테두리를 제거
	inputSelector.classList.remove("success");
	// 에러 메시지를 빨간색으로 변경 
  errorSelector.classList.add("failure");
	// 에러 메시지를 보이게 함
  errorSelector.classList.remove("hide");
	// 마지막 회원가입 버튼을 누를 시, boolean을 리턴하여 어떤 값이 잘못되었는지 알려줌
  return false;
};
profile
작지만 꾸준하게 성장하는 개발자🌳

0개의 댓글