DIV의 치수 변경을 감지하는 방법은 무엇입니까?


351

다음 샘플 HTML을 100 % 너비의 DIV가 있습니다. 일부 요소가 포함되어 있습니다. 창 크기 조정을 수행하는 동안 내부 요소의 위치가 변경되고 div의 크기가 변경 될 수 있습니다. div의 치수 변경 이벤트를 연결할 수 있는지 묻고 있습니까? 어떻게합니까? 현재 콜백 함수를 대상 DIV의 jQuery 크기 조정 이벤트에 바인딩하지만 콘솔 로그가 출력되지 않습니다 (아래 참조).

크기를 조정하기 전에 여기에 이미지 설명을 입력하십시오

<html>
<head>
    <script type="text/javascript" language="javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript" language="javascript">
            $('#test_div').bind('resize', function(){
                console.log('resized');
            });
    </script>
</head>
<body>
    <div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
    </div>
</body>
</html>

7
resize 이벤트를 지정된 div 요소에 바인딩하기 때문에 작동하지 않습니다. 그러나 크기 조정 이벤트는 요소가 아닌 창에 대해 트리거됩니다.
Fatih Acet 2016 년

setInterval가능한 해결책으로 여기서 사용할 수 있습니다. clearInterval작업이 완료되면 언제든지 버튼 클릭에 바인딩 하여 루프를 중지 할 수 있습니다 .
피터 다 미스

1
2020 년부터 ResizeObserver 는 IE를 제외한 모든 주요 브라우저 (Chrome, Safari, Firefox, Edge)에서 작동합니다. caniuse.com/#feat=resizeobserver

답변:


263

요소의 크기가 변경되었는지 확인하는 매우 효율적인 방법이 있습니다.

http://marcj.github.io/css-element-queries/

이 라이브러리에는 ResizeSensor크기 조정 감지에 사용할 수 있는 클래스 가 있습니다.
이벤트 기반 접근 방식을 사용하므로 빠르며 CPU 시간을 낭비하지 않습니다.

예:

new ResizeSensor(jQuery('#divId'), function(){ 
    console.log('content dimension changed');
});

jQuery onresize 플러그인 은 루프에서 setTimeout()DOM clientHeight/ clientWidth속성 을 읽고 변경 사항을 확인 하는 데 사용되므로 사용 하지 마십시오 . 레이아웃 스 래싱을 유발하기 때문에
매우 느리고 부정확 합니다 .

공개 :이 라이브러리와 직접 연결되어 있습니다.


8
@jake, IE11 지원이 구현되었습니다.
Marc J. Schmidt

15
@Aletheios 좀 더 자세히 살펴 봐야합니다. requestAnimationFrame은 느린 차원 감지를위한 것이 아니라 정반대입니다. 실제 이벤트 기반 크기 조정 센서에서 발생하는 극단적 인 수의 이벤트를 모두 처리하여 CPU 시간을 절약합니다. github.com/marcj/css-element-queries/blob/master/src/
Marc J. Schmidt

6
@Aletheios 나는 당신이 요점을 놓친 것 같아요 : setTimeout은 부정확 할뿐만 아니라 지옥만큼 느립니다. 간단한 부울을 확인하는 requestAnimationFrame은 DOM 속성에 대해 항상 확인하는 setTimeout보다 훨씬 빠릅니다. setTimeout 외에도 몇 밀리 초마다 호출됩니다.
Marc J. Schmidt

9
@ Orwellophile 당신은 분명히 아무것도 이해하지 못했습니다. 내부적으로 어떻게 작동하는지 모르는 곳에서 답을 줄이지 마십시오. css-element-query : 차원이 변경 될 때마다 트리거되는 실제 크기 조정 이벤트를 사용합니다. 너무 많은 이벤트 (예 : 드래그 앤 드롭)가 발생하기 때문에 requestAnimationFrame 검사에 간단한 부울 변수를 확인하여 트리거 된 이벤트를 1 / 프레임까지 부드럽게합니다. jquery 플러그인 : 각 검사가 매우 느리지 만 동일한 기능을 갖도록 자주 검사 해야하는 DOM 레이아웃 소품 (clientHeight 등)을 항상 검사하는 setTimeout을 사용합니다.
Marc J. Schmidt

9
@Aletheios, @Orwellophile 및 그들에 의해 오도 된 사람 : requestAnimationFramevs setTimeout는 관련이 없으므로이 라이브러리 는 반복되지 않습니다 . requestAnimationFrame콜백 호출 빈도를 디 바운스 / 스로틀하는 데에만 사용되며 폴링하지 않습니다 . MutationObserver는 이론적으로 유사한 효과에 사용될 수 있지만 이전 브라우저에서는 그렇지 않습니다. 이것은 매우 영리합니다.
한 서울 –

250

이에 대한 새로운 표준은 Chrome 64에서 사용 가능한 크기 조정 관찰자 API입니다.

function outputsize() {
 width.value = textbox.offsetWidth
 height.value = textbox.offsetHeight
}
outputsize()

new ResizeObserver(outputsize).observe(textbox)
Width: <output id="width">0</output><br>
Height: <output id="height">0</output><br>
<textarea id="textbox">Resize me</textarea><br>

관찰자 크기 조정

사양 : https://wicg.github.io/ResizeObserver

폴리 필 : https://github.com/WICG/ResizeObserver/issues/3

