Lsiron

Java Script -DOM 객체 (feat. Elice) 본문

언어/Java Script

Java Script -DOM 객체 (feat. Elice)

Lsiron 2024. 5. 8. 00:01

DOM에서 사용되는 CRUD 메소드

=> document 객체의 다음 메소드들을 사용해서 HTML 요소들을 조작할 수 있다.

  • CREATE: createElement, append, appendChild
  • READ: querySelector, querySelectorAll, getElementById, getElementByClassName
  • UPDATE: textContent, id, classList, setAttribute
  • DELETE: remove, removeChild, innerHTML="", textContent=""

DOM 생성 (CREATE)

1. document.createElement()

작성한 태그 명의 HTML 요소를 생성하여 반환하며, 태그를 생성할때는 createElement 사용한다. 

노드요소 뿐만아니라 빈 텍스트도 매개변수로 받을 수 있다.

Document.createElement() 메소드는 지정한 tagName의 HTML 요소를 만들어 반환한다.

document.createElement('div')
<div>​</div>


//자바스크립트에서 어떤 작업의 결과를 담으려면?
//변수를 선언하고 어떤 작업의 결과를 변수에 할당
//여기서는 div element를 tweetDiv에 할당

const tweetDiv = document.createElement('div')

2. child.append(parent)

String도 추가 가능하다. 여러 개를 한 번에 추가할 수 있으며, 반환 값이 없다.

현재 노드(child)를 특정 부모 노드(parent)의 마지막 자식 다음으로 삽입한다.

append와 appendChild 모두 부모 노드에 자식 노드를 추가하는 메소드이다.

한번에 여러 매개변수를 넣을 수 있어서 appndChild보다 범용적이다.

append 메소드는 노드객체(Node object)나 DOMString(text)를 사용할 수 있다. 또한 한번에 여러 개의 자식 요소를 설정할 수 있다.

// NodeObect 삽입
const parent = document.createElement('div');
const child = document.createElement('p');

parent.append(child);

// <div><p></p></div>
 
// DOMString 삽입
const parent = document.createElement('div');

parent.append('DOMString 삽입');

// <div>DOMString 삽입</div>

3. child.appendChild(parent)

String은 추가할 수 없고 하나의 Node만 추가한다. 여러 개를 추가하면 가장 먼저 들어오는 인자 하나만 추가된다.

현재 노드(child)를 특정 부모 노드(parent)의 마지막 자식 다음으로 삽입한다.

append와 appendChild 모두 부모 노드에 자식 노드를 추가하는 메소드이다.

한번에 하나만 매개변수를 받고, appendChild 메소드는 오직 Node 객체만 받을 수 있다. 한번에 오직 하나의 노드만 추가할 수 있다. - 현업에서 주로 사용

// NodeObect 삽입
const parent = document.createElement('div');
const child = document.createElement('p');

parent.appendChild(child);

// <div><p></p></div>
 
// DOMString 삽입
const parent = document.createElement('div');

parent.appendChild('DOMString 삽입'); ==> 에러발생!!!

 

이외에도 아래와 같은 추가 방법이 있다.

• 요소.prepend() : 선택된 요소의 첫번째 자식요소로 추가
• 요소.before() : 선택된 요소의 앞에 있는 형제요소로 추가
• 요소.after() : 선택된 요소의 바로 뒤인 형제요소로 추가

★ DOM 선택 (READ)

0. 유사배열

'유사배열' 단어가 많이 나오는데, 이는 배열이 아닌 객체이다.

객체지만 length 프로퍼티를 가진다. key 값이 0,1,2,... 순으로 숫자로 이루어져 있다.

ex) { 0: "hello", 1: "world", length:2} ==> length를 제외한 모든것은 객체상태로 키와 값으로 나타난다.

유사배열은 배열이 아니기 때문에 배열의 메소드를 가지고 있지 않으며, array.from 메소드를 사용해 배열로 변환해줄 수 있다. 

유사배열을 이해하는 것과 유사배열을 어떻게 배열로 변환하는지 아는게 중요 !

=> array.from()  // ex)

const array = document.getElementsByClassName("array")
array.from(array)

 

1. 아이디(Id)값 찾기

- getElementById()

