Как определить изменение размера DIV?

352

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

Перед изменением размера введите описание изображения здесь

<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
Это не будет работать, потому что вы связываете событие изменения размера с указанным элементом div. Но событие resize сработает для окна, а не для вашего элемента.
Фатих Ацет
Вы можете использовать setIntervalздесь в качестве возможного решения. Вы всегда можете привязать clearIntervalк нажатию кнопки, чтобы остановить цикл, как только ваша работа будет завершена.
Питер Дармис
1
С 2020 года ResizeObserver работает во всех основных браузерах (Chrome, Safari, Firefox, Edge), кроме IE. caniuse.com/#feat=resizeobserver
Дан,

Ответы:

265

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

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

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

Пример:

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

Пожалуйста, не используйте плагин jQuery onresize, так как он используется setTimeout()в сочетании с чтением DOM clientHeight/ clientWidthсвойств в цикле для проверки изменений.
Это невероятно медленно и неточно, так как вызывает перебивание макета .

Раскрытие: я напрямую связан с этой библиотекой.

Марк Дж. Шмидт
источник
8
@jake, поддержка IE11 теперь реализована.
Марк Дж. Шмидт,
15
@Aletheios вы должны присмотреться. requestAnimationFrame предназначен не для медленного определения размеров, а с точностью до наоборот: он сглаживает все те крайние числа событий, которые запускаются датчиком изменения размера на основе реальных событий, чтобы сэкономить время процессора. Смотрите обновленные документы на github.com/marcj/css-element-queries/blob/master/src/…
Марк Дж. Шмидт,
6
@Aletheios Я думаю, вы упустили момент: setTimeout не только неточен, но и чертовски медленен. RequestAnimationFrame, который проверяет простое логическое значение, на несколько порядков быстрее, чем setTimeout, постоянно проверяющий свойства DOM. Помимо этого setTimeout также вызывается каждые несколько миллисекунд.
Марк Дж. Шмидт
9
@ Орвеллофил, ты, очевидно, ничего не понял. Прекратите подавлять ответы, если вы не представляете, как это работает внутри. Снова: css-element-query: использует реальное событие изменения размера, которое запускается каждый раз, когда изменяется измерение. Поскольку вы получите слишком много событий (например, для drag'n'drop), он добавил requestAnimationFrame, проверяющий простую логическую переменную, чтобы сгладить эти инициируемые события до 1 / кадр. Плагин jquery: использует setTimeout, проверяющий все время реквизиты макета DOM (clientHeight и т. д.), где каждая проверка очень медленная, но ее нужно часто проверять, чтобы иметь одинаковую функциональность.
Марк Дж. Шмидт
9
@Aletheios, @Orwellophile и все, кого они могли ввести в заблуждение: requestAnimationFramevs не setTimeoutимеет значения, эта библиотека не работает . requestAnimationFrameиспользуется только для устранения / уменьшения частоты вызовов ваших обратных вызовов, он не опрашивает . MutationObserver теоретически может быть использован для аналогичного эффекта, но не в старых браузерах, в отличие от этого. Это невероятно умно.
Хан Сеул-О,
251

Новый стандарт для этого - 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>

Resize Observer

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

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

Firefox Issue: https://bugzil.la/1272409

Safari Issue: http://wkb.ug/157743

Текущая поддержка: http://caniuse.com/#feat=resizeobserver

Даниэль Херр
источник
3
пока не используется для производственных сайтов, так как в настоящее время его поддерживает только Chrome. Но определенно лучшее решение здесь! Кстати, вот краткий обзор статуса реализации: chromestatus.com/feature/5705346022637568
Филипп
8
@ Филипп Есть полифилл.
Даниэль Херр
2
Кажется, это все еще экспериментальная функция во всех браузерах. Caniuse.com/#feat=resizeobserver
Франческ Росас
5
Даже через 2 года после этого ответа поддержка браузера невелика
Scrimothy
2
Работает как шарм в последних Chrome и FF.
Клемен Тушар
32