Firefox 문제 : https://bugzil.la/1272409

사파리 문제 : http://wkb.ug/157743

현재 지원 : http://caniuse.com/#feat=resizeobserver


3
현재 Chrome 만 지원하므로 프로덕션 사이트에는 아직 유용하지 않습니다. 그러나 여기에 가장 좋은 해결책입니다! btw, 다음은 구현 상태에 대한 간략한 개요입니다. chromestatus.com/feature/5705346022637568
Philipp

8
@Philipp 폴리 필이 있습니다.
Daniel Herr

2
아직 모든 브라우저에서의 실험적인 기능 것 같다 caniuse.com/#feat=resizeobserver
Francesc 로사에게

5
이 답변 후 2 년이 지났지 만 브라우저 지원은
어둡습니다

2
최신 Chrome 및 FF의 매력처럼 작동합니다.
Klemen Tušar

32

일반 html 요소가 아닌 객체 에서 resize이벤트 를 바인딩해야합니다 window.

그런 다음 이것을 사용할 수 있습니다 :

$(window).resize(function() {
    ...
});

및 콜백 함수 내에서 당신은 당신의 새로운 폭을 확인하실 수 있습니다 div호출을

$('.a-selector').width();

따라서 귀하의 질문에 대한 답변은 아니오resize 입니다. 이벤트를 div에 바인딩 할 수 없습니다 .


124
이 대답은 충분하지 않습니다. 창 크기를 조정하지 않으면 크기가 변경 될 수 있습니다. 조금도.
vsync

9
예를 들어 스플리터 요소가 있거나 요소에 텍스트 나 다른 내용을 추가하는 경우입니다.
Günter Zöchbauer 17:02에

@anu는 사실이 아닙니다. 예를 들어, 자바 스크립트를 통해 DOM을 수정하여 CSS가 새로운 구조에 적용되도록하여 모든 컨테이너의 크기와 레이아웃이 다릅니다.
Antoniossss

29

장기적으로 ResizeObserver 를 사용할 수 있습니다 .

new ResizeObserver(callback).observe(element);

불행히도 현재 많은 브라우저에서 기본적으로 지원되지 않습니다.

그 동안 다음과 같은 기능을 사용할 수 있습니다. 요소 크기 변경의 대부분은 DOM 크기 조정 또는 DOM의 창 크기 변경에서 비롯됩니다. 창의 크기 조정 이벤트 로 창 크기 조정을 청취하고 MutationObserver를 사용하여 DOM 변경 사항을 청취 할 수 있습니다 .

다음은 이벤트 중 하나의 결과로 제공된 요소의 크기가 변경 될 때 다시 호출하는 함수의 예입니다.

var onResize = function(element, callback) {
  if (!onResize.watchedElementData) {
    // First time we are called, create a list of watched elements
    // and hook up the event listeners.
    onResize.watchedElementData = [];

    var checkForChanges = function() {
      onResize.watchedElementData.forEach(function(data) {
        if (data.element.offsetWidth !== data.offsetWidth ||
            data.element.offsetHeight !== data.offsetHeight) {
          data.offsetWidth = data.element.offsetWidth;
          data.offsetHeight = data.element.offsetHeight;
          data.callback();
        }
      });
    };

    // Listen to the window's size changes
    window.addEventListener('resize', checkForChanges);

    // Listen to changes on the elements in the page that affect layout 
    var observer = new MutationObserver(checkForChanges);
    observer.observe(document.body, { 
      attributes: true,
      childList: true,
      characterData: true,
      subtree: true 
    });
  }

  // Save the element we are watching
  onResize.watchedElementData.push({
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  });
};

1
불행히도 MutationObserver가 Shadow DOM의 변경 사항을 감지하지 못하는 것 같습니다.
Ajedi32

@nkron, 불행히도 CSS3 resize 를 사용 하면 사용자가 수동으로 크기 를 조정할 때 크기 조정이 발생할 수 있습니다. 이 이벤트는 잡을 수 없습니다.
Pacerier

@ Ajedi32 예. 그러나 ShadowDOM 내부에서 MutationObserver를 사용할 수 있습니다. 내 말은, body이 예제와 같이 를 보는 대신 요소를 직접 볼 수 있습니다. 그것은 실제로 몸 전체를 보는 것보다 더 성능적이고 효율적입니다.
trusktr

@ Ajedi32 글쎄, 유일한 문제는 Shadow DOM 트리가 닫히면 내부에 액세스 할 수 없지만 일반적으로해야 할 일이라고 생각하지 않는다는 것입니다. 그런 닫힌 나무는 디자인에 문제가있을 수 있습니다. 이상적으로는 액세스 할 수있는 자신의 요소 만 관찰하면됩니다. 내부 크기를 관찰해야하는 Shadow-DOM 구성 요소가 올바르게 설계되지 않았을 수 있습니다. 구체적인 예가 있습니까? 그렇다면 해결책을 제안하는 데 도움이 될 수 있습니다 (나도 관심이 있지만 아직 예가 없기 때문에).
trusktr

