TIL 14. Java Script - DOM

신미영·2021년 4월 21일
0

Java Script

목록 보기
8/17

자바스크립트는 웹 문서 안에 있는 텍스트, 이미지, 표 등 모든 요소를 객체화시켜 조작 할 수 있다. 이를 문서 객체 모델, DOM(Document Object Model)이라고 한다. 웹 문서를 DOM으로 해석하여 웹 문서 안의 모든 요소를 제어할 수 있는 방법을 정리해 보려고 한다.



DOM 트리

DOM을 조작하기 위해서는 문서의 구조를 먼저 파악해야 한다. 웹 문서의 구조는 나무처럼 생겼다. 부모 요소에서 가지를 뻗어 자식요소와 연결 된 것으로 이해하면 쉽다. 더불어 웹 문서의 구조를 명확히 알고 있어야 자바스크립트로 원하는 요소에 접근하고자 할 때 정리가 쉽다.

  • body, h1, 'contents' 등 웹 문서 안에 있는 요소나 속성을 '노드(Node)'라고 한다.
  • 노드는 태그 노드와 텍스트 노드, 속성 노드 그리고 주석 노드가 있다.
  • bodyh1, p는 부모 노드와 자식 노드의 관계이다.
  • h1, p 태그 노드 안의 텍스트 노드('Title', 'Contents')는 해당 요소의 자식 노드이다.
  • 태그 노드의 속성은 모두 해당 태그 노드의 자식 노드 이다.


DOM 요소 접근

DOM요소에 접근하여 자바스크립트를 활용하고자 할 때 CSS에서 사용했던 선택자(Selector)를 활용할 수 있다.

<body>
  <h1 id="heading">제목</h1>
  <p>
    글을 쓸 때 강조하고 싶은 내용이 있다면 
    <span class="accent">다양한 방법</span>을 사용할 수 있다. 
    먼저 <span class="accent">폰트의 두께를 두껍게</span> 만드는 방법도 있고, 
    <span class="accent">글씨체를 두껍게</span> 설정할 수도 있다.
  </p>
</body>

getElementById()

h1 태그에 접근하고자 할 때 아래와 같이 id 속성으로 접근할 수 있다.

document.getElementById("heading")  // id="heading" 인 요소에 접근

위와 같이 접근 후 함수를 활용하여 접근한 요소에만 함수가 적용되게 할 수 있다.

document.getElementById("heading").onclick = function() {
  this.stlye.color = "red"  // 클릭 시 h1의 폰트 컬러를 "red"로 변경
}

getElementsByClassName()

id 선택자를 활용하여 요소에 접근한 것과 유사한 방식으로 class 선택자로도 요소에 접근할 수 있다.

document.getElementsByClassName("accent")  // class="accent" 인 요소에 접근

위와 같이 class 요소로 접근할 경우 여러개의 요소들에 동시에 접근 되어 해당하는 요소들이 배열의 형태로 접근 된다. 즉, Array[index]를 통해 원하는 요소에만 접근 할 수 있다는 것이다. 'accent'를 class로 갖는 요소를 출력하면 아래와 같다.

console.log(document.getElementsByClassName("accent"));

[span.accent, span.accent, span.accent]
0: <span class="accent">다양한 방법</span>
1: <span class="accent">폰트의 두께를 두껍게</span>
2: <span class="accent">글씨체를 두껍게</span>

class 전체에 밑줄을 긋고 첫 번째 요소만 폰트 사이즈를 4em으로 변경하고자 한다면 아래와 같이 작성하면 된다.

document.getElementsByClassName("accent").style.textDecoration = "underline";
document.getElementsByClassName("accent")[0].style.fontsize = "4em";

getElementsByTagName()

id나 class가 없는 경우 tag로 접근이 가능하며 id, class 선택자로 접근한 것과 동일하게 해당 요소의 변경 등이 가능하다.

document.getElementsByTagName("p").style.backgroundColor = "gray";
// <p> 요소에 접근하여 배경 컬러 'gray'로 변경

querySelector()

선택자에 관계없이 동일한 함수를 사용하여 DOM요소를 찾을 수 있는 것이 querySelector()이다. 다만 선택자를 입력할 때 class는 '.', id는 '#'을 붙여 구분하여야 한다. 또한 class 선택자 처럼 같은 선택자를 가진 요소가 많다면 querySelectorAll()을 사용하면 된다.

