게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌24 - HTML&DOM - 6년 전 등록 / 4년 전 수정

MutationObserver

안녕하세요. 이번 시간에는 DOM의 재밌는 기능 중 하나인 MutationObserver 객체를 소개합니다! DOM 요소(태그같은 것)에 발생하는 변경사항을 감지할 수 있습니다. IE11부터 지원됩니다. 바로 코드를 보시죠.

<body>
  <div id="zerocho-changeable"></div>
  <button id="attributes">attributes</div>
  <button id="childList">childList</div>
</body>

먼저 html 태그입니다. 버튼들을 누르면 div 태그에 변경이 생기고, MutationObserver 객체가 나중에 변경된 내용을 기록할 것입니다. 스크립트도 같이 보시

var target = document.getElementById('zerocho-changeable');

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation);
  });
});

var config = {
  attributes: true,
  childList: true,
  characterData: true,
  subtree: true || null,
  attributeOldValue: true || null,
  characterDataOldValue: true || null,
}; // 감시할 내용 설정
observer.observe(target, config); // 감시할 대상 등록

document.getElementById('attributes').addEventListener('click', function() {
  target.setAttribute('class', 'zerocho-newclass'); // 대상에 변경 발생
});

document.getElementById('childList').addEventListener('click', function() {
  target.textContent = 'zerocho'; // 대상에 변경 발생
});

MutationObserver 생성자에서 새로운 옵저버(스타크래프트의 옵저버와 스펠링이 같습니다)를 만들어냅니다. observe라는 메서드가 있는 객체들은 감시자 역할로, 감시하는 대상에 변경사항이 발생할 때마다 미리 정해둔 동작을 수행합니다. observe 메서드에 첫 번째 인자로 감시할 대상을, 두 번째 인자로 어떤 것을 감시할 지에 대한 옵션을 넣어주면 됩니다.

옵션들을 잠깐 살펴볼까요? attributes는 태그의 속성(id, class, value와 같은)이 변경되는 것을 감지합니다. 추가적으로 attributeOldValue가 true면 변경전 속성값도 보여줘서 유용합니다. 위에 예제에는 넣지 않았지만 attributeFilter도 있는데 ['class']같은 값(배열 형식이어야 합니다)을 주면 class 속성 변경만 감시합니다. childList 속성은 태그의 자식 태그들이 변경되는지를 추적하고, characterData는 태그의 텍스트 데이터가 변경되는지(characterDataOldValue는 변경전 데이터도 보여주겠죠? 단, childList 속성과 겹치기 때문에 chidList를 false로 해야 characterData가 기록됩니다.)를, subtree는 감시 대상의 자식 태그에 변경이 일어나도 변경점을 기록해줍니다.

콘솔에 찍히는 결과는 다음과 같은 객체입니다. 어떤 부분이 변경되었는지 자세하게 알려줍니다.

MutationRecords = {
  addedNodes: [], // 추가된 자식 노드,
  attributeName: null, // 변경된 속성명
  attributeNamespace: null, // 변경된 속성네임스페이스
  nextSibling: null, // 다음 형제 태그
  previousSibling: null, // 이전 형제 태그
  oldValue: null, // 변경전 값 
  removedNodes: [], // 제거된 자식 노드 
  target: Element, // 대상 태그 
  type: 'attributes' || 'childList' || 'characterData' // 어떤 종류가 변경되었는지
}

예를 들어 attributes 버튼을 누르면 다음과 같이 기록됩니다.

{
  attributesName: 'class',
  target: div#zerocho-changeable.zerocho-newclass,
  type: 'attributes',
  // 나머지는 기본값
}

마지막으로 옵저버의 disconnect 메서드를 사용해서 감시를 중단할 수 있습니다. 중단 후에 언제든지 다시 observe 메서드로 감시를 재개할 수 있습니다.

observer.disconnect(); // 감시 중지

옵저버 객체들은 활용 방법이 무궁무진합니다. 예를 들어, 특정 태그에 클래스가 변경되거나, 어떠한 자식 태그가 추가되었을 때 미리 지정한 동작을 하게 할 수 있습니다. CSS를 바꿀 수도 있고, setTimeout으로 몇 초 뒤에 추가적인 행동을 수행하게 할 수도 있고, 이벤트 리스너같은 용도로 사용할 수 있을 것 같습니다.

단, 지나친 남용은 옵저버간의 연쇄 작용(서로가 서로를 감시해 하나가 바뀌었을 때 연달아서 모든 게 바뀌어버림)을 심화시켜 디버깅을 매우 어렵게만들 수 있습니다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

2개의 댓글이 있습니다.
3년 전
안녕하세요 제로초님 동일하게 작업해보니

해당 위의 코드중에
mutations.forEach(function(mutation) {
console.log(mutation);
});


이 부분은 타갯노드가 똑같은게 여러개 들어오던데 저는 어트리뷰터 감지만 적용을했구요..

왜 굳이 동일한 타갯노드가 여러개 들어오는지 궁금합니다.
6년 전
옵저버간의 연쇄 작용 부분에서 질문있습니다, 서로의 변화를 감지할 경우 무한 루프에 빠질 수도 있나요? 그럴 경우가 있을 것 같은데 예외처리가 가능한가요?
6년 전
네 맞습니다. 그래서 전파받은 것을 다시 전파할 때 추가적인 데이터(클래스나 data attribute를 넣어 확인하거나, observe를 끊음)를 넣어 재전파를 막습니다.