Як виявити зміни розміру 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. Але подія зміни розміру запустить вікно не для вашого елемента.
Fatih Acet

Ви можете використати setIntervalтут як можливе рішення. Ви завжди можете прив'язати clearIntervalдо натискання кнопки, щоб зупинити цикл, коли ваша робота закінчена.
Пітер Дарміс

1
З 2020 року ResizeObserver працює у всіх основних браузерах (Chrome, Safari, Firefox, Edge), крім IE. caniuse.com/#feat=resizeobserver
Dan

Відповіді:


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/…
Marc J. Schmidt

6
@Aletheios Я думаю, ви пропустите точку: setTimeout не тільки неточний, але й повільний, як пекло. RequestAnimationFrame, який перевіряє простий булевий, на порядок швидший, ніж setTimeout, який весь час перевіряє властивості DOM. Крім цього setTimeout також називається кожні кілька мілісекунд.
Марк Дж. Шмідт

9
@Orwellophile ви, очевидно, нічого не зрозуміли. Перестаньте робити заборонені відповіді там, де ви поняття не маєте, як це працює всередині. Знову ж таки: css-element-query: використовує реальну подію зміни розміру, яка запускається щоразу, коли розмір змінюється. Оскільки ви отримаєте занадто багато подій (наприклад, для drag'n'drop), він додав checkAnimationFrame для перевірки простої булевої змінної, щоб згладити ці викликані події до 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>

Змінити розмір спостерігача

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

Поліфузи: https://github.com/WICG/ResizeObserver/isissue/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 Є поліфіл.
Даніел Гер

2
Здається, це все-таки експериментальна функція у всіх браузерах caniuse.com/#feat=resizeobserver
Francesc Rosas

5
Навіть через 2 роки після цієї відповіді, підтримка браузера безрадісна: caniuse.com/#search=resizeobserver
Scrimothy

2
Працює як шарм в останніх Chrome і FF.
Клемен Тушар

32

Ви повинні зв’язати resizeподію наwindow об'єкта, а не до загального html-елемента.

Потім ви можете використовувати це:

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

і за допомогою функції зворотного дзвінка ви можете перевірити нову ширину свого divдзвінка

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

Отже, відповідь на ваше запитання - ні , ви не можете пов'язувати resizeподію з дівом.


124
ця відповідь недостатньо хороша. зміни розміру можуть відбуватися без будь-якого розміру вікна. зовсім.
vsync

9
наприклад, якщо у вас є елемент спліттера або просто додаєте до нього якийсь текст або інший вміст.
Günter Zöchbauer

@anu не відповідає дійсності, ви можете, наприклад, змінити DOM через javascript, що призведе до того, що CSS застосовується до нової структури, що призводить до різного розміру макета кожного контейнера.
Антоніоссс

29

Довгостроково ви зможете використовувати 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
  });
};

1
На жаль, здається, що MutationObserver не може виявити зміни в Shadow DOM.
Ajedi32

@nkron, на жаль, якщо ви використовуєте розмір CSS3 , розмір може статися, коли користувач змінить розмір вручну. Цю подію неможливо зловити.
Pacerier

@ Ajedi32 Так, але ви можете використовувати MutationObserver всередині ShadowDOM. Що я маю на увазі, це замість того, щоб дивитись, bodyяк у цьому прикладі, ви можете дивитися елемент безпосередньо. Це насправді ефективніше та ефективніше, ніж спостереження за усім тілом.
trusktr

@ Ajedi32 Ну, єдина проблема, якщо дерево Shadow DOM закрите, ви не зможете отримати доступ до внутрішніх справ, але я не думаю, що це зазвичай щось потрібно робити, і якщо вам потрібно спостерігати закрите дерево подібне, то може виникнути проблема в дизайні. В ідеалі вам слід лише спостерігати за своїми елементами, до яких у вас є доступ. Компонент Shadow-DOM, який вимагає дотримуватися його внутрішнього розміру, може бути неправильно розроблений. У вас є конкретний приклад? Якщо так, можливо, я можу допомогти запропонувати рішення (бо мене це теж цікавить, але приклад поки не маю).
trusktr