@ trusktr 현재 MCVE가 없지만 기본적으로 일부 사용자 입력의 결과로 크기를 변경할 수있는 Shadow DOM 요소 로이 문제를 유발할 수 있습니다. 예를 들어 클릭하면 몇 가지 추가 정보로 확장되는 상자입니다. 이유와 상관없이 페이지 크기가 커지면 자동으로 아래로 스크롤하기 때문에 개별 요소가 아닌 페이지를 관찰하고 있습니다. Shadow DOM 요소 확장은 페이지가 길어질 수있는 여러 가지 이유 중 하나 일뿐입니다.
Ajedi32

24

ResizeSensor.js 는 거대한 라이브러리의 일부이지만 기능을 THIS로 줄였습니다 .

function ResizeSensor(element, callback)
{
    let zIndex = parseInt(getComputedStyle(element));
    if(isNaN(zIndex)) { zIndex = 0; };
    zIndex--;

    let expand = document.createElement('div');
    expand.style.position = "absolute";
    expand.style.left = "0px";
    expand.style.top = "0px";
    expand.style.right = "0px";
    expand.style.bottom = "0px";
    expand.style.overflow = "hidden";
    expand.style.zIndex = zIndex;
    expand.style.visibility = "hidden";

    let expandChild = document.createElement('div');
    expandChild.style.position = "absolute";
    expandChild.style.left = "0px";
    expandChild.style.top = "0px";
    expandChild.style.width = "10000000px";
    expandChild.style.height = "10000000px";
    expand.appendChild(expandChild);

    let shrink = document.createElement('div');
    shrink.style.position = "absolute";
    shrink.style.left = "0px";
    shrink.style.top = "0px";
    shrink.style.right = "0px";
    shrink.style.bottom = "0px";
    shrink.style.overflow = "hidden";
    shrink.style.zIndex = zIndex;
    shrink.style.visibility = "hidden";

    let shrinkChild = document.createElement('div');
    shrinkChild.style.position = "absolute";
    shrinkChild.style.left = "0px";
    shrinkChild.style.top = "0px";
    shrinkChild.style.width = "200%";
    shrinkChild.style.height = "200%";
    shrink.appendChild(shrinkChild);

    element.appendChild(expand);
    element.appendChild(shrink);

    function setScroll()
    {
        expand.scrollLeft = 10000000;
        expand.scrollTop = 10000000;

        shrink.scrollLeft = 10000000;
        shrink.scrollTop = 10000000;
    };
    setScroll();

    let size = element.getBoundingClientRect();

    let currentWidth = size.width;
    let currentHeight = size.height;

    let onScroll = function()
    {
        let size = element.getBoundingClientRect();

        let newWidth = size.width;
        let newHeight = size.height;

        if(newWidth != currentWidth || newHeight != currentHeight)
        {
            currentWidth = newWidth;
            currentHeight = newHeight;

            callback();
        }

        setScroll();
    };

    expand.addEventListener('scroll', onScroll);
    shrink.addEventListener('scroll', onScroll);
};

사용 방법:

let container = document.querySelector(".container");
new ResizeSensor(container, function()
{
    console.log("dimension changed:", container.clientWidth, container.clientHeight);
});

이것이 js가 수행하는 차트입니다.
Antoniossss

압축 해 주셔서 감사합니다. 나는 그것을 시도 할 것이다 :)
Tony K.

이 표현에는 빠진 것이 있습니다parseInt( getComputedStyle(element) )
GetFree

2
"let zIndex = parseInt (getComputedStyle (element));"가 어떻게 혼동되는지 혼동됩니다. 유효한? "let zIndex = parseInt (getComputedStyle (element) .zIndex);
Ryan Badour 님이

1
위의 솔루션 / 코드는 모든 크기 조정 이벤트를 감지하지 못합니다 (예 : 컨테이너가 고정 된 크기로 조정 된 경우 하위 이벤트의 크기 조정을 감지하지 못합니다 ( jsfiddle.net/8md2rfsy/1 참조 )). 수락 된 답변이 작동합니다 (해당 줄의 주석 처리를 제거하십시오).
newBee

21

나는 setTimeout()성능을 늦추기 때문에 해킹을 권장하지 않습니다 ! 대신 Div 크기 변경을 청취하기 위해 DOM 돌연변이 관찰자 를 사용할 수 있습니다.

JS :

var observer = new MutationObserver(function(mutations) {
    console.log('size changed!');
  });
  var target = document.querySelector('.mydiv');
  observer.observe(target, {
    attributes: true
  });

HTML :

<div class='mydiv'>
</div>

여기 바이올린
사업부의 크기를 변경하려고는.


debounce효율성을 높이기 위해 분석법에 분석법을 추가로 포장 할 수 있습니다 . debounceDIV 크기를 조정할 때마다 밀리 초마다 트리거하는 대신 x 밀리 초마다 메소드를 트리거합니다.


9
이 문제의 유일한 문제는 돌연변이가 실제로 요소에 발생하지 않는 한 변경 사항을보고하지 않는다는 것입니다. 다른 요소가 추가되어 요소의 크기가 조정되면 작동하지 않습니다.
Tony K.

@TonyK에 동의합니다. 이것은 MutationObserver의 유일한 문제이며 이제는 요소 크기 조정 라이브러리를 찾고 있습니다.
Murhaf Sousli

@JerryGoyal div에 <img> 태그가 포함되어 있으면 작동하지 않습니다. 첫 번째 인스턴스에서 이미지가로드되지 사업부 크기는 '0'으로 설정하고 부하 후 DIV 크기는 변경되지만, 관찰자는 트리거되지 않습니다
Santhosh