<div id="content">
    <p class="txt_red">안녕하세요</p>
    <p>반갑습니다.</p>
    <span class="txt_red">Hello world</span>
 </div>
 
 <script>
    var Content = document.getElementById('content');
    // id가 content인 요소를 가져온다.
 </script>

2. 클래스(Class)값 찾기

- getElementsByClassName()

 : 가져온 값은 HTML Collection 객체(유사배열) 로 가져온다. (리스트나 반복되는 영역에서 해당 명령어를 사용할 때 특정 값을 지칭하려면 소괄호 뒤에 [index값]을 붙인다.), 값을 찾지 못할경우 null을 반환한다.

<div id="content">
    <p class="txt_red">안녕하세요</p>
    <p>반갑습니다.</p>
    <span class="txt_red">Hello world</span>
 </div>
 
 <script>
    var textRed = document.getElementsByClassName('txt_red');
    // class가 txt_red인 요소를 HTMLCollection 배열로 가져온다.
   
    console.log(textRed[0]);
    // <p class="txt_red">안녕하세요</p>
 </script>

3. 태그(Tag) 값 찾기

- getElementsByTagName()

 : 가져온 값은 HTML Collection 객체(유사배열) 로 가져온다. (리스트나 반복되는 영역에서 해당 명령어를 사용할 때 특정 값을 지칭하려면 소괄호 뒤에 [index값]을 붙인다.)

<div id="content">
    <p class="txt_red">안녕하세요</p>
    <p>반갑습니다.</p>
    <span class="txt_red">Hello world</span>
 </div>
 
 <script>
    var tag_P = document.getElementsByTagName('p');
    // document에서 p태그 요소를 HTMLCollection 배열로 가져온다.
   
    console.log(tag_P[1]);
    // <p>반갑습니다.</p>
 </script>

 

4. querySelector()

