Изменить размер элемента div

80

В jQuery есть resize()событие -, но он работает только с окном.

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

Это прекрасно работает! Но когда я хочу добавить событие в элемент div, это не работает.

Например

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

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

Есть какое-нибудь решение для этого?

TJR
источник
2
События изменения размера запускаются только для объектов окна (ов) (и, возможно, фреймов?).
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 fiddle

Панос Теоф
источник
Это правильный ответ. Прикрепить событие к окну iframe гораздо проще, чем интервал.
Кевин Бил
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
Это чистый гений.
Thomas
Я собираюсь использовать его, но мне интересно: какова роль таймера и setTimeout? это что-то вроде «дребезга» / дросселирования, чтобы предотвратить слишком большое изменение размера, которое может быть обнаружено, когда пользователь изменяет размер элемента?
Mathieu
Да, это сделано для предотвращения слишком частого вызова триггера widthChanged
Панос Теоф
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-query , без setTimeout / setInterval.

Вы используете только

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

или как плагин изменения размера

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

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

РЕДАКТИРОВАТЬ : новая версия использует iframe и изменяет размер объекта окна, потому что предыдущие решения не работали, когда страница находилась внутри iframe.

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

EDIT3:: есть лучшее решение с использованием полифилла resizeObserver, который использует наблюдатель мутаций (если resizeObserver не поддерживается) и работает даже в IE. Он также имеет типизацию TypeScript.

jcubic
источник
Это была отличная идея. Хорошая работа, правда.
Марко
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 (timer)!
Гавриил
5

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

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

DrCord
источник
1
вы сказали, что он не опрашивает постоянно, но он использует requestAnimationFrame: github.com/sdecima/javascript-detect-element-resize/blob/master/…
Мухаммад Умер
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. Поскольку мой родитель невидим при загрузке, вычисленные ширина и высота равны 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.

KaMeHb
источник
setIntervalможет стать довольно дорогим, так как он продолжает попытки изменить размер
тон
@ton: Я думаю, вы не совсем правы. Это происходит только в случае попытки изменить размер элемента во время его изменения. : / Или вас беспокоит производительность? В последних
версиях
Если вы добавите простой как 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