15

가장 좋은 해결책은 소위 Element Queries 를 사용하는 것 입니다. 그러나 표준이 아니며 사양이 없으며 유일한 방법은 사용하려는 폴리 필 / 라이브러리 중 하나를 사용하는 것입니다.

요소 쿼리의 기본 개념은 페이지의 특정 컨테이너가 제공된 공간에 응답 할 수 있도록하는 것입니다. 이렇게하면 구성 요소를 한 번 작성한 다음 페이지의 아무 곳에 나 놓을 수 있으며 내용을 현재 크기로 조정할 수 있습니다. 창 크기에 관계없이 이것이 요소 쿼리와 미디어 쿼리 사이의 첫 번째 차이점입니다. 누구나 어떤 시점에서 요소 쿼리 (또는 동일한 목표를 달성하는 것)를 표준화하고 기본, 깨끗하고 단순하며 강력하게 만드는 사양이 만들어지기를 희망합니다. 대부분의 사람들은 미디어 쿼리가 상당히 제한적이며 모듈 식 디자인과 진정한 응답 성을 지원하지 않는다는 데 동의합니다.

여러 가지 방법으로 문제를 해결하는 폴리 필 / 라이브러리가 몇 가지 있습니다 (솔루션 대신 해결 방법이라고도 함).

  • CSS 요소 쿼리-https: //github.com/marcj/css-element-queries
  • BoomQueries- https: //github.com/BoomTownROI/boomqueries
  • eq.js- https: //github.com/Snugug/eq.js
  • ElementQuery- https: //github.com/tysonmatanich/elementQuery
  • 그리고 여기에 나열하지 않을 몇 가지가 있지만 자유롭게 검색 할 수 있습니다. 현재 사용 가능한 옵션 중 어느 것이 가장 좋은지 말할 수 없습니다. 몇 가지 시도하고 결정해야합니다.

비슷한 문제에 대한 다른 해결책을 제안했습니다. 일반적으로 후드 아래에서 타이머 또는 창 / 뷰포트 크기를 사용하는데 이는 실제 솔루션이 아닙니다. 또한 이상적으로는 JavaScript 또는 html이 아닌 CSS에서 주로 해결해야한다고 생각합니다.


요소 검색어의 경우 +1이지만 조만간 검색어를 볼 수는 없습니다. 이 시점에서 AFAIK 사양 초안조차 없습니다 ... 아마도 우리 중 하나가 관심있는 당사자가 하나를 모아 제출해야합니까?
Rob Evans

1
물론 좋은 생각입니다. 최종 버전에 도달하는 데 시간이 오래 걸리므로 많은주의를 기울여야합니다. 이것을 좋은 방법으로 디자인하는 것은 나에게 사소한 것처럼 보이지 않습니다. 브라우저 간 호환성, 순환 종속성, 디버깅, 가독성 및 유지 관리 등 가능한 한 빨리 시작하겠습니다 :)
Stan

@ Stan, Element Query가 무엇인지에 대해 더 자세히 설명하면이 답변이 더 나을 수 있다고 생각합니다.
Pacerier

15

MarcJ의 솔루션이 작동하지 않을 때이 라이브러리가 작동한다는 것을 알았습니다.

https://github.com/sdecima/javascript-detect-element-resize

매우 가볍고 CSS 또는 HTML 로딩 / 렌더링을 통해 자연스러운 크기 조정도 감지합니다.

코드 샘플 (링크에서 가져옴) :

<script type="text/javascript" src="detect-element-resize.js"></script>
<script type="text/javascript">
  var resizeElement = document.getElementById('resizeElement'),
      resizeCallback = function() {
          /* do something */
      };
  addResizeListener(resizeElement, resizeCallback);
  removeResizeListener(resizeElement, resizeCallback);
</script>

이거 야. 147 줄, 스크롤 이벤트를 사용합니다. div 치수 변경을 가장 잘 감지하는 방법에 대한 완전한 답변을 원하면이 코드를 읽으십시오. 힌트 : "이 라이브러리 만 사용"하는 것이 아닙니다.
Seph Reed

1
사람들은 이 라이브러리를 사용하기 전에이 문제 를 살펴 봐야 합니다.
Louis

13

http://benalman.com/code/projects/jquery-resize/examples/resize/를 살펴보십시오.

다양한 예가 있습니다. 창 크기를 조정하고 컨테이너 요소 내부의 요소가 어떻게 조정되었는지 확인하십시오.

작동 방법을 설명하기 위해 js 바이올린과 예제.
이 바이올린을 살펴보십시오 http://jsfiddle.net/sgsqJ/4/

이 resize () 이벤트는 "test"클래스를 가진 요소와 윈도우 객체에 바인딩되며 윈도우 객체의 크기 조정 콜백에서 $ ( '. test'). resize ()가 호출됩니다.

예 :

$('#test_div').bind('resize', function(){
            console.log('resized');
});

$(window).resize(function(){
   $('#test_div').resize();
});

흥미 롭군 관리자가 열려있는 jsfiddle이 크롬에서 지속적으로 충돌합니다. "텍스트 추가"링크를 클릭하십시오. Firefox에서 "너무 많은 재귀"오류가 발생합니다.
EricP

