Zmień rozmiar elementu DIV

80

jQuery ma resize()zdarzenie -, ale działa tylko z oknem.

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

To działa dobrze! Ale kiedy chcę dodać zdarzenie do elementu div, nie działa.

Na przykład

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

Chcę rozpocząć wywołanie zwrotne, gdy zmieni się rozmiar elementu div. Nie chcę rozpoczynać zdarzenia o zmiennym rozmiarze - po prostu zdarzenia, aby sprawdzić, czy rozmiar elementu div się zmienił.

Czy jest jakieś rozwiązanie, aby to zrobić?

TJR
źródło
2
zdarzenia zmiany rozmiaru są uruchamiane tylko na obiektach okien (i być może ramkach iframe?).
BiAiB
To może pomóc: resizeObserver. developer.mozilla.org/en-US/docs/Web/API/ResizeObserver . Obsługiwane przez Chrome 64, Firefox 69 ...
kapitan puget

Odpowiedzi:

35

DIVnie uruchamia resizezdarzenia, więc nie będziesz w stanie zrobić dokładnie tego, co zakodowałeś, ale możesz przyjrzeć się monitorowaniu właściwości DOM .

Jeśli faktycznie pracujesz z czymś takim jak resizables i jest to jedyny sposób na zmianę rozmiaru elementu div, to Twoja wtyczka do zmiany rozmiaru prawdopodobnie zaimplementuje własne wywołanie zwrotne.

David Hedlund
źródło
Możesz wywołać zdarzenie zmiany rozmiaru okna za pomocą $ (window) .trigger ("resize");
Laurent
32

Interesował mnie tylko wyzwalacz, gdy szerokość elementu została zmieniona (nie obchodzi mnie wysokość), więc stworzyłem zdarzenie jquery, które robi dokładnie to, używając niewidocznego elementu 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);
      };
  }
}

Wymaga następującego CSS:

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

Możesz zobaczyć to w akcji tutaj widthChanged fiddle

Panos Theof
źródło
To jest właściwa odpowiedź. Dołączanie zdarzenia do okna elementu iframe jest znacznie mniej skomplikowane niż interwał.
Kevin Beal
1
To jest doskonałe! Zrobiłem mój całkowicie oparty na js, dodając dynamicznie arkusz stylów: 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
To czysty geniusz.
Thomas
Mam zamiar go użyć, ale zastanawiam się: jaka jest rola timera i setTimeout? czy to jest jak "debounce" / throttle, aby zapobiec wykryciu zbyt wielu zmian rozmiaru, gdy użytkownik zmieni rozmiar elementu?
Mathieu
Tak, ma to na celu zapobieżenie wielokrotnemu wywoływaniu wyzwalacza „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));
Akram Kamal Qassas
źródło
7

Stworzyłem wtyczkę jquery jquery.resize , użyj resizeObserver, jeśli jest obsługiwana, lub rozwiązania opartego na zdarzeniu przewijania marcj / css-element-queries , bez setTimeout / setInterval.

Używasz tylko

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

lub jako wtyczka zmiany rozmiaru

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

Stworzyłem to dla terminala jQuery i rozpakowałem do oddzielnych pakietów repo i npm, ale w międzyczasie przełączyłem się na ukrytą ramkę iframe, ponieważ miałem problemy ze zmianą rozmiaru, jeśli element był wewnątrz iframe. Mogę odpowiednio zaktualizować wtyczkę. Możesz spojrzeć na wtyczkę zmiany rozmiaru opartą na iframe w kodzie źródłowym terminala jQuery .

EDYCJA : nowa wersja używa elementu iframe i zmienia rozmiar obiektu okna, ponieważ poprzednie rozwiązania nie działały, gdy strona znajdowała się wewnątrz elementu iframe.

EDIT2 : Ponieważ element zastępczy używa elementu iframe, którego nie można używać z kontrolkami formularza lub obrazami, należy dodać go do elementu opakowania.

EDIT3:: istnieje lepsze rozwiązanie wykorzystujące polifill resizeObserver, który używa obserwatora mutacji (jeśli resizeObserver nie jest obsługiwany) i działa nawet w IE. Ma również typy TypeScript.

jcubic
źródło
To był świetny pomysł. Dobra robota, naprawdę.
Marco Luzzara
6

a co z tym:

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

Swoją drogą sugeruję dodanie id do div i zmianę $ ("div") na $ ("# yourid"), będzie szybsze i nie zepsuje się, gdy później dodasz inne div

