TIL)09 JS 자바스크립트 DOM 2

이명진·2021년 2월 26일
0
post-thumbnail

들어가기에 앞서..

JS 자바스크립트 DOM 2 입니다. DOM 첫 게시물은 이전글에서 볼 수 있습니다.

오늘은 무엇을 배울까 ?

DOM 조작 (nodevalue,nodeName, nodeType)
(className,classList,id,.hasAttribute.getAttribute.setAttribute.removeAttribute,textContent,innerText,innerHTML)
(createElement,createTextNode,appendChild,removeChild,insertAdjacentHTML)

DOM 조작

텍스트 노드 접근/수정

요소의 텍스트는 텍스트에 저장되어 있다.
텍스트 노드에 접근 과 수정 방법은 아래와 같다.

  • 해당 텍스트 노드의 부모 노드를 선택한다. 텍스트 노드는 요소 노드의 자식이다.
  • firstChild 프로퍼티를 사용하여 텍스트 노드를 탐색한다.
  • 텍스트 노드의 유일한 프로퍼티(nodeValue)를 이용하여 텍스트를 취득한다.
  • nodeValue를 이용하여 텍스트를 수정한다.
1. 해당 텍스트 노드의 부모 요소 노드를 선택한다.
const one = document.getElementById('one');
console.dir(one); // HTMLLIElement: li#one.red

// nodeName, nodeType을 통해 노드의 정보를 취득할 수 있다.
console.log(one.nodeName); // LI
console.log(one.nodeType); // 1: Element node

2. firstChild 프로퍼티를 사용하여 텍스트 노드를 탐색한다.
const textNode = one.firstChild;

// nodeName, nodeType을 통해 노드의 정보를 취득할 수 있다.
console.log(textNode.nodeName); // #text
console.log(textNode.nodeType); // 3: Text node

3. nodeValue 프로퍼티를 사용하여 노드의 값을 취득한다.
console.log(textNode.nodeValue); // Seoul

4. nodeValue 프로퍼티를 이용하여 텍스트를 수정한다.
textNode.nodeValue = 'Pusan';

nodevalue

  • 노드의 값을 반환한다.
  • Return: 텍스트 노드의 경우는 문자열, 요소 노드의 경우 null 반환

nodeName, nodeType을 통해 노드의 정보를 취득할 수 있다.
값말고 노드의 타입과 노드의 종류 를 알수 있다.

어트리뷰트 노드 접근/수정

className

  • class 어트리뷰트의 값을 취득 또는 변경한다.
  • class 어트리뷰트가 존재하지 않으면 class 어트리뷰트를 생성하고 지정된 값을 설정한다.
  • class 어트리뷰트의 값이 여러 개일 경우, 공백으로 구분된 문자열이 반환되므로 String 메소드 split(' ')를 사용하여 배열로 변경하여 사용한다.
const elems = document.querySelectorAll('li');

[...elems].forEach(elem => {
  // class 어트리뷰트 값을 취득하여 확인
  if (elem.className === 'red') {
    // class 어트리뷰트 값을 변경한다.
    elem.className = 'blue';
  }
});

어트리뷰 값을 바로 변경이 가능하다 .

classList

  • add, remove, item, toggle, contains, replace 메소드를 제공한다.
[...elems].forEach(elem => {
  // class 어트리뷰트 값 확인
  if (elem.classList.contains('blue')) {
    // class 어트리뷰트 값 변경한다.
    elem.classList.replace('blue', 'red');
  }
});

메소드를 이용하여 확인하고 변경을 한다. (contains, replace)

id

  • id 어트리뷰트의 값을 취득 또는 변경한다.
  • id 어트리뷰트가 존재하지 않으면 id 어트리뷰트를 생성하고 지정된 값을 설정한다.

.hasAttribute(attribute)
지정한 어트리뷰트를 가지고 있는지 검사한다.
Return : Boolean

.getAttribute(attribute)
어트리뷰트의 값을 취득한다.
Return : 문자열

.setAttribute(attribute, value)
어트리뷰트와 어트리뷰트 값을 설정한다.
Return : undefined

.removeAttribute(attribute)
지정한 어트리뷰트를 제거한다.
Return : undefined

HTML 콘텐츠 조작

마크업이 포함된 콘텐츠를 추가하는 행위는 크로스 스크립팅 공격(XSS: Cross-Site Scripting Attacks)에 취약하므로 주의가 필요하다.

마크업이란 ?
마크업 언어는 "마크(Mark)"로 둘러싸인 언어이다. "태그(Tag)"로 둘러싸였다고도 표현한다.

출처: https://blog.cordelia273.space/15 [세상의 모든 지식]

출처: https://blog.cordelia273.space/15 [세상의 모든 지식]

textContent
요소의 텍스트 콘텐츠를 취득 또는 변경한다. 이때 마크업은 무시된다.
textContent를 통해 요소에 새로운 텍스트를 할당하면 텍스트를 변경할 수 있다.
이때 마크업을 포함시키면 문자열로 인식되어 그대로 출력된다.

// 요소의 마크업이 포함된 콘텐츠로 변경하면.
  one.textContent = '<h1>Heading</h1>';

  // 마크업이 문자열로 표시된다.
  console.log(one.textContent); // <h1>Heading</h1>