3
jQuery의 크기 조정 플러그인을 사용하지 마십시오. 정말 느리고 정확하지 않습니다. 더 나은 솔루션을 얻으려면 내 답변을 참조하십시오.
Marc J. Schmidt

24
치수 변경을 직접 감지하지 않습니다. resize 이벤트 리스너의 부산물 일뿐입니다. 차원 변경은 여러 가지 방법으로 발생할 수 있습니다.
vsync

4
div 크기 조정이 창 크기 조정이 아닌 스타일이나 dom의 변경에서 오는 경우 어떻게합니까?
awe

9

사용 iframe하거나 object사용 contentWindow하거나 contentDocument크기를 조정할 수 있습니다 . setInterval또는 없이setTimeout

단계:

  1. 요소 위치를 relative
  2. 투명한 절대 숨겨진 IFRAME 내부에 추가
  3. 듣기 IFRAME.contentWindow- onresize이벤트

HTML의 예 :

<div style="height:50px;background-color:red;position:relative;border:1px solid red">
<iframe style=width:100%;height:100%;position:absolute;border:none;background-color:transparent allowtransparency=true>
</iframe>
This is my div
</div>

자바 스크립트 :

$('div').width(100).height(100);
$('div').animate({width:200},2000);

$('object').attr({
    type : 'text/html'
})
$('object').on('resize,onresize,load,onload',function(){
    console.log('ooooooooonload')
})

$($('iframe')[0].contentWindow).on('resize',function(){
    console.log('div changed')
})

실행 예

JSFiddle : https://jsfiddle.net/qq8p470d/


더보기:


1
이벤트가 iframe에서 실행될 IFRAME.contentWindow때까지 jquery를 사용하지 않는 사람들을위한 메모를 사용할 수 없습니다 onload. 또한 visibility:hidden;iframe이 마우스 뒤의 요소에 대한 마우스 입력을 차단할 수 있으므로 style을 추가 할 수 있습니다 (적어도 IE에서는 "플로팅"된 것으로 간주 됨).
James Wilkins 2016 년

3
이것이 효과가 있지만 크기 변경을 관찰하기 위해 완전히 새로운 브라우징 컨텍스트를 만드는 오버 헤드가있는 헤비급 솔루션입니다. 또한 어떤 경우 display에는 요소 의 속성 을 변경하는 것이 이상적이지 않거나 실현 가능하지 않습니다 .
trusktr

동의, 이것은 위에서 언급 한 끔찍한 해결책입니다
29er

어떻게 그렇게 끔찍한 해결책을 썼습니까?
Aminadav Glickshtein

이 방법은 동적 컨텐츠 크기 조정이 필요한 비디오 플레이어 및 오디오 플레이어와 잘 작동합니다. 이 방법을 사용하여 wavesurfer.js 출력의 크기를 조정합니다.
David Clews

8

윈도우 객체 만 "크기 조정"이벤트를 생성합니다. 내가 원하는 것을 수행하는 유일한 방법은 주기적으로 크기를 확인하는 간격 타이머를 실행하는 것입니다.


7

var div = document.getElementById('div');
div.addEventListener('resize', (event) => console.log(event.detail));

function checkResize (mutations) {
    var el = mutations[0].target;
    var w = el.clientWidth;
    var h = el.clientHeight;
    
    var isChange = mutations
      .map((m) => m.oldValue + '')
      .some((prev) => prev.indexOf('width: ' + w + 'px') == -1 || prev.indexOf('height: ' + h + 'px') == -1);

    if (!isChange)
      return;

    var event = new CustomEvent('resize', {detail: {width: w, height: h}});
    el.dispatchEvent(event);
}

