Змінити розмір елемента div


80

jQuery має resize()подію -, але вона просто працює з вікном.

jQuery(window).resize(function() { /* What ever */ });

Це чудово працює! Але коли я хочу додати подію до елемента div, це не працює.

Напр

jQuery('div').resize(function() { /* What ever */ });

Я хочу розпочати зворотний виклик, коли розмір елемента div змінився. Я не хочу запускати змінну - подію - просто подію, щоб перевірити, чи змінився розмір елемента div -.

Чи є якесь рішення для цього?


2
події зміни розміру спрацьовують лише для об’єктів вікна (ок) (а iframes можливо?).
BiAiB

3
подивіться на цю сторінку - benalman.com/code/projects/jquery-resize/examples/resize
Елен

Це може допомогти: resizeObserver. developer.mozilla.org/en-US/docs/Web/API/ResizeObserver . Підтримується Chrome 64, Firefox 69 ...
капітан Пьюджет

Відповіді:


35

DIVне запускає resizeподію, тому ви не зможете робити саме те, що закодували, але ви можете вивчити властивості DOM .

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


Ви можете запустити подію зміни вікна за допомогою $ (window) .trigger ("resize");
Лоран,

32

Мене зацікавив тригер лише тоді, коли була змінена ширина елемента (мене не хвилює висота), тому я створив подію jquery, яка робить саме це, використовуючи невидимий елемент iframe.

$.event.special.widthChanged = {
  remove: function() {
      $(this).children('iframe.width-changed').remove();
  },
  add: function () {
      var elm = $(this);
      var iframe = elm.children('iframe.width-changed');
      if (!iframe.length) {
          iframe = $('<iframe/>').addClass('width-changed').prependTo(this);
      }
      var oldWidth = elm.width();
      function elmResized() {
          var width = elm.width();
          if (oldWidth != width) {
              elm.trigger('widthChanged', [width, oldWidth]);
              oldWidth = width;
          }
      }

      var timer = 0;
      var ielm = iframe[0];
      (ielm.contentWindow || ielm).onresize = function() {
          clearTimeout(timer);
          timer = setTimeout(elmResized, 20);
      };
  }
}

Для цього потрібен такий css:

iframe.width-changed {
    width: 100%;
    display: block;
    border: 0;
    height: 0;
    margin: 0;
}

Ви можете побачити це в дії тут widthChanged скрипка


Це правильна відповідь. Приєднання події до вікна iframe набагато менше, ніж інтервал.
Kevin Beal

1
Це ідеально! Я зробив свій повністю js на основі додавання таблиці стилів динамічно: var ss = document.createElement('style'); ss.type = "text/css"; ss.innerHTML = "iframe.width-changed {width: 100%;display: block;border: 0;height: 0;margin: 0;}"; document.body.appendChild(ss);
sroskelley

Це чистий геній.
Томас

Я збираюся використати його, але мені цікаво: яка роль таймера і setTimeout? це як "розрив" / дросель, щоб запобігти виявленню забагато розміру, коли користувач змінює розмір елемента?
Матьє

Так, це для запобігання надто багато разів викликати тригер "widthChanged"
Panos Theof

22
// this is a Jquery plugin function that fires an event when the size of an element is changed
// usage: $().sizeChanged(function(){})

(function ($) {

$.fn.sizeChanged = function (handleFunction) {
    var element = this;
    var lastWidth = element.width();
    var lastHeight = element.height();

    setInterval(function () {
        if (lastWidth === element.width()&&lastHeight === element.height())
            return;
        if (typeof (handleFunction) == 'function') {
            handleFunction({ width: lastWidth, height: lastHeight },
                           { width: element.width(), height: element.height() });
            lastWidth = element.width();
            lastHeight = element.height();
        }
    }, 100);


    return element;
};

}(jQuery));

7

Я створив плагін jquery jquery.resize, він використовує resizeObserver, якщо підтримується або рішення базується на події прокрутки marcj / css-element-queries , без setTimeout / setInterval.

Ви використовуєте просто

 jQuery('div').on('resize', function() { /* What ever */ });

або як плагін Resizer

jQuery('div').resizer(function() { /* What ever */ });

Я створив це для jQuery Terminal і витягнув його в окремий пакет repo та npm, але тим часом я перейшов на прихований iframe, оскільки мав проблеми зі зміною розміру, якщо елемент знаходився всередині iframe. Я можу відповідно оновити плагін. Ви можете подивитися плагін для зміни розміру на основі iframe у вихідному коді jQuery Terminal .

