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

다음 샘플 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>



답변

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

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속성 을 읽고 변경 사항을 확인 하는 데 사용되므로 사용 하지 마십시오 . 레이아웃 스 래싱을 유발하기 때문에
매우 느리고 부정확 합니다 .

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


답변

이에 대한 새로운 표준은 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


답변

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

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

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

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

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

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


답변

장기적으로 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
  });
};


답변

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);
});


답변

나는 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 밀리 초마다 메소드를 트리거합니다.


답변

가장 좋은 해결책은 소위 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에서 주로 해결해야한다고 생각합니다.