var observer = new MutationObserver(checkResize); 
observer.observe(div, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
#div {width: 100px; border: 1px solid #bbb; resize: both; overflow: hidden;}
<div id = "div">DIV</div>


7

놀랍게도이 문제만큼 오래된 것은 대부분의 브라우저에서 여전히 문제입니다.

다른 사람들이 말했듯이 Chrome 64 이상에는 기본적으로 크기 조정 관찰 기능이 기본적으로 제공되지만 사양은 여전히 ​​잘 조정되어 있으며 현재 Chrome은 현재 사양 의 최신 버전 뒤에 있습니다 (2019-01-29 기준) .

나는 몇 가지 좋은 ResizeObserver polyfills를 야생에서 보았지만, 일부는 사양을 따르지 않고 일부는 계산 문제가 있습니다.

모든 응용 프로그램에서 사용할 수있는 반응 형 웹 구성 요소를 만들려면이 동작이 절실히 필요했습니다. 잘 작동하게하려면 항상 크기를 알아야하므로 ResizeObservers는 이상적으로 들리며 사양을 최대한 준수하는 폴리 필을 만들기로 결정했습니다.

리포지토리 : https://github.com/juggle/resize-observer

데모 : https://codesandbox.io/s/myqzvpmmy9


이것은 IE11 + 브라우저 호환성을 다루는 모든 사람에게 가장 적합한 대답입니다.
ekfuhrmann

3

Clay.js ( https://github.com/zzarcon/clay )를 사용하면 요소 크기의 변화를 감지하는 것이 매우 간단합니다.

var el = new Clay('.element');

el.on('resize', function(size) {
    console.log(size.height, size.width);
});

7
귀하의 도서관임을 감안하여 적절한 공개를 제공하십시오.
jhpratt GOFUNDME 재 라이센스

이것은 ResizeSensor가없는 곳에서 저에게 효과적이었습니다. 모달 스타일이 깨졌습니다. 감사합니다 Zzarcon :)
Máxima Alekz

3

이 블로그 게시물을 통해 DOM 요소의 크기 변경을 효율적으로 감지 할 수있었습니다.

http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/

이 코드를 사용하는 방법 ...

AppConfig.addResizeListener(document.getElementById('id'), function () {
  //Your code to execute on resize.
});

예제에서 사용 된 패키지 코드 ...

var AppConfig = AppConfig || {};
AppConfig.ResizeListener = (function () {
    var attachEvent = document.attachEvent;
    var isIE = navigator.userAgent.match(/Trident/);
    var requestFrame = (function () {
        var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
            function (fn) { return window.setTimeout(fn, 20); };
        return function (fn) { return raf(fn); };
    })();

    var cancelFrame = (function () {
        var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
               window.clearTimeout;
        return function (id) { return cancel(id); };
    })();

    function resizeListener(e) {
        var win = e.target || e.srcElement;
        if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__);
        win.__resizeRAF__ = requestFrame(function () {
            var trigger = win.__resizeTrigger__;
            trigger.__resizeListeners__.forEach(function (fn) {
                fn.call(trigger, e);
            });
        });
    }

    function objectLoad(e) {
        this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
        this.contentDocument.defaultView.addEventListener('resize', resizeListener);
    }

    AppConfig.addResizeListener = function (element, fn) {
        if (!element.__resizeListeners__) {
            element.__resizeListeners__ = [];
            if (attachEvent) {
                element.__resizeTrigger__ = element;
                element.attachEvent('onresize', resizeListener);
            } else {
                if (getComputedStyle(element).position === 'static') element.style.position = 'relative';
                var obj = element.__resizeTrigger__ = document.createElement('object');
                obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
                obj.__resizeElement__ = element;
                obj.onload = objectLoad;
                obj.type = 'text/html';
                if (isIE) element.appendChild(obj);
                obj.data = 'about:blank';
                if (!isIE) element.appendChild(obj);
            }
        }
        element.__resizeListeners__.push(fn);
    };

    AppConfig.removeResizeListener = function (element, fn) {
        element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
        if (!element.__resizeListeners__.length) {
            if (attachEvent) element.detachEvent('onresize', resizeListener);
            else {
                element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
                element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__);
            }
        }
    }
})();

참고 : AppConfig는 재사용 가능한 기능을 구성하는 데 사용하는 네임 스페이스 / 개체입니다. 원하는 이름으로 검색하고 이름을 바꾸십시오.


3

내 jQuery 플러그인은뿐만 아니라 모든 요소에서 "크기 조정"이벤트를 활성화합니다 window.

https://github.com/dustinpoissant/ResizeTriggering

$("#myElement") .resizeTriggering().on("resize", function(e){
  // Code to handle resize
}); 

1
링크가 더 이상 존재하지 않는 위치를 가리키고있었습니다. 플러그인 이름을 검색하여 설명에 해당하는 페이지를 찾았습니다. 귀하는 플러그인 작성자 인 것으로 보이므로 귀하의 답변임을 명시하기 위해 답변 언어를 편집했습니다. 이 사이트의 규칙은 답변을 작성할 때 개발 한 것을 사용하여 추천 할 때 관계를 명시 적으로 작성 해야합니다 .
Louis

setTimer에서 몇 가지 기능을 반복해서 실행하기 때문에 아무 문제가 없어도 브라우저가 지속적으로 CPU를 굽고 있음을 의미하기 때문에 이것은 훌륭한 해결책이 아닙니다. 랩톱 및 휴대폰 소유자는 onScroll 이벤트 사용과 같은 동작이있을 때만 브라우저 이벤트를 사용하는 솔루션을 활용할 수 있습니다.
로마 젠카

2

다음 스 니펫에서 코드를 시도 할 수 있으며 일반 자바 스크립트를 사용하여 필요를 충족시킵니다. ( 코드 스 니펫을 실행하고 전체 페이지 링크를 클릭하여 테스트하려는 경우 div 크기가 조정되었다는 경고를 트리거하십시오. ).

이것이 setInterval100 밀리 초라 는 사실에 근거하여, 내 PC가 너무 많은 CPU 배고픔을 찾지 못했다고 감히 말할 것입니다. (테스트 시점에 Chrome에서 열린 모든 탭에 대해 CPU의 0.1 %가 총계로 사용되었습니다.) 그러나 다시 이것은 하나의 div에 대한 것입니다. 다량의 요소에 대해이 작업을 수행하려는 경우 CPU 배고픔이 발생할 수 있습니다.

언제든지 click 이벤트를 사용하여 div-resize 스니핑 을 중지 할 수 있습니다 .

var width = 0; 
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized div');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
</div>

당신은 또한 바이올린을 확인할 수 있습니다

최신 정보

var width = 0; 
function myInterval() {
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
return interval;
}
var interval = myInterval();
document.getElementById("clickMe").addEventListener( "click" , function() {
if(typeof interval!=="undefined") {
clearInterval(interval);
alert("stopped div-resize sniffing");
}
});
document.getElementById("clickMeToo").addEventListener( "click" , function() {
myInterval();
alert("started div-resize sniffing");
});
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" id="clickMe" />
        <input type="button" value="button 2" id="clickMeToo" />
        <input type="button" value="button 3" />