원하는 요소를 아이디(#), 클래스(.), 태그 값을 입력해서 하나만 찾는다.

(리스트나 반복되는 영역에서 해당 명령어를 사용하게 되면 가장 첫번째로 있는 DOM 요소를 찾는다.)

<div id="wrap">
  <ul>
    <li>리스트 1</li>
    <li>리스트 2</li>
    <li>리스트 3</li>
  </ul>
</div>

<script>
  var wrapper = document.querySelector('#wrap');
  var lists = wrapper.querySelector('li');
 
  console.log(wrapper);  // <div id="wrap"> 영역을 찾는다.
  console.log(lists);  // #wrap 하위에 있는 첫 번째 li를 찾는다.
</script>

5. querySelectorAll()

원하는 요소를 아이디(#), 클래스(.), 태그 값을 입력해서 여러 요소들을 Nodelist (유사배열)의 형태로 가져온다. (리스트나 반복되는 영역에서 해당 명령어를 사용하게 되면 DOM 요소를 전부 가져온다)

<div id="wrap">
  <ul>
    <li>리스트 1</li>
    <li>리스트 2</li>
    <li>리스트 3</li>
  </ul>
</div>

<script>
  var wrapper = document.querySelector('#wrap');
  var lists = wrapper.querySelectorAll('li');
 
  console.log(wrapper);  // <div id="wrap"> 영역을 찾는다.
  console.log(lists);  // #wrap 하위에 있는 모든 li를 유사 배열 형태로 가져온다.
 
  // lists → [<li>리스트 1</li>, <li>리스트 2</li>, <li>리스트 3</li>]
</script>

 

★ DOM 추가 (UPDATE)

1. classList.~

선택 요소에 class를 더하거나, 뺴거나, 클래스가 존재하는지 체크하는 메소드

• 요소.classList.add() : 클래스 추가
• 요소.lassList.remove() : 클래스 삭제
• 요소.classList.contains() : 해당 클래스가 요소에 포함되어 있는지 아닌지 boolean값으로 반환
• 요소.classList.toggle()

// HTML 요소 내용 읽고 쓰기
const text = document.getElementById('text');
console.log(text);

text.classList.add('title'); //클래스 추가
// text.classList.remove('title'); // css 적용된거 사라짐
text.classList.toggle('title-big');
console.log(text.classList.contains('title-big'));

cf. style.~

style 속성을 사용하는 경우는 [TAG].style.backgroundColor 와 같은 식으로 접근 가능.

주의해야 할 점은 스타일의 속성은 항상 카멜 케이스로 접근해서 사용해야 함.

인라인 속성으로 들어가기 때문에 주의해야함.

document.getElementById(id).style.property="새 스타일";

2. Node. textContent  / Node.innerText / Node. innerHTML

태그 사이에 문자열을 담아준다.

텍스트를 변경할땐 innerHTML 쓰는것은 권장하지 않음(XSS 공격에 취약). textContent , innerText를 쓸것 => 보안에 안전함. cf) XSS (Cross-site Scripting) : 악성 자바스크립트 코드를 삽입해 민감한 정보를 탈취

 
<div id='content'>
    안녕~
    <span style='display:none'>innerText는 나를 볼 수 없어</span>
  </div>
 
<script>
console.log(content.innerHTML);
// html 전체를 다 가져옴

// 안녕~
// <span style='display:none'>innerText는 나를 볼 수 없어</span>

-----------------------------------------------------
 
console.log(content.innerText);
// 사용자에게 보여지는 텍스트만 가져옴
// 숨겨진 텍스트는 사용자에게 보여지지 않기 때문에 안녕~만 가져옴

// 안녕~

-----------------------------------------------------
 
console.log(content.textContent);
// 숨겨진 텍스트까지 포함해서 텍스트값을 모두 다 가져옴

// 안녕~
// innerText는 나를 볼 수 없어
</script>

 

textContent => 태그는 무시하고 글자만 따옴, 실전에선 이것을 주로 사용

// text라는 아이디를 가진 element를 content라는 변수에 담는다
const content = document.getElementById('text')

// content에 담겨있는 <div id="text">Hello World</div>의 내용 변경
 
content.textContent = '<span style="color:red;">  안녕하세요</span>'

//결과 => <span style="color:red;">안녕하세요</span>

innerHTML => 태그포함 텍스트를 전부 따온다, 보안에 취약하다.

// html 코드와 함께 작성 가능
document.documentElement.innerHTML = "<p>innerHTML</p>"
// 스타일 적용
document.documentElement.innerHTML =
  "<span style='color:blue'>innerHTML</span>"

// 이런 식으로 빈 문자열을 넣으면 body의 전체 내용을 지울 수 있다.
document.body.innerHTML = "";

 

innerText => 숨겨진 텍스트는 무시하고, 보이는 텍스트만을 처리함.

// innerHTML과 달리 text값만 다루기 때문에 html태그 사용 불가능
document.documentElement.innerText = "innerText"

// html태그를 넣으면 태그도 text값으로 인식하고
// <p>innerText</p> 문자열 그대로 적용함.
document.documentElement.innerText = "<p>innerText</p>"
 

innerHTML과 innerText 비교
const innerT = document.getElementById('innerT');
innerT.innerText = "<div style='color:red'>innerText</div>";
console.log(innerT)
// 스타일 적용되지 않은 기본 폰트로 <div style='color:red'>innerText</div> 출력

const innerH = document.getElementById('innerH');
innerH.innerHTML = "<div style='color:red'>innerHTML</div>";
console.log(innerH)
// 스타일 적용된 빨간색 폰트로 innerHTML 출력
 

3. setAttribute("html 요소 속성명","지정할 속성")

선택한 요소의 속성 값을 직접 지정할 수 있는 메소드이다.

//setAttribute : html 요소 속성 추가
const link = document.getElementById('link'); //여기선 속성이 없음
link.setAttribute('href', 'https://www.naver.com/');
const img = document.getElementById('image');
img.setAttribute('src', 'img.jpg');
img.setAttribute('width', '200');
const input = document.getElementById('input');
input.setAttribute('placeholder', '이름을 입력하세요.');

 

★ DOM 제거 (DELETE)

1. Element.remove() 

간단하게 Element요소에서. romove 메서드를 통해 요소를 제거할 수 있다.

<div>
    <h1>제목 1</h1>
    <h1>제목 2</h1>
    <h1>제목 3</h1>
  </div>
const newel = document.querySelectorAll('h1');
const pos = document.querySelector('div');
pos.remove();

결과값은 모두 삭제된 것으로 출력된다.

2. Node.removeChild()

특정 위치에서 요소들을 제거하는 방법이다. appendChild와 사용방법은 동일하다.

<div>
    <h1>제목 1</h1>
    <h1>제목 2</h1>
    <h1>제목 3</h1>
  </div>
const newel = document.querySelectorAll('h1');
const pos = document.querySelector('div');
pos.removeChild(newel[2]);

 

결과값은 제목3이 삭제된 것으로 출력된다.

★ 이벤트 핸들러

이벤트는 click, dblclick, focus, blur 등 여러 종류가 있다.

//추가
addEventListener('이벤트', 발생할 함수)

.addEventListner('keyup', () => {

             console.log(event.key);

});

//삭제

removeEventListener('이벤트', 발생할 함수)

인자가 addEventListener와 일치해야함



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

const newel = document.querySelectorAll('h1');
const pos = document.querySelector('div');
pos.removeChild(newel[2]);

 

★ preventDefault

event.preventDefault를 사용하여, 이벤트의 기본 동작을 막을 수 있다. 

예를 들어 <a> 태그의 경우 페이지 이동이 기본 행동인데 이를 막을 수 있는 셈이다.

preventDefault는 브라우저가 기본 동작을 계속하지 못하게 막고, stopPropagation은 다른 이벤트 핸들러가 동일한 이벤트 처리를 하지 못하도록 한다 (버블링을 막아준다). 

<a href="https://www.naver.com" id="link">네이버</a>
<script>
    document.querySelector('#link').addEventListener('click', function(e){
        e.preventDefault();
    });
    // a 태그 클릭 시 preventDefault를 사용했기 때문에 링크값이 있어도 이동하지 않는다.
</script>

★. Tips 

1. html collection 은 면접에 안 나온다

2. 시간복잡도는 O(logn) 이다.  {} = 해쉬테이블의 시간복잡도는 O(1) => 대기업 면접질문

해시테이블(HashTable) : 해시 테이블은 key-value pair로 데이터를 저장하는 자료구조 중 하나로, 빠르게 데이터를 검색할 수 있는 자료구조

3. skipnavi.querySelector(".skip) =  document.querySelector("#skipnavi.skip")

4. NodeList의 특징은 중요하지 않음, 요소가 결과 값으로 NodeList 타입의 유사배열을 반환할때 이 유사배열이 중요함.

5. 트리는 탐색에 있어서 종류는 2개

6. dfs(depth first search) vs bfs (breath first search)

한 우물 전략 = dfs, 레벨별로 훑는것 = bfs  ,보통 코테는 이진트리로 나옴 => 면접에 안 나옴

7. 면접에 이벤트는 무조건 나옴  - 캡처링, 버블링, 이벤트위임

캡쳐링과 버블링은 이벤트가 아니다. 

이벤트가 이뤄지는 과정이 세단계로 나눠져있음 캡쳐링 - 이벤트 발생태그 도달 - 버블링, 위임(보통 캡쳐링에서 많이 사용)

캡쳐링은 내려가는 것 , 이벤트발생태그 도달은 상호작용하는 것 , 버블링은 올라가는 것

8. +on 이벤트 이름 => 현실에서 사용하지 않음 ex) on click , on change

const ul = document.querySelector("#ul");
const list = Array.from(ul.querySelectorAll(".li"));

console.dir(ul);
console.dir(list);

ul.addEventListener(
  "click",
  () => {
    console.log("부모 - 버블링");
  },
  false
);
ul.addEventListener(
  "click",
  () => {
    console.log("부모 - 캡쳐링");
  },
  true
);

list.forEach((li) => {
    li.addEventListener("click", (event) => {
      event.target.classList.toggle("bg-pink");
    console.log(event.target.textContent);
  });
});

event.target 에서 target은 li를 가리킴 

이때 부모와 list 의 console이 같이 실행되는데(ex. 부모 / list) 이것은 캡쳐링에 의해 내려올때 ul 또한 같이 찍히기 때문

// 이는 같은 이벤트 일 때만 같이 찍힘. 만약 ul에 onchange 라면 onclick만 실행되고 onchange는 무시함

또한 부모와 list 의 console이 같이 실행될때 (ex. list / 부모) 이것은 버블링에 의해 올라갈때 ul 또한 같이 찍히기 때문

이것을 방지하는것이 stopPropagation() 메소드임. => 내려갈때 또는 올라갈때 실행되는것을 잘라줌