교육 : 자바스크립트 기초 (오후)

호밀빵 굽는 쿼카·2022년 1월 25일
0

NHN Cloud 인턴

목록 보기
15/48

Todo 추가하기

DOM 전체에서 엘리먼트 찾기

document.getElementById('myId');  //returns HTMLElement or null
document.getElementsByTagName('div'); //returns HTMLCollection
document.getElementsByClassName('myClass'); //returns HTMLCollection

document

  • 브라우저상의 HTML 문서를 모델링한 객체
  • DOM API의 시작점

HTMLCollection

  • 유사 배열: Array 비슷하게 사용가능하지만 Array가 아님(Array-like Object)
    - 숫자로 인덱싱 가능, length 존재
    - Array가 아니라서 Array의 API를 사용할 수 없음
    - Array의 API를 사용하려면 Array로 변환한 뒤 사용해야함
  • live 한 컬렉션이다.

엘리먼트안의 엘리먼트 찾기

HTML 엘리먼트는 다른 엘리먼트를 포함할 수 있다.(DOM은 트리구조로 모델링됨)

element.getElementsByClassName('myClass');
element.getElementsByTagName('div');

특정 엘리먼트의 자식 엘리먼트를 검색해 검색의 범위를 좁힐 수 있다.

var myContentsEl = document.getElementById('myContents');
myContentsEl.getElementByTagName('A'); // myContentsEl 하위 엘리먼트중에서 검색

엘리먼트에 이벤트 리스너 적용

element.addEventListener("click", function() {
  // Your code's here
}, false);

이벤트 리스너 안에서의 this 는 이벤트가 적용된 엘리먼트(이벤트 리스너가 화살표 함수인 경우는 이벤트 리스너 생성 당시의 this임)

동적으로 엘리먼트 만들기

document.createElement(tagName)

var newDiv = document.createElement("div");
var newP = document.createElement("p");

document.createTextNode(text)

var newText = document.createTextNode("텍스트 노드");
var newText2 = document.createTextNode("HELLO WORLD");

엘리먼트에 자식 엘리먼트 추가하기

element.appendChild(node)

var newDiv = document.createElement("div");
var newP = document.createElement("p");
var newText = document.createTextNode("HELLO ROOKIES");

newP.appendChild(newText);
newDiv.appendChild(newP);

document.body.appendChild(newDiv);

결과)

<body>
  <div>
    <p>HELLO ROOKIES</p>
  </div>
</body>

Console에서 결과 확인)


document.body.childNodes[0].tagName == 'DIV';
document.body.childNodes[0].childNodes[0].tagName == 'P';
document.body.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'HELLO ROOKIES';

자식엘리먼트 삭제하기

element.removeChild(node)

var newDiv = document.createElement("div");
var newP = document.createElement("p");
var newText = document.createTextNode("HELLO ROOKIES");

newP.appendChild(newText);
newDiv.appendChild(newP);

document.body.appendChild(newDiv); // Body에 추가했지만,
document.body.removeChild(newDiv); // 바로 삭제됨.

innerHTML 이용해 동적으로 엘리먼트 만들기

element.innerHTML = '<div>text</div>';

HTML 텍스트를 이용해 자식 노드를 생성

document.body.innerHTML = '<div><p>HELLO ROOKIES</p></div>';

결과)

<body>
  <div>
    <p>HELLO ROOKIES</p>
  </div>
</body>

장점)

  • 새로운 엘리먼트들을 만드는 상황에서는 보통 제일 빠름.
  • 정적 언어로 컴파일된 자바 스크립트 엔진 내부에서 생성해줌.
  • DOM API를 이용하는것보다 편한 경우가 많다.

단점)

  • 엘리먼트에 작은 변화를 주는 경우 비효율적임.
  • 엘리먼트 하위 DOM Tree를 모두 지우고 다시 만들어야 함.
  • 낮은 버전의 IE에서 상호 참조로 인한 메모리 누수 발생할 수 있다.

주의할점)
innerHTML값이 세팅 될때마다 해당 노드의 모든 자식 엘리먼트를 지우고 다시 만들기 때문에 Addition assginment(+=) 연산자를 직접 사용하는것을 피해야 한다.

// Bad (X)
div.innerHTML = '<p>text1</p>';
    // 자식으로 <p>text1</p> 을 만든다.
