개발이군고구마

[JS] 이벤트 핸들러 방식과 this(DOM의 attribute/property) 본문

FRONT

[JS] 이벤트 핸들러 방식과 this(DOM의 attribute/property)

김구황 2024. 10. 26. 17:05
728x90

1. 문제상황

ajax
	.. 받아온 결과값data 
    html(data);

 

[현재코드]

바닥 페이지에 빈 요소 노드 (=태그) 를 만들어 놓고 (레이어 페이지 처럼 동작하게끔)

비동기 통신으로 가져온 data(=html) 의 값을 jqeury html 메서드로 데이터 값을 넣

 

[문제상황]

해당 레이어가 닫힌 후에 "다시 통신" 할때, 프로퍼티 방식 (스크립트 태그 내) 으로 선언한 함수가 동작하지 않음

 

 

[시도해본 방법]

  • 새로 data를 가져올 때 DOM에 대한 파싱을 하지 않고 기존에 DOM을 가져오는 건 아닐까 하여, document.ready 에 있는 메서드를 밖으로 빼봄 
    • jsp는 react 처럼 가상 돔을 비교하지 않는다.
    • 새로 데이터를 불러왔기 때문에 DOM을 처음부터 끝까지 다시 그리기 때문에 상관 없음
  • js의 캐싱 문제인 줄 알고 ajax 선언시에 cache를 false로 선언함

 

[원인]

  • 스크립트 태그 안에 있는 js는 브라우저 캐싱이 있어서 다시 호출한다고 해도 새로 갱신되지 않음
  • jqeury html 메서드가 기존에 있던 태그들을 지우지 않기 때문에
  • 매번 호출할 때마다 바닥 페이지에 빈 요소 노드에 태그들이 "쌓임"
  • 프로퍼티 방식으로 선언된 이벤트는 매핑된 DOM 요소에 이벤트를 주기 때문에 이전 js는 그때 만들어진 이전 DOM 요소를 가르키고 있음 
  • 따라서 새로 불러온 html 요소 노드에 이벤트가 먹지 않고 있었던 것 
이전에, querySelectorAll 메서드를 사용해
새롭게 생성한 팝업 DOM 에 접근했을 때 메서드가 안먹는 현상이 있었음 (원인은 querySelectorAll이 갱신이 안됨)
-> 팝업 DOM 에 직접 이벤트를 주는 방식 (=프로퍼티 방식) 으로 해결한 적이 있었음

* 해결 방법은 다르지만, 팝업 레이어가 쌓이고 있었던 원인은 동일함*

 

 

[아래의 개념에 대한 이해부족]

  • jqeury의 html 메서드가 작동하는 방식 (=>기존 요소 노드의 값을 재갱신하는지에 대한 여부)
    • html 메서드는 기존 내용을 삭제하고 새로운 html이 집어넣어짐 
    • 하지만 제대로 작동하지 않았던 것은, 브라우저에서 html을 캐싱한 것 같음 
    • append 의 경우엔 기존의 내용을 유지한채로 html 집어넣음 
  • 이벤트 핸들러 등록
  • 이벤트 핸들러가 가르키는 this

 

 

2. DOM의 어트리뷰트와 프로퍼티의 상관관계 

1) 어트리뷰트

  • HTML 요소의 초기 상태를 지정. HTML 어트리뷰트 값은 HTML 요소의 초기 상태를 의미하며 변하지 않음. 
  • 언제나 문자열 (예, checked 어트리뷰트의 값은 문자열) 

 

2) 프로퍼티 

  • 사용자가 입력한 최신상태는 HTML 어트리뷰트에 대응하는 요소 노드의 DOM 프로퍼티가 관리 
  • 사용자의 입력에 의한 상태 변화에 반응하여 언제나 최신 상태 유지 
  • 문자열이 아닐 수도 있음 (예, checked의 프로퍼티 값은 boolean)

 

3. 이벤트 핸들러 등록방식 

1) 이벤트 핸들러 어트리뷰트 방식(*작동했던 이벤트 핸들러)

<button onclick="sayHi('Lee')"> Click me!</button>

<script>
	function sayHi(name) {
    	console.log(`Hi!${name}`);
    }
</script>
  • 여기서 function sayHi 내부의 this는 전역 객체 window
    •  일반 함수로 호출되는 방식이기 때문에, 전역객체를 가르킴 
  • 다만 인수로 전달한 this의 경우 해당 이벤트를 바인딩한 DOM 요소를 가리킴 

 

 

2) 이벤트 핸들러 프로퍼티 방식 (*작동하지 않았던 이벤트 핸들러)

<button> Click me!</button>

<script>
   const $button = document.querySelector('button');
    
    $button.onclick = function() {
    	console.log("button click");
    }
</script>
  • 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가르킴 (=button)

 

 

 

3) addEventListener 방식 

<button> Click me!</button>

<script>
   const $button = document.querySelector('button');
    
    $button.addEventListener('click', function() {
    	console.log("button click");
    })
</script>

이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가르킴 (=button)