frontend/javascript&web

[Web] 순수 자바스크립트로 양방향 데이터 바인딩 구현(Pure Javascript Two-way Data binding) - 추가작업(이벤트 재할당)

NERD는 한글로 류호진 2023. 6. 13. 12:42

오늘은 지난번에 진행했던 양방향 데이터 바인딩 구현을 이어서 진행해보려고 합니다. 지난번의 작업중 이어서 할 작업은 DOM변경에 대한 이벤트 재할당 기능을 추가하려고 합니다. 이 작업은 아주 쉬운 방법으로 추가할 수 있습니다.

 

1. DOM 초기화 로직 세분화

 

아래는 기존의 initializeDOM 함수입니다. 해당 소스는 DOM을 최초로 초기화 하는 작업이 추가 되어 있습니다. 하지만 아래 작업의 내용을 DOM이 변경 된 이후 이벤트 재할당 과정이 필요하기 때문에 DOM초기화 로직을 분리 시켜야됩니다.

   initializeDOM() {
      const bindings = Array.from(this.$el.querySelectorAll("[b-model]"));
      bindings.forEach((element) => {
         const key = element.getAttribute("b-model");
         this.updateElement(element, this.$data[key]);
         if (element.tagName == "INPUT" || element.tagName == "TEXTAREA") {
            if (element.type != "radio" && element.type != "checkbox") {
               element.addEventListener("input", (e) => {
                  this.$data[key] = e.target.value;
               });
            } else {
               element.addEventListener("click", (e) => {
                  this.$data[key] = e.target.value;
               });
            }
         }
      });
   }

아래와 같이 bindElements를 분리 하여 DOM 변경을 감지하여 변경된 DOM에도 해당 내용이 추가 될 수 있도록 진행을 하여야 됩니다.

   initializeDOM() {
      this.bindElements(this.$el.querySelectorAll("[b-model]"));
   }

   bindElements(elements) {
      elements.forEach((element) => {
         const key = element.getAttribute("b-model");
         this.updateElement(element, this.$data[key]);
         if (element.tagName == "INPUT" || element.tagName == "TEXTAREA") {
            if (element.type != "radio" && element.type != "checkbox") {
               element.addEventListener("input", (e) => {
                  this.$data[key] = e.target.value;
               });
            } else {
               element.addEventListener("click", (e) => {
                  this.$data[key] = e.target.value;
               });
            }
         }
      });
   }

 

2. DOM 변경 감지 및 재할당

DOM이 변경되는 것을 감지하기 위해서는 MutationObserver라는 객체를 이용해야 됩니다. 해당 객체를 선언하면 DOM변경을 감지할 수 있고 변경된 DOM의 후작업으로 어떤 내용을 할 것인지 정의할 수 있습니다.

   observeDOM() {
      const observer = new MutationObserver((mutationsList, observer) => {
         for(let mutation of mutationsList) {
            if (mutation.type === 'childList') {
               this.bindElements(mutation.target.querySelectorAll("[b-model]"));
            }
         }
      });

      observer.observe(this.$el, { childList: true, subtree: true });
   }

MutationObserver로 변경된 DOM을 감지하고 해당 DOM에 b-model이라는 어트리뷰트들을 bindElements에 넘겨 호출하면 위에서 분리해놓은 이벤트 할당 부분이 적용이 됩니다.

 

이까지 이벤트 재할당까지 작업하고 추가적으로 가상 DOM을 구현해 보아야 겠다고 생각을 했는데 그렇게 생각을 해보니 그런 방식이면 vue cdn방식을 써도 되지 않나 라는 생각이 들어 고민 중에 있습니다. 앞으로도 지속적으로 발전시켜 나갈 계획이지만 방향성에 대해선 조금 더 생각해보아야 될 것 같다고 생각합니다.

반응형