Gavriel
źródło
Oczywiście - to był tylko przykład - oczywiście używam id i klas do wybierania moich elementów. Podoba mi się twój pomysł - myślę, że zadziała! Wielkie dzięki. Spróbuję za kilka minut i przekażę opinię.
TJR,
To monitoruje DIV pod kątem zmian rozmiaru przy każdym uruchomieniu resizezdarzenia okna . Można sobie wyobrazić, że rozmiar elementu div zmieni się bez natychmiastowej zmiany rozmiaru okna, w którym to przypadku /* what ever */część nie zostanie oceniona.
David Hedlund,
Dobrze! I to jest problem w moim projekcie. Element div znajduje się w zewnętrznym opakowaniu, które ma atrybut css Overflow: hidden - dzięki czemu okno nie zmienia rozmiaru. Ale pod innymi względami przykład będzie działał dobrze - właśnie go przetestowałem.
TJR,
@Timo: $(window).resizenasłuchuje czynności fizycznej zmiany rozmiaru okna przeglądarki przez, powiedzmy, przeciągnięcie prawego dolnego rogu. Nie ma żadnych zdarzeń DOM, które wyzwalają to zdarzenie overflow:hiddenlub nie. Ta odpowiedź nie rozwiązuje Twojego problemu. Bardziej sensowne byłoby uruchomienie tego kodu w zegarze niż podłączenie go do nasłuchiwania losowych zdarzeń, które prawdopodobnie nigdy nie zostaną wyzwolone. Byłoby jeszcze lepiej, gdybyś mógł użyć monitorowania właściwości DOM i wrócić do licznika czasu (lub ręcznie wywołać jakieś zdarzenie w miejscach, w których rozmiar div może się zmienić).
David Hedlund,
dodany kod dla setInterval. Musisz to dostroić, ponieważ 1000 ms może być dla ciebie za dużo, z drugiej strony zbyt niska liczba może łatwo zabić procesor. Jeśli wiesz, że nie musisz już słuchać, zadzwoń: clearInterval (timer)!
Gavriel
5

Jest naprawdę fajna, łatwa w użyciu, lekka (wykorzystuje natywne zdarzenia przeglądarki do wykrywania) wtyczka zarówno dla podstawowego JavaScript, jak i dla jQuery, która została wydana w tym roku. Działa doskonale:

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

DrCord
źródło
1
powiedziałeś, że nie sonduje stale, ale tak, używa requestAnimationFrame: github.com/sdecima/javascript-detect-element-resize/blob/master/…
Muhammad Umer
1
Interesujące: wspomniany projekt GitHub został zainspirowany tym wpisem na blogu: backalleycoder.com/2013/03/18/… Ale kod w poście został później znacznie zmieniony, podczas gdy projekt GitHub wydaje się wykorzystywać starsze podejście. Warto więc przyjrzeć się obu, zanim zdecydujesz, czego użyć.
CF
2

Obsługiwane jest tylko okno tak, ale możesz użyć do niego wtyczki: http://benalman.com/projects/jquery-resize-plugin/

Nielsen Ramon
źródło
1
Nie. Właśnie tego próbował OP i wskazał, że to nie działa.
David Hedlund,
to użycie setTimeout, które może być dość drogie, jeśli używasz tego wiele razy.
jcubic
0

W przypadku integracji map Google szukałem sposobu na wykrycie, kiedy zmienił się rozmiar elementu div. Ponieważ mapy google zawsze wymagają odpowiednich wymiarów, np. Szerokości i wysokości, aby poprawnie renderować.

Rozwiązanie, które wymyśliłem, to delegacja wydarzenia, w moim przypadku kliknięcie karty. Może to być oczywiście zmiana rozmiaru okna, idea pozostaje ta sama:

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.mapw tym przypadku jest mój div mapy. Ponieważ mój rodzic jest niewidoczny podczas ładowania, obliczona szerokość i wysokość są równe 0 lub nie są zgodne. Używając .bind(this)mogę delegować wykonywanie skryptu ( this.activate) do zdarzenia ( click).

Teraz jestem pewien, że to samo dotyczy wydarzeń związanych ze zmianą rozmiaru.

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

Mam nadzieję, że to pomoże każdemu!

Tim Vermaelen
źródło
0

Po prostu wypróbuj tę funkcję (może działać nie tylko w przypadku elementów 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);
}

Możesz tego używać w ten sposób

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"!']);

AKTUALIZACJA: Możesz także użyć bardziej progresywnego obserwatora (może działać dla dowolnych obiektów, nie tylko elementów 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);
    }

Po prostu spróbuj:

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ędzie rejestrował 'zmianę' za każdym razem, gdy bezpośrednio zmienisz b, a.foo lub a.ext

KaMeHb
źródło
setIntervalmoże stać się dość drogi, ponieważ ciągle próbuje zmienić rozmiar
ton
@ton: Myślę, że nie masz pełnej racji. Dzieje się tak tylko w przypadku próby zmiany rozmiaru elementu podczas zmiany rozmiaru. : / A może martwisz się o wydajność? W najnowszych przeglądarkach działa idealnie nawet na „ciężkich” stronach
KaMeHb,
Jeśli dodasz prosty console.logtuż przed $.each, zobaczysz, że będzie on drukowany co 100ms, tak jak ustawiłeśinterval
ton
@ton: Źle mnie zrozumiałeś. Wiem dobrze, jak setIntervaldziała. To jak e-mail „żywy” - ciągle pinguje serwer. Wiem to. I co? Wydajność? Przeczytaj mój komentarz powyżej. Martwisz się o coś innego? Napisz do mnie, przyjacielu.
KaMeHb,
0

Możesz zmienić swój tekst, Treść lub Atrybut w zależności od rozmiaru ekranu: 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>
Amranur Rahman
źródło
-2

Jeśli chcesz zmienić rozmiar samego div, musisz to określić w stylu css. Musisz dodać przepełnienie i zmienić rozmiar właściwości .

Poniżej znajduje się mój fragment kodu

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

<div id="div1">

</div>
Dillip Kumar Nayak
źródło
Ta odpowiedź nie dotyczy oryginalnego posta. Szeroka dyskusja tutaj dotyczy nasłuchiwania zmian rozmiaru elementu (i późniejszego wykonywania akcji), a nie ustalania rozmiaru elementu.
MarsAndBack