Вы должны привязать resizeсобытие к windowобъекту, а не к элементу общего HTML.

Вы могли бы тогда использовать это:

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

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

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

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

Алессандро Вендрусколо
источник
124
Этот ответ недостаточно хорош. изменения размера могут произойти без изменения размера окна. вообще.
vsync
9
например, когда у вас есть элемент сплиттера или вы просто добавляете некоторый текст или другое содержимое к элементу.
Гюнтер Цохбауэр
@anu не верно, вы можете иметь, например, модификацию DOM через javascript, в результате чего CSS будет применяться к новой структуре, что приведет к разной компоновке - размеру каждого контейнера.
Антониосс
29

В долгосрочной перспективе вы сможете использовать ResizeObserver .

new ResizeObserver(callback).observe(element);

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

В то же время, вы можете использовать функцию, как показано ниже. Так как большинство изменений размера элемента будет происходить из изменения размера окна или из-за изменения чего-либо в DOM. Вы можете прослушивать изменение размера окна с помощью события resize окна и прослушивать изменения 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
  });
};
nkron
источник
1
К сожалению, похоже, что MutationObserver не может обнаружить изменения в Shadow DOM.
Ajedi32
@nkron, к сожалению, если вы используете CSS3 изменения размера , изменение размера может произойти, когда пользователь изменяет размер вручную. Это событие не может быть пойман.
Pacerier
@ Ajedi32 Да, но вы можете использовать MutationObserver внутри ShadowDOM. Я имею в виду, что вместо просмотра, bodyкак в этом примере, вы можете наблюдать за элементом напрямую. Это на самом деле более эффективно и эффективно, чем наблюдать за всем телом.
trusktr
@ Ajedi32 Ну, единственная проблема в том, что если дерево Shadow DOM закрыто, вы не сможете получить доступ к внутренним компонентам, но я не думаю, что это обычно то, что вам нужно делать, и если вам нужно наблюдать закрытое дерево, подобное этому, тогда может быть проблема в дизайне. В идеале вам нужно только наблюдать за своими собственными элементами, к которым у вас есть доступ. Компонент Shadow-DOM, который требует от вас соблюдения его внутреннего размера, может быть неправильно спроектирован. У вас есть конкретный пример? Если это так, может быть, я могу помочь предложить решение (потому что я тоже интересуюсь им, но пока не имею примера).
trusktr
@trusktr У меня нет MCVE на данный момент, но в принципе для запуска этой проблемы достаточно любого элемента Shadow DOM, который может изменить свой размер в результате некоторого пользовательского ввода. Например, поле, в котором при щелчке раскрывается дополнительная информация. Обратите внимание, что я наблюдаю за страницей, а не за отдельным элементом, потому что я хочу автоматически прокручивать страницу вниз, когда размер страницы увеличивается, независимо от причины. Расширение теневого DOM-элемента является лишь одной из многих возможных причин, по которым страница может стать длиннее.
Ajedi32
24

ResizeSensor.js является частью огромной библиотеки, но я сократил ее функциональность до ЭТОГО :

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.
Антониосс
Спасибо за сжатие этого. Я собираюсь попробовать это :)
Тони К.
В этом выражении чего-то не хватаетparseInt( getComputedStyle(element) )
GetFree
2
Я запутался, как это "let zIndex = parseInt (getComputedStyle (element));" действует? Я предполагаю, что вы имели в виду: "let zIndex = parseInt (getComputedStyle (element) .zIndex);
Райан Бадур
1
Приведенное выше решение / код не обнаруживает все события изменения размера (например, если размер контейнера изменяется до фиксированного с ним, он не определяет изменение размера дочерних событий. См. Jsfiddle.net/8md2rfsy/1 ). Принятый ответ работает (раскомментируйте соответствующие строки).
newBee
21

