[230411] DOM | 이벤트

윤지수·2023년 4월 11일
0
post-thumbnail

오늘의 꿀팁

💡 레퍼런스 체크: 전 회사에 전화해보는 과정 -> 깽판 치고 나오면 안된다!

💡 처음 자기소개할 때 자격요건에 있는 내용 포함해서 말하기

🪄 DOM

DOM 제어

  • JavaScript 문자열을 사용해 element, text 노드를 생성하거나 추가
    • node.textContent
      노드의 텍스트 콘텐츠를 표현한다. 콘텐츠를 단순히 텍스트로만 다룬다.
    • element.innerHTML
      요소 내에 포함된 HTML 마크업을 가져오거나 설정한다.
      즁요한 기능은 innerHTML로 값을 할당할 때, 마크업으로 변환할 수 있는 문자열이 있다면 마크업으로 만들어 보여준다.
    • htmlElement.innerText
      요소의 렌더링된 텍스트 콘텐츠를 나타낸다. 텍스트 내에 문법적으로 처리(HTML, CSS)가 가능한 텍스트가 있으면 처리가 끝난 결과물을 텍스트로 전달한다.

💡 innerHTML 사용시 주의 사항

사이트의 공격 경로가 되어 잠재적인 보안 위험이 발생할 수 있다.

name = "<script>alert('I am John in an annoying alert!')</script>";
el.innerHTML = name; // harmless in this case

cross-site scripting 공격처럼 보일 수 있지만 결과는 무해하다. HTML5는 innerHTML과 함께 삽입된 <script> 태그가 실행되지 않도록 지정한다.

그러나 <script> 요소를 사용하지 않고 자바스크립트를 실행하는 방법이 있으므로 innerHTML을 사용하여 제어할 수 없는 문자열을 설정할 때마다 여전히 보안위험이 있다.

const name = "<img src='x' onerror='alert(1)'>";
el.innerHTML = name; // shows the alert

∴ 사용자에게 입력받을 때는 textContent를 사용해야 한다.

https://developer.mozilla.org/ko/docs/Web/API/Element/innerHTML#security_considerations

  • 속성 제어
    • 요소의 스타일을 제어하는 style 객체
target.style.color = "red";
target.style.fontWeight = "bold";
target.style.color = null; // 현재 스타일 정보를 제거(초기화)

style 객체의 속성 식별자 규칙

  • 속성 이름이 한 글자라면 그대로 사용한다 (height, color …)
  • 속성 이름이 대쉬(-) 를 통해 여러 단어로 나눠져있는 경우는 카멜케이스로 사용한다 (background-image ⇒  backgroundImage)
  • float 속성의 경우 이미 자바스크립트의 예약어로 존재하기 때문에 cssFloat으로 사용한다

💡 style 객체를 통해 설정된 스타일은 CSS inline 스타일과 동일한 가중치를 가진다. 따라서 CSS를 통해 수정의 여지가 있는 스타일에는 많이 사용되지 않는다. 이 경우에는 classList를 이용한 클래스 제어가 더 효과적이다.

    • 속성에 접근하고 수정할 수 있는 Attribute 메소드
      • element.getAttribute(attributeName)
      • element.setAttribute(attributeName, value)

    • 요소에 데이터를 저장하도록 도와주는 data 속성과 dataset 객체
      - data-* 속성을 사용하면 HTML 요소에 추가적인 정보를 저장하여 마치 프로그램 가능한 객체처럼 사용할 수 있게 한다. 단, data 속성의 이름에는 콜론(:)이나 영문 대문자가 들어가서는 안된다.
      - dataset 객체를 통해 data 속성을 가져오기 위해서는 속성 이름의 data- 뒷 부분을 사용한다(대시들은 camelCase로 변환됨)
<img class="terran battle-cruiser" 
  src="battle-cruiser.png"
  data-ship-id="324"
  data-weapons="laser"
  data-health="400"
  data-mana="250"
  data-skill="yamato-cannon"/>
<script>
	console.log(target.dataset);		// DOMStringMap
	console.log(target.dataset.shipId);	// 324
</script>
  • 더 인접한 곳으로 정밀하게 배치
    • element.insertAdjacentHTML('beforebegin', text)
    • element.insertAdjacentHTML('afterbegin', text)
    • element.insertAdjacentHTML('beforeend', text)
    • element.insertAdjacentHTML('afterend', text)

  • DOM 안에서 노드 탐색
    • element.firstElementChild
    • element.lastElementChild
    • element.nextElementSibling
    • element.previousElementSibling
    • node.nextSibling
    • node.previousSibling
    • element.children
    • element.parentElement
    • element.closest('selector') : 일치하는 CSS 선택자를 찾을 때까지 자기 자신부터 시작해 위쪽으로 순회한다

🪄 이벤트

이벤트 객체

이벤트에서 호출되는 핸들러에는 이벤트와 관련된 모든 정보를 가지고 있는 매개변수가 전송되는데 이것이 바로 이벤트 객체다

const btnFirst = document.querySelector('.btn-first');
btnFirst.addEventListener('click', (event) => {
    console.log(event);
});

이벤트 흐름
(이미지 출처 - 멋쟁이사자처럼 프론트엔드스쿨 5기 교안)

브라우저 화면에서 이벤트가 발생하면 브라우저는 가장 먼저 이벤트 대상을 찾기 시작한다.
브라우저가 이벤트 대상을 찾아갈 때는 가장 상위의 window 객체부터 document, body 순으로 DOM 트리를 따라 내려간다. 이를 캡처링 단계라고 한다. 이때 이벤트 대상을 찾아가는 과정에서 브라우저는 중간에 만나는 모든 캡처링 이벤트 리스너를 실행시킨다.
이벤트 대상을 찾고 캡처링이 끝나면 이제 다시 DOM 트리를 따라 올라가며 만나는 모든 버블링 이벤트 리스너를 실행한다. 이를 버블링 단계라고 한다.
그리고 이러한 과정에서 이벤트 리스너가 차례로 실행되는 것을 이벤트 전파(event propagation)라고 한다.

이벤트 위임

target 속성에는 이벤트가 발생한 진원지의 정보가 담겨 있다. target 속성을 통해 이벤트 리스너가 없는 요소의 이벤트가 발생했을 때도 해당 요소에 접근 할 수 있다.
currentTarget 속성에는 이벤트 리스너가 연결된 요소가 참조되어 있다.

<article class="parent">
  <ol>
  <li><button class="btn-first" type="button">버튼1</button></li>
    <li><button type="button">버튼2</button></li>
      <li><button type="button">버튼3</button></li>
  </ol>
</article>

<script>
  const parent = document.querySelector('.parent');
  parent.addEventListener('click', function (event) {
    console.log(event.target);
    console.log(event.currentTarget);
  
    if (event.target.nodeName === "BUTTON") {
      event.target.innerText = "버튼4";
    }
  });
</script>

=> 이벤트 리스너가 없어도 마치 리스너가 있는 것처럼 사용할 수 있다. 이벤트 하나만으로도 자식 요소들을 이벤트 처리할 수 있다.

0개의 댓글