</div>

업데이트 된 바이올린


2

이것은 최상위 답변의 정확한 사본이지만 링크 대신 중요한 코드의 일부이며 IMO로 더 읽기 쉽고 이해하기 쉽습니다. 다른 작은 변경 사항으로는 cloneNode ()를 사용하고 html을 js 문자열에 넣지 않는 것이 있습니다. 작은 것들이지만, 그대로 복사하여 붙여 넣을 수 있으며 작동합니다.

작동하는 방식은 두 개의 보이지 않는 div를보고있는 요소를 채우고 각각에 트리거를 배치하고 스크롤 위치를 설정하여 크기가 변경되면 스크롤 변경을 트리거하는 것입니다.

모든 실제 크레딧은 Marc J에게 전달되지만 관련 코드를 찾고 있다면 다음과 같습니다.

    window.El = {}

    El.resizeSensorNode = undefined;
    El.initResizeNode = function() {
        var fillParent = "display: block; position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;";
        var triggerStyle = "position: absolute; left: 0; top: 0; transition: 0s;";

        var resizeSensor = El.resizeSensorNode = document.createElement("resizeSensor");
        resizeSensor.style = fillParent;

        var expandSensor = document.createElement("div");
        expandSensor.style = fillParent;
        resizeSensor.appendChild(expandSensor);

        var trigger = document.createElement("div");
        trigger.style = triggerStyle;
        expandSensor.appendChild(trigger);

        var shrinkSensor = expandSensor.cloneNode(true);
        shrinkSensor.firstChild.style = triggerStyle + " width: 200%; height: 200%";
        resizeSensor.appendChild(shrinkSensor);
    }


    El.onSizeChange = function(domNode, fn) {
        if (!domNode) return;
        if (domNode.resizeListeners) {
            domNode.resizeListeners.push(fn);
            return;
        }

        domNode.resizeListeners = [];
        domNode.resizeListeners.push(fn);

        if(El.resizeSensorNode == undefined)
            El.initResizeNode();

        domNode.resizeSensor = El.resizeSensorNode.cloneNode(true);
        domNode.appendChild(domNode.resizeSensor);

        var expand = domNode.resizeSensor.firstChild;
        var expandTrigger = expand.firstChild;
        var shrink = domNode.resizeSensor.childNodes[1];

        var reset = function() {
            expandTrigger.style.width = '100000px';
            expandTrigger.style.height = '100000px';

            expand.scrollLeft = 100000;
            expand.scrollTop = 100000;

            shrink.scrollLeft = 100000;
            shrink.scrollTop = 100000;
        };

        reset();

        var hasChanged, frameRequest, newWidth, newHeight;
        var lastWidth = domNode.offsetWidth;
        var lastHeight = domNode.offsetHeight;


        var onResized = function() {
            frameRequest = undefined;

            if (!hasChanged) return;

            lastWidth = newWidth;
            lastHeight = newHeight;

            var listeners = domNode.resizeListeners;
            for(var i = 0; listeners && i < listeners.length; i++) 
                listeners[i]();
        };

        var onScroll = function() {
            newWidth = domNode.offsetWidth;
            newHeight = domNode.offsetHeight;
            hasChanged = newWidth != lastWidth || newHeight != lastHeight;

            if (hasChanged && !frameRequest) {
                frameRequest = requestAnimationFrame(onResized);
            }

            reset();
        };


        expand.addEventListener("scroll", onScroll);
        shrink.addEventListener("scroll", onScroll);
    }


1

@nkron의 솔루션의 단순화 된 버전은 단일 요소에 적용 할 수 있습니다 (@nkron의 답변에 요소 배열 대신 복잡성이 필요하지 않음).

function onResizeElem(element, callback) {    
  // Save the element we are watching
  onResizeElem.watchedElementData = {
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  };

  onResizeElem.checkForChanges = function() {
    const data = onResizeElem.watchedElementData;
    if (data.element.offsetWidth !== data.offsetWidth || data.element.offsetHeight !== data.offsetHeight) {
      data.offsetWidth = data.element.offsetWidth;
      data.offsetHeight = data.element.offsetHeight;
      data.callback();
    }
  };

  // Listen to the window resize event
  window.addEventListener('resize', onResizeElem.checkForChanges);

  // Listen to the element being checked for width and height changes
  onResizeElem.observer = new MutationObserver(onResizeElem.checkForChanges);
  onResizeElem.observer.observe(document.body, {
    attributes: true,
    childList: true,
    characterData: true,
    subtree: true
  });
}

이벤트 리스너 및 옵저버는 다음을 통해 제거 할 수 있습니다.

window.removeEventListener('resize', onResizeElem.checkForChanges);
onResizeElem.observer.disconnect();

0
jQuery(document).ready( function($) {

function resizeMapDIVs() {

// check the parent value...

var size = $('#map').parent().width();



if( $size < 640 ) {

//  ...and decrease...

} else {

//  ..or increase  as necessary

}

}

resizeMapDIVs();

$(window).resize(resizeMapDIVs);

});

0

사용 바랏 파틸의 단순히 당신의 바인드 콜백 내부 false를 돌려 대답 아래 최대 스택 오류를 참조 예를 방지하기 위해 :