@trusktr На даний момент у мене немає MCVE, але в основному будь-який елемент Shadow DOM, який може змінити свій розмір в результаті деякого введення користувача, буде достатньо, щоб викликати цю проблему. Наприклад, вікно, яке розширюється додатковою інформацією при натисканні. Зауважте, що я спостерігаю за сторінкою, а не окремим елементом, тому що я хочу автоматично прокручувати вниз, коли розмір сторінки збільшується, незалежно від причини. Елемент Shadow 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) )
бракує

2
Мене бентежить, як "нехай zIndex = parseInt (getComputedStyle (елемент));" чинне? Я припускаю, що ви мали на увазі: "нехай 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 змінюється за розміром.


9
Єдина проблема з цим полягає в тому, що він не повідомляє про зміни, якщо мутація насправді не відбудеться з елементом. Якщо елемент змінить розмір за рахунок додавання інших елементів, це не працюватиме.
Тоні К.

Я погоджуюся з @TonyK. Це моя єдина проблема з MutationObserver, і тепер я шукаю бібліотеку
змінних

@JerryGoyal Не працює, коли div містить тег <img>. У першому випадку зображення не завантажується і розмір div встановлюється як 0, а після завантаження розмір div змінюється, але спостерігач не спрацьовує
Santhosh,

15

Найкращим рішенням буде використання так званих запитів елементів . Однак вони не є стандартними, ніяких специфікацій не існує - і єдиний варіант - використовувати одне з наявних поліфазів / бібліотек, якщо ви хочете піти цим шляхом.

Ідея запитів елементів полягає в тому, щоб дозволити певному контейнеру на сторінці відповідати на простір, який йому надається. Це дозволить написати компонент один раз, а потім скинути його будь-де на сторінці, при цьому він буде коригувати його вміст під його поточний розмір. Незалежно від розміру Вікна. Це перша різниця, яку ми бачимо між запитами елементів та медіа-запитами. Усі сподіваються, що в якийсь момент буде створена специфікація, яка стандартизує запити елементів (або те, що досягає тієї ж мети) та зробить їх рідними, чистими, простими та надійними. Більшість людей погоджуються з тим, що медіа-запити досить обмежені і не допомагають модульному дизайну та справжній чуйності.

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

Я бачив інші запропоновані варіанти подібних проблем. Зазвичай вони використовують таймери або розмір вікна / вікна перегляду під кришкою, що не є реальним рішенням. Крім того, я думаю, що в ідеалі це повинно вирішуватися в основному в CSS, а не в JavaScript або html.


+1 для запитів елементів, але я не сподіваюсь побачити їх найближчим часом. На даний момент навіть немає проекту специфікації AFAIK ... можливо, хтось із нас, хто зацікавився, повинен скласти його та подати?
Роб Еванс

1
Це гарна ідея, звичайно. До кінця версії знадобиться багато часу, потрібно звернути багато уваги. Конструювати це вдало, мені не здається банальним. Сумісність між браузерами, кругові залежності, налагодження, читабельність та обслуговування тощо. Отже, почнемо якомога раніше :)
Стан

@ Стан, я думаю, що ця відповідь може бути кращою, додавши докладнішу інформацію про те, про що йдеться у запиті елементів.
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
Люди повинні поглянути на це питання, перш ніж спробувати цю бібліотеку.
Луї

13

Погляньте на цей http://benalman.com/code/projects/jquery-resize/examples/resize/

Він має різні приклади. Спробуйте змінити розмір вікна і подивитися, як коригуються елементи всередині елементів контейнера.

Приклад з js fiddle, щоб пояснити, як змусити його працювати.
Погляньте на цю скрипку 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. Це дуже повільно, а також не точно. Дивіться мою відповідь, щоб отримати краще рішення.
Марк Дж. Шмідт

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

погодилися, це жахливе рішення, як сказано вище
29er