div.innerHTML += '<p>text2</p>';
    // innerHTML === '<p>text1</p><p>text2</p>'
    // 지금까지의 DOM Tree를 지우고 <p>text1</p> 부터 다시 만들고 <p>text2</p>도 만든다.

// Good (O)
var content = '';
// HTML 스트링을 미리 만든다.
content += '<p>text1</p>'; // for문 같은 반복문에서 사용된다고 가정할 수 있음.
content += '<p>text2</p>';

div.innerHTML = content; // innerHTML 할당은 한 번만 일어남.

textContent

innerHTML과 비슷하지만 텍스트 노드를 생성하거나 참조할 수 있다. 모든 자식 엘리먼트의 텍스트 노드를 확인할 수 있다.

element.textContent = 'new text content';
console.log(element.textContent);

이벤트의 전파

<body>
  <ul>
    <li><input type="checkbox" /> TODO</li>
  </ul>
</body>

이벤트는 특정한 방향으로 전파된다

  • 위에서 아래로
    위에서 아래로 => Capturing
    body -> ul -> li -> input

  • 아래에서 위로
    아래에서 위로 => Bubbling
    input -> li -> ul -> body

순서: 캡처링 -> 실제 대상 엘리먼트 -> 버블링

addEventListener()의 세번째 인자로 캡처링/버블링 이벤트를 선택할 수 있다.=> true 면 캡처링 활성화
이벤트 리스너에 첫번째 인자로 넘어오는 Event 객체로 전파를 차단할 수 있다.

var useCapturing = true;

element.addEventListener('click', function(eventObject) {
  eventObject.stopPropagation(); // 캡처링이나 버블링을 취소한다.(이벤트 전파를 차단한다)

  // etc
  eventObject.preventDefault(); // 디폴트 동작을 취소한다.(ex. 링크 이동 차단)
  // 체크 박스의 클릭을 취소하는경우 브라우저마다 다른 동작을 한다.
}, useCapturing);

기본적으로 useCapturing 자리가 false 이므로 버블링임(아래->위)

여기서 잠깐!🖐
stopPropagation이 필요한 이유!
이벤트 전파 (버블링) 되어서 다른 이벤트에 영향을 주게 됨
ex) 자식요소가 부모요소 이벤트에 영향을 주게 됨

Event 객체에는 흐름 제어 외에도 많은 유용한 정보를 포함하고 있다. 그 내용은 이벤트 타입에 따라 조금씩 다르다.

엘리먼트에 css 아이디와 클래스 적용

<style>
  .myClass {
    border: 1px solid #f00;
  }

  #myId {
    padding: 5px;
  }
</style>
// HTML의 class속성과 동일
element.className = 'myClass';

// 다중 적용시 띄어쓰기
element.className = 'myClass1 myClass2';

// 아이디도 동일하게 적용가능(다중 적용 X)
element.id = 'myId';
  • 아이디 는 문서에서 유일한 값으로 특정 엘리먼트와 1:1 매치 되며, 엘리먼트당 한 개의 아이디만 적용 가능하다.
  • 클래스 는 여러 엘리먼트에 적용 가능하고, 각 엘리먼트마다 다중 적용할 수 있다.
  • 디자인 적용은 클래스 를 이용하는것을 추천!
  • 재사용 가능한 코드가 됨.
  • 아이디는 엘리먼트를 찾기 위한 식별 용도로 사용하는것을 추천함.

Todo 카운팅하기

querySelector

document.querySelector('.myClass'); // 처음 찾은 한개만 반환 함.
document.querySelectorAll('.myClass'); // 해당되는 모든 엘리먼트를 찾아서 반환. (Nodelist 타입 - Live Collection이 아님)
element.querySelector(), document.querySelector() 모두 사용가능
  • CSS 셀렉터를 이용해 엘리먼트를 찾는다.
  • jQuery와 비슷
  • 에버그린 브라우저 및 IE8 이상부터 지원

엘리먼트 노드 속성

  • DOM상의 엘리먼트들은 트리 구조로 서로 연결되어 있다.
  • 엘리먼트 노드의 속성을 통해서도 트리 탐색이 가능하다.
// 부모
element.parentNode // 부모 노드

// 형제
element.nextSibling // 다음 형제 노드
element.previousSibling  // 이전 형제 노드

// 자식
element.firstChild // 첫번째 자식 노드
element.lastChild // 마지막 자식 노드
element.childNodes // 자식 노드 모두 담고 있는 HTMLCollection
profile
열심히 굽고 있어요🍞

0개의 댓글