document.querySelector("p")  // p태그 요소에 접근
document.querySelector("#heading")  // id="heading" 요소에 접근
document.querySelecortAll(".accent")  // class="accent"인 '모든' 요소에 접근

** getElement~()함수와 querySelector()함수의 차이

쓰임새는 같지만 접근이 가능한 범위가 다르다. getElement~()함수는 요소 노드까지만 접근이 가능하고 querySelector() 함수는 요소, 텍스트, 속성 노드까지 접근이 가능하다.



DOM 요소의 속성 접근

DOM 요소의 속성 노드에 접근하여 속성값을 가져오거나 수정하는 함수로 요소 뿐만 아니라 속성도 활용 할 수 있다.

<div id="main-img">
  <img src="images/fall-image.jpg" alt="가을 풍경 이미지">
</div>

getAttribute()

속성 값을 변경하기 위해 먼저 속성값을 가져올 때 사용하는 함수이다.

document.querySelector('#main-img > img').getAttribute("src")  
// id="main-img" 내의 img 태그 요소를 선택하여 "src"속성을 가져옴
// "images/fall-image.jpg"이 결과값이 됨

setAttribute()

속성 값을 변경하는 함수이다.

document.querySelector('#main-img > img').setAttribute("src","images/summer-image.jpg")  
// id="main-img" 내의 img 태그 요소를 선택하여 "src"속의 값을 "images/summer-image.jpg"으로 변경


이벤트 처리

DOM에서 이벤트를 연결하는 방법엔 세 가지가 있다.

HTML 태그에 연결

<div>
  <img id="origin-pic" src="images/origin-pic.jpg" alt="" onclick="change()">  
  <!----이미지 클릭 시 change 함수 실행---->
</div>

<script>
  let pic = document.querySelector('#pic');
  function change() {
    pic.src = "images/change-pic.jpg";  // 이미지 경로 변경
  }
</script>

DOM 요소에 연결

<div>
  <img id="origin-pic" src="images/origin-pic.jpg" alt="">  
</div>

<script>
  let pic = document.querySelector('#pic');
  pic.onclick = change;
  
  function change() {
    pic.src = "images/change-pic.jpg";  // 이미지 경로 변경
  }
</script>

addEventListener() 함수 사용

HTML 태그와 DOM 요소에 이벤트를 연결할 경우 한 요소에 한 이벤트만 연결할 수 있다는 단점을 보완 할 수 있는 함수이다.

DOM.addEventListener("type", event, capturing)
  • type: 'click', 'mouseover', 'mouseout'처럼 이벤트를 발생시킬 유형을 지정한다.
  • evnet: 실행해야 할 명령을 나열하거나 함수 이름을 지정한다.
  • capturing: 이벤트 캡처링 여부를 지정하는 것으로 캡처링(true)면 DOM의 부모 노드에서 자식 노드로 이벤트가 전달되는 것이고, 버블링(false)면 그 반대로 이벤트가 전달 되는 것이다. 기본값은 버블링(false)이다.
<div>
  <img id="origin-pic" src="images/origin-pic.jpg" alt="">  
</div>

<script>
  let pic = document.querySelector('#pic');
  pic.addEventListener("click", changePic, false);
  pic.addEventListener("click", changeStyle, false);
  // 클릭 시 changePic과 changeStyle 2개의 함수 실행 
  // pic.onclick = changePic, pic.onclick = changeStyle 로 함수 지정 시 하나의 이벤트 함수만 실행 
  
  function changePic() {
    pic.src = "images/change-pic.jpg";  // 이미지 경로 변경
  }
  
  function changeStyle() {
    pic.style.border = 5px solid #ccc;
  }
 </script>


DOM에 요소 추가

온라인 쇼핑몰 등에서 상품 옵션(수량, 사이즈 등)을 선택하면 그 내용이 화면 아래에 표시 되는 것처럼 DOM으로 웹 문서 상에 없던 요소를 추가해서 화면에 표시할 수 있다.

새로운 노드 추가

  • createElement() : 새로운 요소 노드 생성
  • createTextNode() : 텍스트가 있을 경우 텍스트 노드 생성
  • appendChild() : 텍스트 노드를 요소 노드에 자식 노드로 추가
  • createAttribute() : 요소에 속성이 있을 경우 속성 노드 생성
  • setAttributeNode() : 속성 노드를 요소 노드에 연결
  • appendChild() : 새로 만든 요소 노드를 부모 노드에 추가