작은 따옴표를 활용하여 요소를 추가한다. 추가할때 마크업은 안적어도 된다.

innerText
innerText 프로퍼티를 사용하여도 요소의 텍스트 콘텐츠에만 접근할 수 있다. 하지만 아래의 이유로 사용하지 않는 것이 좋다.

  • CSS에 순종적이다. 예를 들어 CSS에 의해 비표시(visibility: hidden;)로 지정되어 있다면 텍스트가 반환되지 않는다.
  • CSS를 고려해야 하므로 textContent 프로퍼티보다 느리다

innerHTML
해당 요소의 모든 자식 요소를 포함하는 모든 콘텐츠를 하나의 문자열로 취득할 수 있다.
이 문자열은 마크업을 포함한다.

const one = document.getElementById('one');

// 마크업이 포함된 콘텐츠 취득
console.log(one.innerHTML); // Seoul

// 마크업이 포함된 콘텐츠 변경
one.innerHTML += '<em class="blue">, Korea</em>';

// 마크업이 포함된 콘텐츠 취득
console.log(one.innerHTML); // Seoul <em class="blue">, Korea</em>

위와 같이 마크업이 포함된 콘텐츠를 추가하는 것은 크로스 스크립팅 공격(XSS: Cross-Site Scripting Attacks)에 취약하다.
크로스 스크립팅 공격은 다음에 알아보도록한다.

DOM 조작 방식

innerHTML 프로퍼티를 사용하지 않고 새로운 콘텐츠를 추가할 수 있는 방법은 DOM을 직접 조작하는 것이다. 한 개의 요소를 추가하는 경우 사용한다.

이 방법은 다음의 수순에 따라 진행한다.

  • 요소 노드 생성 createElement() 메소드를 사용하여 새로운 요소 노드를 생성한다. 메소드의 인자로 태그 이름을 전달한다.
  • 텍스트 노드 생성 createTextNode() 메소드를 사용하여 새로운 텍스트 노드를 생성한다. 경우에 따라 생략될 수 있지만 생략하는 경우, 콘텐츠가 비어 있는 요소가 된다.
  • 생성된 요소를 DOM에 추가 appendChild() 메소드를 사용하여 생성된 노드를 DOM tree에 추가한다. 또는 removeChild() 메소드를 사용하여 DOM tree에서 노드를 삭제할 수도 있다.
  • createElement(tagName)
    태그이름을 인자로 전달하여 요소를 생성한다.
    Return: HTMLElement를 상속받은 객체

    createTextNode(text)
    텍스트를 인자로 전달하여 텍스트 노드를 생성한다.
    Return: Text 객체

    appendChild(Node)
    인자로 전달한 노드를 마지막 자식 요소로 DOM 트리에 추가한다.
    Return: 추가한 노드

    removeChild(Node)
    인자로 전달한 노드를 DOM 트리에 제거한다.
    Return: 추가한 노드

    insertAdjacentHTML(position, string)
    인자로 전달한 텍스트를 HTML로 파싱하고 그 결과로 생성된 노드를 DOM 트리의 지정된 위치에 삽입한다. 첫번째 인자는 삽입 위치, 두번째 인자는 삽입할 요소를 표현한 문자열이다. 첫번째 인자로 올 수 있는 값은 아래와 같다.

    • ‘beforebegin’ - 앞에서 앞
    • ‘afterbegin’ - 앞에서 뒤
    • ‘beforeend’ - 뒤에서 앞
    • ‘afterend’ -뒤에서 뒤

    순서

    --beforebegin -- 
    <p>
    -- afterbegin--
    내용
    --beforeend--
    </p>
    --afterend--
    

    결론

    innerHTML

    장점

    • DOM 조작 방식에 비해 빠르고 간편하다.
    • 간편하게 문자열로 정의한 여러 요소를 DOM에 추가할 수 있다.
    • 콘텐츠를 취득할 수 있다.
      단점
    • XSS공격에 취약점으로 입력받은 콘텐츠(untrusted data: 댓글, 사용자 이름 등)를 추가할 때 주의하여야 한다.
    • 해당 요소의 내용을 덮어 쓴다. 즉, HTML을 다시 파싱한다. 이것은 비효율적이다.

    DOM 조작 방식

    장점

    • 특정 노드 한 개(노드, 텍스트, 데이터 등)를 DOM에 추가할 때 적합하다

      단점

    • innerHTML보다 느리고 더 많은 코드가 필요하다.

    insertAdjacentHTML()

    장점

    • 간편하게 문자열로 정의된 여러 요소를 DOM에 추가할 수 있다.

    • 삽입되는 위치를 선정할 수 있다.

      단점

    • XSS공격에 취약점이 있기 때문에 사용자로 부터 입력받은 콘텐츠(untrusted data: 댓글, 사용자 이름 등)를 추가할 때 주의하여야 한다.

      innerHTML과 insertAdjacentHTML()은 크로스 스크립팅 공격(XSS: Cross-Site Scripting Attacks)에 취약하다.텍스트를 추가 또는 변경시에는 textContent, 새로운 요소의 추가 또는 삭제시에는 DOM 조작 방식을 사용하도록 한다.

    profile
    프론트엔드 개발자 초보에서 고수까지!

    0개의 댓글