Як написали таке жахливе рішення?
Амінадав Глікштейн

цей метод добре працює з відеоплеєрами та аудіоплеєрами, яким потрібен динамічний розмір вмісту. Я використовую цей метод, щоб змінити розмір виводу Waveurfer.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 Observe, але специфікація все ще налагоджується, і Chrome зараз (за 2019-01-29) відстає від останньої версії специфікації .

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

Я відчайдушно потребував такої поведінки, щоб створити деякі чуйні веб-компоненти, які можна було б використовувати в будь-якій програмі. Для того, щоб вони добре працювали, вони повинні знати їх розміри в усі часи, тому 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 RELICENSING

Це працювало для мене, коли ResizeSensor цього не робить, це порушує мій модальний стиль. Дякую Zzarcon :)
Максіма Алекз

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 зміни розміру, якщо ви хочете перевірити його. )

Виходячи з того, що це а setInterval 100 мілісекунд, я б наважився сказати, що мій ПК не вважає його занадто великим голодним процесором. (0,1% CPU було використано загалом для всіх відкритих вкладок у Chrome на тестований час.). Але знову ж таки це лише один дів, якщо ви хочете зробити це для великої кількості елементів, то так, це може бути дуже голодним процесором.

Ви завжди можете використовувати подію натискання, щоб все-таки зупинити нюхання за розміром.

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-рядок. Невеликі речі, але ви можете скопіювати та вставити це так, як є, і воно буде працювати.

Як це працює - це зробити два невидимих ​​діви заповнити спостережуваний елемент, а потім поставити тригер у кожну та встановити положення прокрутки, яке призведе до запуску зміни прокрутки, якщо розмір зміниться.

Весь реальний кредит припадає на 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 :

  1. зберігати розмір елементів із зміщенням ширини та зміщення висоти ;
  2. додайте прослуховувач подій onclick по цьому елементу;
  3. при спрацьовуванні, порівняти curent offsetWidthі offsetHeightзі збереженими значеннями, а якщо різні, робити те , що ви хочете , і оновлювати ці значення.

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

використовуючи відповідь Bharat Patil, просто поверніть помилкове значення у зворотній зв'язок, щоб запобігти максимальній помилці стека, див. приклад нижче:

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

0

Це дійсно старе питання, але я зрозумів, що опублікую своє рішення щодо цього.

Я намагався використовувати, ResizeSensorоскільки, здавалося, у всіх досить велика пригніченість. Після впровадження, я зрозумів, що під капотом запит елементів вимагає, щоб відповідний елемент мав позицію relativeабо absoluteзастосований до нього, що не працювало для моєї ситуації.

Я закінчив обробляти це за допомогою Rxjs intervalзамість прямої setTimeoutабо requestAnimationFrameподібної попередньої реалізації.

Що добре в спостережуваному ароматі інтервалу, це те, що ви можете змінити потік, однак будь-який інший спостерігається може бути оброблений. Для мене було достатньо базового втілення, але ви могли зійти з розуму і робити всілякі злиття тощо.

У наведеному нижче прикладі я відстежую внутрішні (зелені) зміни ширини дива. Він має ширину, встановлену на 50%, але максимальну ширину - 200 пікселів. Перетягування повзунка впливає на ширину оболонки (сірого) кольору. Ви можете бачити, що спостережуване справляється лише тоді, коли змінюється ширина внутрішнього діва, що відбувається лише в тому випадку, якщо ширина зовнішнього діва менше 400 пікс.

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Існує лише в специфікації, але ви завжди можете використовувати 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...
}

Це вкрай неефективне рішення, якщо у вас є зміни розміру.
suricactus

-1

я думав, що це неможливо зробити, але тоді я подумав про це, ви можете вручну змінити розмір div через style = "resize: obo;" для того, щоб ви попросили натиснути на нього, додали функцію 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>

2
Це обчислюється лише при запуску події натискання, яка не є частиною вимоги запитання.
Роб Еванс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.