Resize Observer

JJuice·2021년 8월 3일
1

javascript

목록 보기
1/1

ResizeObserver

시작하기에 앞서

와인오디오 3차 리뉴얼 작업-반응형 Navigation 작업 중 Javascript에서 스크린의 width값을 체크하며 특정 width값 이하가 되면 true/false값을 시켜주는 변수가 있었으면 좋겠다는 생각이 들었다. 그래서 바로 구글링을 해보니 resize 이벤트에 대해서 알게되었다.
참조자료를 살펴보니 resize 이벤트는 매우 빈번하게 발생될 수 있는 문제 때문에 아래와 같은 코드를 이용해 이벤트를 throttle?하는 것이 좋다가 나와있었다.

▶throttle 심플한 정의
-throttle : 일정 시간 동안 요청이 한 번만 되도록 수행
-debounce : 요청이 들어오고 일정 시간을 기다린 후 요청을 수행한다. 만약 일정 시간안에 요청이 추가로 들어오면 이전 요청은 취소된다.

//requestAnimationFrame + customEvent
(function() {
    var throttle = function(type, name, obj) {
        obj = obj || window;
        var running = false;
        var func = function() {
            if (running) { return; }
            running = true;
             requestAnimationFrame(function() {
                obj.dispatchEvent(new CustomEvent(name));
                running = false;
            });
        };
        obj.addEventListener(type, func);
    };

    /* init - you can init any event */
    throttle("resize", "optimizedResize");
})();

// handle event
window.addEventListener("optimizedResize", function() {
    console.log("Resource conscious resize callback!");
});

window.requestAnimationFrame() : 브라우저에게 수행하기를 원하는 애니메이션을 알리고 다음 ?리페인트?가 진행되기 전에 해당 애니메이션을 업데이트하는 함수를 호출한다. 이 메소드는 리페인트 이전에 실행할 콜백을 인자로 받습니다.
구글 참조 자료 :
JS Web API로서 CSS의 transition으로 처리하기 어려운 애니메이션이나 HTML5의 canvas,svg등의 애니메이션 구현을 위해서 사용하는 비동기 함수이다.(난이도가 어렵다. 모든 애니메이션을 직접 프레임 단위로 계산해 줘야 한다.)

var el = document.querySelector('#움직일-요소');
var left = 0;

function frame() {
  left += 0.1;
   el.style.setProperty('transform', 'translateX(' + left + 'px)');
   if (left < 200) window.requestAnimationFrame(frame);
}
window.requestAnimationFrame(frame);

위와 같이 어설프게 resize관련 throttle 정보를 알고 넘어가는 것보다 조금 더 resize와 관련되어 용이한 API가 있지 않을까 검색해보니 Resize Observer 키워드를 발견하게 되었다.


Resize Observer 무엇에 쓰이는 물건인고??

설정한 해당 Element의 크기 변화를 관찰한다. 해당 element가 크기 변화가 생기는순간
callBackFn으로 2가지 parameter값을 이용해 여러가지로 활용이 가능한 객체이다.
(추가적으로 크게 변화를 제어할 경우 발생할 수 있는 무한 콜백 루프나 ?순환 종속성?등의 다양한 문에 없이 사용이 가능하다고 한다.)

var resizeObserver = new ResizeObserver( callback( entries, observer ) );
resizeObserver.observe( targetElement );

-해당 Element 의 리사이즈가 일어날때마다 callback 함수를 실행시켜준다.


callbackFn( entries, observer )

entries argument

  • ResizeObserverEntry 인스턴스의 배열이다. 각각의 entry는 다음 속성들을 포함시킨다. >> 해당 target:element를 entries에 넣어주는거 같다.(배열)

  • 만약 getElementById와 같이 하나만 entries에 넣어주면 어떻게 될까? 전혀 문제없이 똑같이 적용된다.

    ▶ ResizeObserverEntry 인스턴스의 속성Key

  • contentRect (legacy) : 관찰 대상의 사각형 정보

  • target (legacy) : 관찰 대상의 요소

  • contentBoxSize : 관찰 대상의 content-box(content) 크기

    • 신기한게 하나의 entry에 배열로 인식한다.
  • borderBoxSize : 관찰 대상의 border-box (content+padding+border) 크기

//예제코드.1
const cont = document.getElementsByClassName("cont");
const box1Cont = document.getElementsByClassName("box1");
const ro = new ResizeObserver((entries, observer) => {
	entries.forEach(entry => {
    		console.log(entry.contentRect.width);
        	console.log(entry.contentBoxSize[0].blockSize);
	})
});
ro.observe(box1Cont[0]);

잠시 헷갈려서 자료를 찾아보았던 box-sizing:content-box or border-box의 차이를 잘 기억하고 있자. [실제 컨텐츠width,height값이 유지되는 것이 무엇인지 깎여들어가는 것이 무엇인지]

observer argument

  • 대상요소와 관련된 메서드를 활용할 수 있다.

▶ 관련 메서드들

  • observe() : 대상 요소의 관찰을 시작한다.
  • unobserve() : 대상 요소의 관찰을 중지한다.
  • disconnet() : ResizeObserver 인스턴스가 관찰하는 모든 요소의 관찰을 중지한다.
//내가 만든 코드
const cont = document.getElementsByClassName("cont");
const box1Cont = document.getElementsByClassName("box1");
const ro = new ResizeObserver((entries, observer) => {
	entries.forEach(entry => {
		console.log(entry.contentRect.width);
		if(entry.contentRect.width < 200)  {
			console.log("disconnect");
			observer.disconnect();
		}

	})
});
ro.observe(box1Cont[0]);
//@juggle/resize-observer 참조자료에서의 코드
// Watch multiple!
import { ResizeObserver } from '@juggle/resize-observer';

const ro = new ResizeObserver((entries, observer) => {
  console.log('Elements resized:', entries.length);
  entries.forEach((entry, index) => {
    const { inlineSize: width, blockSize: height } = entry.contentBoxSize[0];
    console.log(`Element ${index + 1}:`, `${width}x${height}`);
  });
});

const els = document.querySelectorAll('.resizes');
[...els].forEach(el => ro.observe(el)); 


//Watching different box sized
const ro = new ResizeObserver((entries, observer) => {
  console.log('Elements resized:', entries.length);
  entries.forEach((entry, index) => {
    const [size] = entry.borderBoxSize;
    console.log(`Element ${index + 1}:`, `${size.inlineSize}x${size.blockSize}`);
  });
});

// Watch border-box
const observerOptions = {
  box: 'border-box'
};

const els = document.querySelectorAll('.resizes');
[...els].forEach(el => ro.observe(el, observerOptions));

※관련 참조 자료 링크

MDN Web Docs | reisze
MDN Docs | ResizeObserver
Polyfills the ResizeObserver API

profile
코딩초보 JJu의 좌충우돌 Coding Story-JJuice

0개의 댓글