새로운 노드를 추가 할 때는 노드의 생성 뿐만 아니라 부모-자식 노드의 연결도 필요하다.
예를 들어 body 태그 안에 다음과 같은 요소, 텍스트, 속성을 추가한다면 아래와 같이 작성할 수 있다.

<h1 id="heading">문서 객체 모델</h1>
<script>
  var newP = document.createElement("p")  // p 요소 노드 생성
  var newText = document.createTextNode("문서 객체 모델")  // 텍스트 노드 생성 
  var newId = document.createAttribute("id")  // id 속성 노드 생성
  newId.value = "heading"  // id 속성노드의 값 지정 
  
  document.body.appendChild(newP)  // body의 자식노드로 p요소 노드 추가 
  newP.appendChild(newText)  // p요소 노드의 자식노드로 텍스트 노드 추가
  newP.setAttributeNode(newId)  // p요소 노드의 자식노드로 id속성 노드 추가
</script>

노드 변경

:: 자식노드 확인

특정 노드에 자식 노드가 있는지 확인하는 함수이다. 자식 노드가 있으면 true, 없으면 false를 반환한다.

document.querySelectorAll("div")[1].hasChildNodes()
// 노드리스트 중 2번 째 div 요소노드에 자식노드가 있는지 확인 

:: 자식노드 접근

childNodes는 자식 노드에 접근하는 함수인데 이때 요소 노드 뿐만 아니라 태그와 태그 사이의 줄바꿈도 빈 텍스트 노드인 자식 노드로 인식하여 NodeList를 만든다. children을 사용하면 요소 노드만 가져와 HTMLCollection이라는 자료형을 만든다.

<div id="userList">
  <p>AAA</p>
  <p>BBB</p>   
  <p>CCC</p>
</div>
<script>
  document.querySelector('#userList').childNodes
  // NodeList(7) [text, p, text, p, text, p, text]
  // <div> 다음의 줄바꿈, <p>태그 사이의 줄바꿈, </div> 앞의 줄 바꿈을 노드로 인식 
  document.querySelector('userList').children
  // HTMLCollection(3) [p, p, p]
</script>

** 노드리스트 접근
여러개의 노드를 한꺼번에 가져와 배열형식에 여러 값을 저장하듯 여러 노드가 하나의 변수에 저장되는 것을 말한다. 노드 리스트는 특정 위치의 노드에 접근하기 위해 인덱스 값과 함께 많이 쓰인다.

document.querySelectorAll("div")
// NodeList(3) [div, div, div]
document.querySelectorAll("div")[1]
// 노드리스트 중 2번 째 div 값에 접근한다. 

:: 노드 삽입

appendChild()함수는 부모 노드에 자식 노드가 있을 경우 새로운 노드를 마지막 노드로 추가한다. 하지만 insertBefore() 함수는 자식 노드를 추가할 기준 노드를 지정하고 그 앞에 자식 노드를 추가한다.

<div id="userList">
  <p>AAA</p>
  <p>BBB</p>   
  <p>CCC</p>
</div>
<script>
  let userList = document.querySelector('#userList')
  userList.inserBefore(userList.children[2], userList.children[1])
  // userList의 3번째 자식 요소를 2번째 자식 요소 앞에 추가
  // userList가 ['AAA', 'CCC', 'BBB']로 변경 됨
</script>

:: 노드 삭제

removeChild() 함수를 실행하면 자식노드를 삭제 할 수 있다. 이 때, 노드는 스스로 삭제할 수 없기 때문에 부모 노드에 접근해서 삭제해야 한다. 혹시 부모 요소가 무엇인지 모른다면 먼저 parentNode속성으로 부모 노드를 찾을 수 있다.

부모 노드 찾기

<div id="userList">
  <p>AAA</p>
  <p>BBB</p>   
  <p>CCC</p>
</div>
<script>
  document.querySelectorAll('p')[0].parentNode
  // p요소는 div요소가 부모 요소라는 것을 알 수 있다.
</script>

노드 삭제

<div id="userList">
  <p>AAA</p>
  <p>BBB</p>   
  <p>CCC</p>
</div>
<script>
  const del1 = document.querySelectorAll('p')[0]  // 첫 번째 p요소 
  const userList = document.querySelector('#userList')
  userList.removeChild(del1)  // div요소에 있는 첫 번째 p요소 삭제 후 삭제 된 요소 반환
</script>
profile
Hello World!

0개의 댓글