РЕДАГУВАТИ : нова версія використовує iframe та змінює розмір його віконного об’єкта, оскільки попередні рішення не працювали, коли сторінка знаходилася всередині iframe.

РЕДАКТУВАТИ2 : Оскільки резервний варіант використовує iframe, ви не можете використовувати його з елементами керування формою або зображеннями, вам потрібно додати його до елемента обгортки.

EDIT3:: є краще рішення з використанням полізаповнення resizeObserver, яке використовує спостерігач мутацій (якщо resizeObserver не підтримується) і працює навіть в IE. Він також має типирування TypeScript.


Це була чудова ідея. Хороша робота, справді.
Марко Луццара,

6

як що до цього:

divH = divW = 0;
jQuery(document).ready(function(){
    divW = jQuery("div").width();
    divH = jQuery("div").height();
});
function checkResize(){
    var w = jQuery("div").width();
    var h = jQuery("div").height();
    if (w != divW || h != divH) {
        /*what ever*/
        divH = h;
        divW = w;
    }
}
jQuery(window).resize(checkResize);
var timer = setInterval(checkResize, 1000);

До речі, я пропоную вам додати ідентифікатор до div і змінити $ ("div") на $ ("# yourid"), це буде швидше, і воно не зламається, коли пізніше ви додасте інші div


Звичайно - це був лише приклад - звичайно, я використовую ідентифікатори та класи для вибору своїх елементів. Мені подобається ваша ідея - я думаю, вона б спрацювала! Дуже дякую. Я спробую за кілька хвилин і дам відгук.
TJR

Це контролює зміну розміру DIV щоразу, коли запускається resizeподія вікна . Цілком можливо, що розмір div зміниться, не відразу після зміни розміру вікна, і в цьому випадку /* what ever */частина не буде оцінена.
Девід Хедлунд,

Правильно! І в цьому проблема мого проекту. Елемент div знаходиться у зовнішній обгортці, яка має атрибут css Overflow: hidden - отже вікно не змінює розмір. Але в інших випадках приклад буде працювати нормально - я щойно перевірив його.
TJR

@Timo: $(window).resizeслухає акт фізичного зміни розміру вікна браузера, скажімо, перетягуючи нижній правий кут. Немає жодних подій DOM, які б викликали цю подію overflow:hiddenчи ні. Ця відповідь не стосується вашої проблеми. Це має більше сенсу запускати цей код за таймером, ніж приєднаний до випадкового прослуховувача подій, який, ймовірно, ніколи не буде спрацьовувати. Було б все-таки краще, якби ви могли використовувати моніторинг властивостей DOM і повернутися до таймера (або вручну підняти якусь подію в місцях, де розмір div може змінюватися).
Девід Хедлунд,

доданий код для setInterval. Вам потрібно його точно налаштувати, оскільки 1000 мс може бути для вас занадто багато, з іншого боку, занадто низька кількість може легко вбити ваш процесор. Якщо ви знаєте, що більше слухати не потрібно, тоді телефонуйте: clearInterval (таймер)!
Gavriel

5

Існує справді приємний, простий у використанні, легкий (використовує власні події браузера для виявлення) плагін як для базового JavaScript, так і для jQuery, який був випущений цього року. Він чудово працює:

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


1
ви сказали, що не опитуєте
Мухаммад Умер

1
Цікаво: посилання на проект GitHub було натхнене цим повідомленням у блозі: backalleycoder.com/2013/03/18/… Але код у дописі суттєво змінився пізніше, тоді як проект GitHub, схоже, використовує старий підхід. Тож варто поглянути на обидва, перш ніж вирішити, що використовувати.
CF

2

Так, підтримується лише вікно, але для нього ви можете використовувати плагін: http://benalman.com/projects/jquery-resize-plugin/


1
Ні. Це саме те, що OP спробував, і зазначив, що це не працює.
Девід Хедлунд

це використовує setTimeout, що може бути досить дорогим, якщо ви використовуєте це кілька разів.
jcubic

0

Для інтеграції карт Google я шукав спосіб виявити, коли div змінився в розмірі. Оскільки карти Google завжди вимагають належних розмірів, наприклад, ширини та висоти, щоб правильно відображати їх.

Рішення, яке я придумав, - це делегування події, у моєму випадку клацніть вкладку. Звичайно, це може бути зміна розміру вікна, ідея залишається незмінною:

if (parent.is(':visible')) {
    w = parent.outerWidth(false);
    h = w * mapRatio /*9/16*/;
    this.map.css({ width: w, height: h });
} else {
    this.map.closest('.tab').one('click', function() {
        this.activate();
    }.bind(this));
}

