(TIL) D+14 DOM

JulyK9·2022년 7월 16일
0

DOM (Document Object Model)

HTML 요소를 Object(JavaScript Object)처럼 조작할 수 있는 Model
DOM을 이용해서 HTML로 구성된 웹 페이지를 동적으로 만들 수 있음

HTML에 JavaScript 적용

<script src="index.js"></script>
  • 위 스크립트 태그를 만나면 브라우저는 HTML 해석을 잠시 멈추고 스크립트 요소를 먼저 실행함

스크립트 태그를 추가하는 방법

DOM 구조 조회하기

  • console.dir(document.body)
  • console.log 는 HTML 형태로 출력하고
  • console.dir 은 DOM을 객체의 모습으로 출력

JS 내장객체 window와 document 차이

DOM 다루기

  • 우선 CRUD 이해에 집중
    - 추가(Create), 조회(Read), 변경(Update), 삭제(Delete)
  • 생성한 HTML Element를 부모 엘리먼트의 자식 엘리먼트로 포함(Append)

CREAT

  • 요소를 생성하기 / createElement
  • 요소 생성
const tweetDiv = document.createElement('div') // 생성한 div 요소를 변수에 할당
  • 현재 div 태그는 그냥 붕 떠있는 상태임

APPEND

  • HTML 요소를 부모 노드에 포함(연결) / append
  • 생성한
    요소를 그 변수와 append 라는 메서드를 사용하여 요소에 넣기(append)
document.body.append(tweetDiv)