Я НЕ рекомендую 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>

Вот скрипка
Попробуйте изменить размер div.


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

JerryGoyal
источник
9
Единственная проблема, связанная с этим, заключается в том, что он не сообщает об изменении, если только с элементом не произошла мутация. Если размер элемента из-за добавления других элементов не будет работать.
Тони К.
Я согласен с @TonyK., Это моя единственная проблема с MutationObserver, и теперь я ищу библиотеку изменения размера элемента
Murhaf Sousli
@JerryGoyal Не работает, когда div содержит тег <img>. В первом случае изображение не загружается, и размер div устанавливается равным 0, а после загрузки размер div изменяется, но наблюдатель не запускается
Santhosh
15

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

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

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

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

Стан
источник
+1 для запросов элементов, но я не надеюсь увидеть их в ближайшее время. На данный момент нет даже черновой спецификации AFAIK ... может, кто-то из нас, заинтересованных сторон, должен собрать ее и представить?
Роб Эванс
1
Это хорошая идея, конечно. Для достижения окончательной версии потребуется много времени, много внимания нужно обратить. Хорошее проектирование этого не кажется мне тривиальным. Кросс-браузерная совместимость, циклические зависимости, отладка, удобочитаемость, поддержка и т. Д. Итак, давайте начнем как можно раньше :)
Stan
@Stan, я думаю, что этот ответ может быть лучше, если добавить больше подробностей о том, что такое Element Query.
Пейсер
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>
joshcomley
источник
Это оно. 147 строк, использует события прокрутки. Прочтите этот код, если вы хотите получить полный и верный ответ о том, как наилучшим образом обнаружить изменения размера div. Подсказка: это не «просто используйте эту библиотеку».
Сеф Рид
1
Люди должны взглянуть на эту проблему, прежде чем попробовать эту библиотеку.
Луи
13

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

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

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

При этом событие resize () привязывается к элементам, имеющим класс «test», а также к объекту окна и при вызове resize объекта окна $ ('. Test'). Resize () вызывается.

например

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

$(window).resize(function(){
   $('#test_div').resize();
});
Бхарат Патил
источник
Интересный. Это jsfiddle последовательно вылетает Chrome с открытым инспектором, и я нажимаю ссылку «Добавить текст». Firefox выдает «слишком много рекурсии» ошибок.
EricP
3
Пожалуйста, не используйте плагин изменения размера jQuery. Это действительно медленно и не точно. Смотрите мой ответ, чтобы получить лучшее решение.
Марк Дж. Шмидт
24
Это НЕ непосредственно определяет изменения размеров. это просто побочный продукт прослушивателя события изменения размера. изменения размеров могут происходить многими другими способами.
vsync
4
Что если изменение размера div происходит из-за изменения стиля или dom, а не из-за изменения размера окна?
благоговение
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>

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/


Узнать больше:

Аминадав Гликштейн
источник
1
Примечание для тех, кто не использует jquery, IFRAME.contentWindowнедоступно, пока onloadсобытие не сработает в iframe. Кроме того, вы можете захотеть добавить стиль visibility:hidden;, так как iframe может блокировать ввод мыши в элементы позади него (по крайней мере, в IE он «плавающий»).
Джеймс Уилкинс
3
Несмотря на то, что это работает, это тяжелое решение с накладными расходами на создание совершенно нового контекста просмотра только для наблюдения за изменением размера. Кроме того, в некоторых случаях не является идеальным или практически невозможным изменить displayсвойство элемента.
trusktr
согласен, это ужасное решение, как указано выше
29
Как написал такое ужасное решение?
Аминадав Гликштейн
Этот метод хорошо работает с видеопроигрывателями и аудиоплеерами, которым требуется динамическое изменение размера контента. Я использую этот метод, чтобы изменить размер файла wavesurfer.js.
Дэвид Клос
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+ теперь поставляется с Resize Observation изначально, однако спецификация все еще находится в тонкой настройке, и Chrome в настоящее время (по состоянию на 2019-01-29) отстает от последней версии спецификации .