this.mapу цьому випадку це мій div div. Оскільки мій батько невидимий при навантаженні, обчислені ширина та висота дорівнюють 0 або не збігаються. За допомогою .bind(this)я можу делегувати виконання сценарію ( this.activate) події (click ).

Зараз я впевнений, що те саме стосується подій зі зміною розміру.

$(window).one('resize', function() {
    this.div.css({ /*whatever*/ });
}.bind(this));

Сподіваюся, це комусь допоможе!


0

Просто спробуйте цей функціонал (він може працювати не лише для div):

function resized(elem, func = function(){}, args = []){
    elem = jQuery(elem);
    func = func.bind(elem);
    var h = -1, w = -1;
    setInterval(function(){
        if (elem.height() != h || elem.width() != w){
            h = elem.height();
            w = elem.width();
            func.apply(null, args);
        }
    }, 100);
}

Ви можете використовувати його так

resized(/*element*/ '.advs-columns-main > div > div', /*callback*/ function(a){
    console.log(a);
    console.log(this); //for accessing the jQuery element you passed
}, /*callback arguments in array*/ ['I\'m the first arg named "a"!']);

ОНОВЛЕННЯ: Ви також можете використовувати більш прогресивний спостерігач (він може працювати для будь-яких об'єктів, а не тільки елементів DOM):

function changed(elem, propsToBeChanged, func = function(){}, args = [], interval = 100){
        func = func.bind(elem);
        var currentVal = {call: {}, std: {}};
        $.each(propsToBeChanged, (property, needCall)=>{
            needCall = needCall ? 'call' : 'std';
            currentVal[needCall][property] = new Boolean(); // is a minimal and unique value, its equivalent comparsion with each other will always return false
        });
        setInterval(function(){
            $.each(propsToBeChanged, (property, needCall)=>{
                try{
                    var currVal = needCall ? elem[property]() : elem[property];
                } catch (e){ // elem[property] is not a function anymore
                    var currVal = elem[property];
                    needCall = false;
                    propsToBeChanged[property] = false;
                }
                needCall = needCall ? 'call' : 'std';
                if (currVal !== currentVal[needCall][property]){
                    currentVal[needCall][property] = currVal;
                    func.apply(null, args);
                }
            });
        }, interval);
    }

Просто спробуйте:

var b = '2',
    a = {foo: 'bar', ext: ()=>{return b}};
changed(a, {
// prop name || do eval like a function?
    foo:        false,
    ext:        true
}, ()=>{console.log('changed')})

Він реєструватиметься "змінено" кожного разу, коли ви безпосередньо змінюєте b, a.foo або a.ext


setIntervalможе стати досить дорогим, оскільки він продовжує намагатись змінити розмір
тонна

@ton: Я думаю, ви не повністю праві. Це відбувається лише у випадку спроби змінити розмір елемента в той час, як він змінив розмір. : / Або вас турбує продуктивність? У найновіших браузерах він чудово працює навіть на "важких" сайтах
KaMeHb

Якщо ви додасте простий console.logбезпосередньо перед $.each, ви побачите, що він друкується кожен 100ms, як ви встановили вinterval
тоні

@ton: Ви неправильно мене зрозуміли. Я добре знаю, як це setIntervalпрацює. Це як "живий" електронний лист - постійно пінгує сервер. Я це знаю. І що? Продуктивність? Прочитайте мій коментар вище. Переживає щось інше? Напиши мені, друже.
KaMeHb

0

Ви можете змінити текст, вміст або атрибут залежно від розміру екрана: HTML:

<p class="change">Frequently Asked Questions (FAQ)</p>
<p class="change">Frequently Asked Questions </p>

Javascript:

<script>
const changeText = document.querySelector('.change');
function resize() {
  if((window.innerWidth<500)&&(changeText.textContent="Frequently Asked Questions (FAQ)")){
    changeText.textContent="FAQ";
  } else {
    changeText.textContent="Frequently Asked Questions (FAQ)";
  }
}
window.onresize = resize;
</script>

-2

Якщо ви просто хочете змінити розмір самого div, вам потрібно вказати це у стилі css. Вам потрібно додати властивість переповнення та зміни розміру .

Нижче мій фрагмент коду

#div1 {
        width: 90%;
        height: 350px;
        padding: 10px;
        border: 1px solid #aaaaaa;
        overflow: auto;
        resize: both;
    }

<div id="div1">

</div>

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