$('#test_div').bind('resize', function(){
   console.log('resized');
   return false;
});

0

이것은 정말 오래된 질문이지만 내 솔루션을 게시 할 것이라고 생각했습니다.

ResizeSensor모두가 꽤 큰 호감이있는 것처럼 보였으므로 사용하려고 했습니다. 그래도 구현 한 후, 요소 쿼리에서 문제의 요소가 위치 relative또는absolute 적용 습니다. 이는 상황에 맞지 않습니다.

나는 interval직선 setTimeout또는 requestAnimationFrame이전 구현 대신 Rxjs로 이것을 처리했습니다 .

인터벌의 관찰 가능한 특징에 대한 좋은 점은 스트림을 수정하지만 다른 관찰 가능한 것을 처리 할 수 ​​있다는 것입니다. 나에게는 기본 구현으로 충분했지만 미쳐서 모든 종류의 병합 등을 할 수 있습니다.

아래 예제에서 내부 (녹색) div의 너비 변경을 추적하고 있습니다. 너비는 50 %로 설정되어 있지만 최대 너비는 200px입니다. 슬라이더를 드래그하면 래퍼 (회색) div의 너비에 영향을줍니다. 내부 div의 너비가 변경 될 때만 observable이 발생한다는 것을 알 수 있습니다. 이는 외부 div의 너비가 400px보다 작은 경우에만 발생합니다.

const { interval } = rxjs;
const { distinctUntilChanged, map, filter } = rxjs.operators;


const wrapper = document.getElementById('my-wrapper');
const input = document.getElementById('width-input');




function subscribeToResize() {
  const timer = interval(100);
  const myDiv = document.getElementById('my-div');
  const widthElement = document.getElementById('width');
  const isMax = document.getElementById('is-max');
  
  /*
    NOTE: This is the important bit here 
  */
  timer
    .pipe(
      map(() => myDiv ? Math.round(myDiv.getBoundingClientRect().width) : 0),
      distinctUntilChanged(),
      // adding a takeUntil(), here as well would allow cleanup when the component is destroyed
    )
      .subscribe((width) => {        
        widthElement.innerHTML = width;
        isMax.innerHTML = width === 200 ? 'Max width' : '50% width';

      });
}

function defineRange() {
  input.min = 200;
  input.max = window.innerWidth;
  input.step = 10;
  input.value = input.max - 50;
}

function bindInputToWrapper() {
  input.addEventListener('input', (event) => {
    wrapper.style.width = `${event.target.value}px`;
  });
}

defineRange();
subscribeToResize();
bindInputToWrapper();
.inner {
  width: 50%;
  max-width: 200px;
}




/* Aesthetic styles only */

.inner {
  background: #16a085;
}

.wrapper {
  background: #ecf0f1;
  color: white;
  margin-top: 24px;
}

.content {
  padding: 12px;
}

body {
  
  font-family: sans-serif;
  font-weight: bold;
}
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>

<h1>Resize Browser width</h1>

<label for="width-input">Adjust the width of the wrapper element</label>
<div>
  <input type="range" id="width-input">
</div>

<div id="my-wrapper" class="wrapper">
  <div id="my-div" class="inner">
    <div class="content">
      Width: <span id="width"></span>px
      <div id="is-max"></div>  
    </div>
  </div>
</div>


-1

Window.onResize사양 에만 존재하지만 DIV 내부에서 항상 IFrame새로운 Window객체 를 생성 하는 데 활용할 수 있습니다 .

답변을 확인하십시오 . 이식성이 있고 사용하기 쉬운 새로운 작은 jquery 플러그인 이 있습니다. 소스 코드를 확인하여 수행 방법을 확인할 수 있습니다.

<!-- (1) include plugin script in a page -->
<script src="/src/jquery-element-onresize.js"></script>

// (2) use the detectResizing plugin to monitor changes to the element's size:
$monitoredElement.detectResizing({ onResize: monitoredElement_onResize });

// (3) write a function to react on changes:
function monitoredElement_onResize() {    
    // logic here...
}

크기 조정 가능한 div가있는 경우 매우 효과적이지 않은 솔루션입니다.
suricactus

-1

할 수 없다고 생각했지만 그것에 대해 생각했습니다. style = "resize : both;"를 통해 div의 크기를 수동으로 조정할 수 있습니다. 이를 위해 클릭 한 번으로 요소의 높이와 너비를 확인하는 onclick 기능을 추가하여 작동했습니다. 순수한 자바 스크립트 5 줄만 있으면 (더 짧을 수 있음) http://codepen.io/anon/pen/eNyyVN

<div id="box" style="
                height:200px; 
                width:640px;
                background-color:#FF0066;
                resize: both;
                overflow: auto;" 
                onclick="myFunction()">
    <p id="sizeTXT" style="
                font-size: 50px;">
       WxH
    </p>
    </div>

<p>This my example demonstrates how to run a resize check on click for resizable div.</p>

<p>Try to resize the box.</p>


<script>
function myFunction() {
var boxheight = document.getElementById('box').offsetHeight;
var boxhwidth = document.getElementById('box').offsetWidth;
var txt = boxhwidth +"x"+boxheight;
document.getElementById("sizeTXT").innerHTML = txt;
}
</script>

2
이것은 클릭 이벤트가 시작될 때만 계산되며 질문의 요구 사항에 속하지 않습니다.
Rob Evans
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.