Как обнаружить изменение измерения DIV?

У меня есть следующий пример html, есть DIV, который имеет ширину 100%. Он содержит некоторые элементы. При повторной калибровке окон внутренние элементы могут быть переставлены, а размер div может измениться. Я спрашиваю, Можно ли подключить событие изменения измерения div? и как это сделать? В настоящее время я привязываю функцию обратного вызова к событию изменения размера jQuery на целевом DIV, однако журнал консоли не выводится, см. ниже:

Before Resizeenter image description here

<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>

21 ответов


существует очень эффективный метод определения того, был ли изменен размер элемента.

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

эта библиотека имеет класс ResizeSensor который можно использовать для обнаружения изменения размера.
он использует основанный на событиях подход, поэтому он чертовски быстр и не тратит время процессора.

пример:

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

пожалуйста, не используйте jQuery onresize плагин как он использует setTimeout() цикл для проверки изменений.
ЭТО НЕВЕРОЯТНО МЕДЛЕННО И НЕ ТОЧНО.

раскрытие информации: я непосредственно связан с этой библиотекой.


новым стандартом для этого является api Resize Observer, доступный в Chrome 64.

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>

Изменить Размер Обозреватель

Spec:https://wicg.github.io/ResizeObserver

Polyfills:https://github.com/WICG/ResizeObserver/issues/3

Проблема Firefox:https://bugzil.la/1272409

Проблема Safari: http://wkb.ug/157743

Поддержка: http://caniuse.com/#feat=resizeobserver


вы должны связать resize событие window объект, а не на общем элементе html.

вы можете использовать это:

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

и в функции обратного вызова вы можете проверить новые ширина div вызов

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

Итак, ответ на твой вопрос нет, вы не можете связать resize событие для div.


долгосрочность, вы будете использовать ResizeObserver.

new ResizeObserver(callback).observe(element);

к сожалению, в настоящее время он не поддерживается по умолчанию во многих браузерах.

в то же время, вы можете использовать функцию, как показано ниже. Поскольку большинство изменений размера элемента будет происходить из изменения размера окна или из изменения чего-либо в DOM. Вы можете слушать изменение размера окна с помощью окна изменение размера событие, и вы можете слушать изменения DOM, используя mutationobserver'а.

вот пример функции, которая перезвонит вам, когда размер предоставленного элемента изменится в результате любого из этих событий:

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

взгляните на это http://benalman.com/code/projects/jquery-resize/examples/resize/

Он имеет различные примеры. Попробуйте изменить размер окна и посмотреть, как настраиваются элементы внутри элементов контейнера.

пример с JS fiddle, чтобы объяснить, как заставить его работать.
Взгляните на эту скрипку http://jsfiddle.net/sgsqJ/4/

в этом событии resize() привязан к элементам, имеющим класс "test", а также к объекту window и в изменении размера обратного вызова объекта window $('.test').вызывается resize ().

например

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

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

лучшим решением было бы использовать так называемые Элемент Запросов. Однако, они не стандартные, нет спецификация существует и единственный вариант-это использовать один из полифиллы/библиотеки, если вы хотите идти по этому пути.

идея запросов элементов заключается в том, чтобы позволить определенному контейнеру на странице отвечать на предоставленное ему пространство. Это позволит написать компонент один раз, а затем удалить его в любом месте страницы, в то время как он будет настраивать его содержание к своему текущему размеру. независимо от размера окна. Это первое различие, которое мы видим между поисковым элементом и медиа-запросы. Все надеются, что в какой-то момент будет создана спецификация, которая стандартизирует запросы элементов (или что-то, что достигает той же цели) и сделает их родными, чистыми, простыми и надежными. Большинство людей согласны с тем, что медиа-запросы довольно ограничены и не помогают модульному проектированию и истинной отзывчивости.

там есть несколько polyfills / библиотек, которые решают проблему по-разному (можно назвать обходными путями вместо решений):

Я видел другие решения подобных проблем. Обычно они используют таймеры или размер окна / окна под капотом, что не является реальным решением. Кроме того, я думаю, что в идеале это должен решаться в основном в CSS, а не в javascript или html.


Я нашел эту библиотеку для работы, когда решение 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>

ResizeSensor.js-огромная библиотека, но я сокращаю ее до этой.

Puff:

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() взломать, поскольку это замедляет производительность! Вместо этого, вы можете использовать наблюдатели мутации DOM для прослушивания изменения размера Div.

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>

вот скрипка https://jsfiddle.net/JerryGoyal/uep7nse1/
Попробуйте изменить размер div.


вы можете дополнительно обернуть свой метод в debounce метод для повышения эффективности. debounce вызовет ваш метод за X миллисекунд вместо запуска каждого миллисекундного DIV изменяется.


можно использовать 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>

Javascript:

$('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/


Посмотреть подробнее:


только объект window генерирует событие "resize". Единственный известный мне способ сделать то, что вы хотите сделать, - это запустить интервальный таймер, который периодически проверяет размер.


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>

С Помощью Глины.js (https://github.com/zzarcon/clay) довольно просто обнаружить изменения размера элемента:

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

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

это сообщение в блоге помогло мне эффективно обнаружить изменения размера элементов 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 имен/объекта я использую для организации универсальных функций. Не стесняйтесь искать и заменять имя на что угодно как.


мой плагин jQuery включает событие "resize" для всех элементов, а не только window.

https://github.com/dustinpoissant/ResizeTriggering

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

вы можете попробовать код в следующем фрагменте, он охватывает ваши потребности, используя простой javascript. (запустите фрагмент кода и нажмите ссылку "полная страница", чтобы вызвать предупреждение об изменении размера div, если вы хотите его проверить.).

исходя из того, что это setInterval 100 миллисекунд, я бы осмелился сказать,что мой компьютер не нашел его слишком голодным. (0,1% CPU было использовано в общей сложности для всех открытых вкладок в Chrome на момент тестирования.). Но опять же это это только для одного div, если вы хотите сделать это для большого количества элементов, то да, это может быть очень голодный процессор.

вы всегда можете использовать событие 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>

обновление Скрипка


это в значительной степени точная копия верхнего ответа, но вместо ссылки это просто часть кода, которая имеет значение, переведенная, чтобы быть более читаемой и понятной. Несколько других небольших изменений включают использование cloneNode (), а не ввод html в строку js. Мелочи, но вы можете скопировать и вставить это как есть, и это сработает.

как это работает, делая два невидимых divs заполнить элемент, который вы смотрите, а затем положить триггер в каждом, и установка положения прокрутки, которое приведет к запуску изменения прокрутки при изменении размера.

весь реальный кредит идет Марку 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);
    }

Я думал, что это не может быть сделано, но потом я подумал об этом, вы можете вручную изменить размер div через style="resize: both;" для этого вам нужно нажать на него, чтобы добавить функцию onclick для проверки высоты и ширины элемента, и это сработало. Только с 5 строками чистого javascript (конечно, он может быть еще короче) 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>

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

});

С помощью Бхарат Патил ответ просто верните false внутри обратного вызова привязки, чтобы предотвратить максимальную ошибку стека см. пример ниже:

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

только Window.onResize существует в спецификации, но вы всегда можете использовать IFrame создать новый Window объект внутри вашего DIV.

пожалуйста, проверьте это ответ. Есть новый маленький плагин 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...
}