READ

  • HTML 요소를 조회 ( 왜 조회해? ⇒ append 등 조작할 대상, 위치를 선택하는 것 같음)
  • querySelector 의 첫번째 인자로 selector 를 전달하여 확인
  • selector 사용 방법 : 요소(”div”) / id(”#tweetList”) / class(”.tweet”)

querySelector

  • 클래스 이름이 tweet 인 HTML 요소중 첫번째 요소를 조회함
const oneTweet = document.querySelector('.tweet');  // 변수에 할당된 요소가 하나임
  • 여러개의 요소를 한번에 가져 오려면? ⇒ querySelectorAll
const tweets = document.querySelectorAll('.tweet')  // 변수에 할당된 요소가 여러개

// 조회한 여러개의 요소들을 배열처럼(배열X) for문을 사용할 수 있음
// 유사배열, 배열형 객체라고 표현함 (Array-like Object)

요소를 조회(READ)하는 다른 방식들

  • getElementById / 오래된 방식, 이전 버전 브라우저 호환성 고려시 사용할 수도 있음
const getOneTweet = document.getElementById('container')
const queryOneTweet = document.querySelector('#container')
console.log(getOneTweet === queryOneTweet) // true (실제 동작, 접근하는 대상이 동일함)

UPDATE

  • 자 이제 요소는 추가했는데 요소 안에 내용(속성), id, class 는 어떻게 넣을까?
  • textContent, classList 라는 메서드를 활용
// 우선 div 요소를 하나 만들고 변수에 할당
const oneDiv = document.createElement('div')
console.log(oneDiv) // <div></div>

// 기존에 생성한 빈 div 태그에 문자열(텍스트) 입력(추가)
oneDiv.textContent = 'dev';  // textContent 를 사용해서 빈 div 요소에 문자열을 입력
console.log(oneDiv) // <div>dev</div>

// div 요소에 class를 추가
oneDiv.classList.add('tweet')
console.log(oneDiv) // <div class = "tweet">dev</div>

// container의 자식 요소가 되도록 추가(넣기)
const container = document.querySelector('#container');
container.append(oneDiv)

요소(엘리먼트)에 다른 속성을 추가하려면?

  • setAttribute() : 선택한 요소의 속성 값을 정한다
  • 사용법과 예시
element.setAttribute('attribuename', 'attributevalue')

// attributename 에는 속성 이름을 넣는다
// attributevalue 에는 속성값을 넣는다
document.querySelector('h2').setAttribute('title', 'This is title');

// h2 요소를 찾아서 title 속성을 만들고 그 값은 This is title 을 넣어줘
// 참고 : 만약 이미 속성값이 존재하는 경우 그 값을 지우고 새 값을 적용하게 됨
  • 활용과 의문사항
    • querySelectorAll 을 사용해서 해당 요소에 모두 어떤 속성을 추가해주고 싶어서 다음과 같이 해봤음
// 클래스가 tweet인 요소를 모두 찾아줘
const setTitle = document.querySelectorAll('.tweet')

// 조회되는 객체의 형태 확인 (NodeList DOM 컬렉션이라고 함)
console.log(setTitle);
console.log(typeof setTitle); // object
Array.isArray(setTitle); // false 배열이 아니고 유사배열

// 예시1) 그 요소 각각에게(배열같은 것의 각 아이템들) title 속성을 만들고 그 값은 This is title 을 넣어줘
for (let item of setTitle) {
    item.setAttribute('title', 'This is title');
}

// 예시2) 그 요소 각각에게 test 라는 클래스를 추가해줘 (배열 요소 순회 for of 활용))
for (let item of setTitle) {
    item.classList.add('test');
}

// 예시3) 배열 요소 순회를 위해 반복문의 알반 형태 활용
for (let i = 0; i < setTitle.length; i++) {
    setTitle[i].classList.add('test2');
}

// 예시4) for 반복문을 forEach()로 바꿔서 적용해보기
setTitle.forEach((item) => item.classList.add('test3'));  // NodeList는 forEach 메서드는 있지만

// setTitle.map((item) => item.classList.add('test4')) // map, filter 메서드는 없어서 다른방식으로 접근해야함

DELETE - (1) 삭제하려는 요소의 위치를 아는 경우

  • remove() 메서드 사용
const container = document.querySelector('#container');
const tweetDiv = document.createElement('div');

container.append(tweetDiv);
tweetDiv.remove() // append 했던 요소를 삭제

// h2 요소를 지워줘
document.querySelector('h2').remove();

DELETE - (2) 여러 개의 자식 요소를 지우는 경우

  • innerHTML 사용
    • 다만, 보안 측면에서 문제를 가지고 있다고 함

    • 참고 : innterHTML 사용 주의해야 하는 이유 : https://til-devsong.tistory.com/m/101

      // id가 container인 요소의 모든 자식 요소를 지우는 경우
      
      document.querySelector('#container').innerHTML = '';
  • removeChild
    • 자식 요소를 지정해서 삭제
    • 모든 자식 요소를 삭제하려면 반복문 활용
    const container = document.querySelector('#container');
    
    // container 에 첫번째 자식 요소가 있으면 container의 첫번째 자식 요소를 삭제해줘
    while (container.firstChild) {
    	container.removeChild(container.firstChild)
    }
    
    // container 하위에 있는 모든 자식 요소들이 모두 날라가버림
  • 혼동되는 부분
    - 삭제하려는 노드가 아니라 해당 노드의 부모 노드에서 실행됨??
    - 따라서 메서드 전달인자로 삭제할 자식 노드를 넘기고, 부모 노드의 메서드로 호출??
    • 특이사항
      • remove() 메서드와 달리 removeChild()효과는 부모-자식 관계를 끊어버림으로써 DOM 트리를 해제하는 거라고 함
      • 따라서 removeChild() 는 삭제한 노드값을 반환하며, 이를 변수에 담아서 다른 DOM 위치에 붙일 수도 있다고 함
      • 참고 : https://blogpack.tistory.com/683

DELETE - (3) 여러 개의 자식 요소를 지울때 조건 주기

  • 위에서 h2 요소까지 전부 지워지므로
  • 조건을 줘서 이를 방지할 수 있다
    - 자식 요소가 담고 있는 문자열을 비교해서 h2 요소만 남게 하거나
    - 새로운 변수를 생성해서 h2 요소를 할당해뒀다가 반복문 종료후 추가하는 방법
    - 자식 요소를 하나만 남게 할 수도 있음
    // container 의 자식 요소가 1개만 남을 때까지, 마지막 자식 요소 제거를 반복
    
    const container = document.querySelector('#container');
    while (container.children.length > 1) {
    	container.removeChild(container.lastChild);
    }
    // 직접 클래스 이름이 tweet 인 요소만 찾아서 지우는 방법
    
    const tweets = document.querySelectorAll('.tweet');
    tweets.forEach(function(tweet) {
    	tweet.remove();
    }
    
    // or
    
    for (let tweet of tweets) {
    	tweet.remove()
    }

추가공부

append 와 appendChild 차이

innerHTML, innerText,textContent 차이

element 와 node 차이

parentNode와 parentElement 차이, children과 childNodes 차이

createDocumentFragment를 활용한 효율적인 DOM 제어

remove 와 removeChild 차이

offsetTop 좌표정보, offsetWidth 크기정보 조회

profile
느리지만 꾸준하게. 부족하거나 잘못된 부분은 알려주시면 감사하겠습니다.

0개의 댓글