들어가기에 앞서..

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개의 댓글

    Powered by GraphCDN, the GraphQL CDN