Я видел несколько хороших полизаполнений ResizeObserver в дикой природе, однако, некоторые из них не следуют спецификации, а другие имеют некоторые проблемы с вычислениями.

Я отчаянно нуждался в таком поведении для создания некоторых адаптивных веб-компонентов, которые могли бы использоваться в любом приложении. Чтобы они работали хорошо, им нужно всегда знать свои размеры, поэтому ResizeObservers звучит идеально, и я решил создать полифилл, который бы максимально соответствовал спецификации.

Repo: 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);
});
Zzarcon
источник
7
Пожалуйста, предоставьте соответствующее раскрытие, учитывая, что это ваша библиотека.
Jhpratt GOFUNDME RELICENSING
Это сработало для меня, где ResizeSensor нет, это нарушает мой модальный стиль. Спасибо, Ззаркон :)
Максима Алек
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
Ваша ссылка указывала на местоположение, которое больше не существует. Я искал название плагина и нашел страницу, которая соответствует вашему описанию. Поскольку вы, кажется, являетесь автором плагина, я также отредактировал язык вашего ответа, чтобы было ясно, что это ваша работа. Правила этого сайта таковы, что когда вы пишете ответы, рекомендуем использовать что-то, что вы разработали, вы должны сделать отношения явными.
Луи
Это не очень хорошее решение, потому что вы снова и снова запускаете некоторую функцию в setTimer, что означает, что браузер постоянно загружает процессор, даже если ничего не происходит. Владельцы ноутбуков и сотовых телефонов получают выгоду от решения, которое использует события браузера только при наличии какого-либо действия, например, при использовании события onScroll.
Роман Зенка,
2

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

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

Вы всегда можете использовать событие щелчка, чтобы в любом случае остановить сниффинг 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

Чистое решение Javascript, но работает, только если размер элемента изменяется с помощью кнопки css resize :

  1. сохранить размер элемента с помощью offsetWidth и offsetHeight ;
  2. добавить прослушиватель события onclick для этого элемента;
  3. при срабатывании сравните текущее offsetWidthи offsetHeightс сохраненными значениями и, если они отличаются, сделайте то, что хотите, и обновите эти значения.
roipoussiere
источник
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();
Gman
источник
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

используя ответ Bharat Patil, просто верните false в обратном вызове bind, чтобы предотвратить ошибку максимального стека, см. пример ниже:

$('#test_div').bind('resize', function(){
   console.log('resized');
   return false;
});
белый кролик
источник
0

Это действительно старый вопрос, но я решил опубликовать свое решение по этому вопросу.

Я пытался использовать, ResizeSensorтак как все, казалось, были в восторге. После реализации, однако, я понял, что под капотом Element Query требуется, чтобы рассматриваемый элемент имел положение relativeилиabsolute применялся к нему, что не сработало для моей ситуации.

В итоге я обработал это с помощью Rxjs intervalвместо прямой setTimeoutили requestAnimationFrameаналогичной предыдущей реализации.

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

В приведенном ниже примере я отслеживаю изменения ширины внутреннего (зеленого) элемента div. Его ширина установлена ​​на 50%, но максимальная ширина составляет 200 пикселей. Перетаскивание ползунка влияет на ширину обёртки (серого) div. Вы можете видеть, что наблюдаемое срабатывает только при изменении ширины внутреннего div, что происходит, только если ширина внешнего 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>

Scrimothy
источник
-1

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...
}
rbtbar
источник
Это очень неэффективное решение, если у вас есть div с изменяемым размером.
Suricactus
-1

я думал, что это не может быть сделано, но потом я подумал об этом, вы можете вручную изменить размер 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>
PixelPimp
источник
2
Он рассчитывается только при срабатывании события щелчка, которое не является частью требования вопроса.
Роб Эванс