Come rilevare la dimensione DIV è cambiata?


351

Ho il seguente esempio HTML, c'è un DIV che ha una larghezza del 100%. Contiene alcuni elementi. Durante l'esecuzione del ridimensionamento delle finestre, gli elementi interni possono essere riposizionati e la dimensione del div può cambiare. Sto chiedendo se è possibile agganciare l'evento di cambio dimensione del div? e come farlo? Attualmente associo la funzione di callback all'evento di ridimensionamento jQuery sul DIV di destinazione, tuttavia, non viene emesso alcun registro della console, vedere di seguito:

Prima di ridimensionare inserisci qui la descrizione dell'immagine

<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
Questo non funzionerà perché stai vincolando l'evento di ridimensionamento all'elemento div specificato. Ma l'evento di ridimensionamento si attiverà per la finestra non per il tuo elemento.
Fatih Acet,

Puoi usare setIntervalqui come possibile soluzione. Puoi sempre associare clearIntervalun clic del pulsante per interrompere il ciclo al termine del lavoro.
Peter Darmis,

1
Dal 2020, ResizeObserver funziona in tutti i principali browser (Chrome, Safari, Firefox, Edge) tranne IE. caniuse.com/#feat=resizeobserver
Dan

Risposte:


264

Esiste un metodo molto efficiente per determinare se la dimensione di un elemento è stata modificata.

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

Questa libreria ha una classe ResizeSensorche può essere utilizzata per il rilevamento del ridimensionamento.
Utilizza un approccio basato sugli eventi, quindi è dannatamente veloce e non fa perdere tempo alla CPU.

Esempio:

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

Non utilizzare il plug-in onresize jQuery in quanto utilizzato setTimeout()in combinazione con la lettura di DOM clientHeight/ clientWidthproprietà in un ciclo per verificare le modifiche.
Questo è incredibilmente lento e impreciso poiché provoca il thrashing del layout .

Divulgazione: sono direttamente associato a questa biblioteca.


8
@jake, il supporto IE11 è ora implementato.
Marc J. Schmidt,

15
@Aletheios dovresti dare un'occhiata più da vicino. requestAnimationFrame non è per il rilevamento di dimensioni lente ma esattamente il contrario: attenua tutti quei numeri estremi di eventi che vengono attivati ​​dal sensore di ridimensionamento basato su eventi reali per risparmiare tempo di CPU. Consulta i documenti aggiornati su github.com/marcj/css-element-queries/blob/master/src/…
Marc J. Schmidt

6
@Aletheios Immagino che ti perda un punto: setTimeout non è solo impreciso ma lento come l'inferno. Un requestAnimationFrame che controlla un semplice valore booleano è ordini di grandezza più veloci di un setTimeout che controlla continuamente le proprietà DOM. Inoltre, setTimeout viene anche chiamato ogni pochi millisecondi.
Marc J. Schmidt,

9
@Orwellophile ovviamente non hai capito niente. Smetti di effettuare il downvoting delle risposte dove non hai idea di come funzioni internamente. Ancora una volta: css-element-query: utilizza un evento di ridimensionamento reale che viene attivato ogni volta che la dimensione cambia. Dato che avresti troppi eventi (ad esempio per il drag'n'drop), ha aggiunto requestAnimationFrame che controlla una semplice variabile booleana per smussare quegli eventi attivati ​​fino a 1 / frame. plugin jquery: utilizza un setTimeout che controlla continuamente puntelli di layout DOM (clientHeight ecc.) in cui ogni controllo è molto lento ma deve essere controllato spesso per avere la stessa funzionalità.
Marc J. Schmidt,

9
@Aletheios, @Orwellophile e chiunque possa essere stato fuorviato da loro: requestAnimationFramevs setTimeoutè irrilevante, questa libreria non esegue il loop . requestAnimationFrameviene utilizzato solo per rimbalzare / limitare la frequenza di chiamata dei callback, non esegue il polling . MutationObserver potrebbe teoricamente essere usato per effetti simili ma non nei browser più vecchi, diversamente da questo. Questo è straordinariamente intelligente.
Han Seoul-Oh,

251

Un nuovo standard per questo è l'API Resize Observer, disponibile in 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>

Ridimensiona osservatore

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

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

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

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

Supporto attuale: http://caniuse.com/#feat=resizeobserver


3
non ancora utile per i siti di produzione, poiché al momento solo Chrome lo supporta. Ma sicuramente la migliore soluzione qui! a proposito, ecco una rapida panoramica dello stato dell'implementazione: chromestatus.com/feature/5705346022637568
Philipp

8
@Philipp C'è un polyfill.
Daniel Herr,

2
Sembra che sia ancora una funzionalità sperimentale in tutti i browser caniuse.com/#feat=resizeobserver
Francesc Rosas

5
Anche 2 anni dopo questa risposta, il supporto del browser è desolante: caniuse.com/#search=resizeobserver
Scrimothy

2
Funziona come un fascino negli ultimi Chrome e FF.
Klemen Tušar,

32

Devi associare l' resizeevento windowsull'oggetto, non su un elemento html generico.

È quindi possibile utilizzare questo:

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

e all'interno della funzione di richiamata è possibile verificare la nuova larghezza della divchiamata

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

Quindi, la risposta alla tua domanda è no , non puoi associare l' resizeevento a un div.


124
questa risposta non è abbastanza buona. le modifiche alle dimensioni potrebbero verificarsi senza QUALSIASI ridimensionamento della finestra. affatto.
vsync,

9
ad esempio quando si dispone di un elemento splitter o si aggiunge semplicemente un testo o altro contenuto a un elemento.
Günter Zöchbauer,

@anu non è vero, puoi ad es. modificare DOM tramite javascript facendo sì che CSS si applichi a una nuova struttura con conseguente layout diverso - dimensioni di ogni contenitore.
Antoniossss,

29

A lungo termine, sarai in grado di utilizzare ResizeObserver .

new ResizeObserver(callback).observe(element);

Purtroppo al momento non è supportato per impostazione predefinita in molti browser.

Nel frattempo, è possibile utilizzare la funzione come la seguente. Da allora, la maggior parte delle modifiche alle dimensioni dell'elemento provengono dal ridimensionamento della finestra o dalla modifica di qualcosa nel DOM. Puoi ascoltare il ridimensionamento della finestra con l' evento di ridimensionamento della finestra e puoi ascoltare le modifiche al DOM usando MutationObserver .

Ecco un esempio di una funzione che ti richiamerà quando la dimensione dell'elemento fornito cambia a seguito di uno di questi eventi:

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
Sfortunatamente, sembra che MutationObserver non sia in grado di rilevare le modifiche in Shadow DOM.
Ajedi32,

@nkron, Sfortunatamente, se usi il ridimensionamento CSS3 , il ridimensionamento può avvenire quando l'utente ridimensiona manualmente. Questo evento non può essere colto.
Pacerier,

@ Ajedi32 Sì, ma è possibile utilizzare MutationObserver all'interno di ShadowDOM. Quello che voglio dire, invece di guardare bodycome in questo esempio, puoi guardare direttamente un elemento. Questo è in realtà più performante ed efficiente che guardare tutto il corpo.
trusktr,

@ Ajedi32 Bene, l'unico problema è che se l'albero del DOM dell'ombra è chiuso, allora non sarai in grado di accedere agli interni, ma non penso che di solito sia qualcosa che devi fare e se devi osservare un albero chiuso come quello, quindi potrebbe esserci un problema nella progettazione. Idealmente, dovresti solo osservare i tuoi elementi a cui hai accesso. Un componente Shadow-DOM che richiede di osservare il dimensionamento interno potrebbe non essere progettato correttamente. Hai un esempio specifico? Se è così, forse posso aiutarti a suggerire una soluzione (perché sono interessato anche a me, ma non ho ancora un esempio).
trusktr,

@trusktr Al momento non ho un MCVE, ma praticamente qualsiasi elemento Shadow DOM che può cambiare le sue dimensioni come risultato di alcuni input dell'utente sarebbe sufficiente per innescare questo problema. Una casella che si espande con alcune informazioni aggiuntive quando si fa clic, ad esempio. Nota che sto osservando la pagina, non il singolo elemento, perché voglio scorrere automaticamente verso il basso quando le dimensioni della pagina aumentano, indipendentemente dal motivo. L'espansione di un elemento DOM Shadow è solo uno dei tanti motivi per cui la pagina potrebbe allungarsi.
Ajedi32

24

ResizeSensor.js fa parte di una vasta libreria, ma ho ridotto la sua funzionalità a QUESTO :

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

Come usarlo:

let container = document.querySelector(".container");
new ResizeSensor(container, function()
{
    console.log("dimension changed:", container.clientWidth, container.clientHeight);
});

Questo è ciò che fanno i grafici js.
Antoniossss,

Grazie per averlo compresso. Ho intenzione di provarlo :)
Tony K.

C'è qualcosa che manca in questa espressioneparseInt( getComputedStyle(element) )
GetFree

2
Sono confuso come è "let zIndex = parseInt (getComputedStyle (element));" valido? Suppongo che intendevi: "let zIndex = parseInt (getComputedStyle (element) .zIndex);
Ryan Badour

1
La soluzione / codice sopra non rileva tutti gli eventi di ridimensionamento (ad es. Se un contenitore viene ridimensionato in modo fisso con esso non rileva il ridimensionamento per eventi figlio. Vedere jsfiddle.net/8md2rfsy/1 ). La risposta accettata funziona (decommenta le rispettive righe).
newBee,

21

NON raccomando l' setTimeout()hacking in quanto rallenta le prestazioni! Al contrario, è possibile utilizzare osservatori di mutazioni DOM per ascoltare la modifica della dimensione 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>

Ecco il violino
Prova a cambiare la dimensione del div.


È possibile avvolgere ulteriormente il metodo nel debouncemetodo per migliorare l'efficienza. debounceattiverà il tuo metodo ogni x millisecondi invece di innescare ogni millisecondo in cui il DIV viene ridimensionato.


9
L'unico problema con questo è che non segnala un cambiamento a meno che all'elemento non si verifichi una mutazione. Se l'elemento viene ridimensionato a causa dell'aggiunta di altri elementi, questo non funzionerà.
Tony K.

Sono d'accordo con @TonyK., Questo è il mio unico problema con MutationObserver e ora sto cercando una libreria di ridimensionamento degli elementi
Murhaf Sousli

@JerryGoyal Non funziona quando il div contiene il tag <img>. Nel primo caso l'immagine non viene caricata e la dimensione div viene impostata su 0 e dopo il caricamento viene modificata la dimensione div, ma l'osservatore non viene attivato
Santhosh

15

La soluzione migliore sarebbe quella di utilizzare le cosiddette Element Query . Tuttavia, non sono standard, non esistono specifiche - e l'unica opzione è quella di utilizzare uno dei polyfill / librerie disponibili, se si desidera procedere in questo modo.

L'idea alla base delle query sugli elementi è consentire a un determinato contenitore nella pagina di rispondere allo spazio che gli è stato fornito. Ciò consentirà di scrivere un componente una volta e quindi rilasciarlo in qualsiasi punto della pagina, mentre adatterà il suo contenuto alle dimensioni correnti. Non importa quale sia la dimensione della finestra. Questa è la prima differenza che vediamo tra le query degli elementi e le query multimediali. Tutti sperano che a un certo punto venga creata una specifica che standardizzi le query degli elementi (o qualcosa che raggiunga lo stesso obiettivo) e le rendano native, pulite, semplici e robuste. Molte persone concordano sul fatto che le query multimediali sono piuttosto limitate e non aiutano per la progettazione modulare e la reattività reale.

Ci sono alcuni polyfill / librerie che risolvono il problema in diversi modi (potrebbe essere chiamato soluzioni alternative invece di soluzioni):

Ho visto altre soluzioni a problemi simili proposti. Di solito usano i timer o le dimensioni della finestra / finestra sotto il cofano, che non è una vera soluzione. Inoltre, penso che idealmente questo dovrebbe essere risolto principalmente in CSS e non in javascript o html.


+1 per le query sugli elementi, ma non spero di vederle presto. Non c'è nemmeno una bozza di specifiche a questo punto AFAIK ... forse una di noi parti interessate dovrebbe metterne insieme una e inviarla?
Rob Evans,

1
Questa è una buona idea ovviamente. Ci vorrà molto tempo per arrivare a una versione finale, molta attenzione deve essere attirata. Progettare questo in un buon modo non mi sembra banale. Compatibilità tra browser, dipendenze circolari, debug, leggibilità e manutenzione, ecc. Cominciamo il prima possibile :)
Stan

@Stan, penso che questa risposta possa essere migliore aggiungendo ulteriori elaborazioni su cosa sia Element Query.
Pacerier,

15

Ho trovato questa libreria funzionante quando la soluzione di MarcJ non ha funzionato:

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

È molto leggero e rileva anche i ridimensionamenti naturali tramite CSS o semplicemente il caricamento / rendering HTML.

Esempio di codice (tratto dal collegamento):

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

Questo è. 147 righe, utilizza gli eventi di scorrimento. Leggi questo codice se desideri la risposta completa e vera su come rilevare meglio le modifiche alle dimensioni div. Suggerimento: non è "usa questa libreria".
Seph Reed,

1
Le persone dovrebbero dare un'occhiata a questo problema prima di provare questa libreria.
Louis,

13

Dai un'occhiata a questo http://benalman.com/code/projects/jquery-resize/examples/resize/

Ha vari esempi. Prova a ridimensionare la finestra e guarda come si sono adattati gli elementi all'interno degli elementi contenitore.

Esempio con js fiddle per spiegare come farlo funzionare.
Dai un'occhiata a questo violino http://jsfiddle.net/sgsqJ/4/

In questo evento resize () è associato a un elemento con classe "test" e anche all'oggetto window e nel callback di ridimensionamento dell'oggetto window $ ('. Test') viene chiamato resize ().

per esempio

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

$(window).resize(function(){
   $('#test_div').resize();
});

Interessante. Quel jsfiddle si blocca costantemente in Chrome con l'ispettore è aperto e faccio clic sul link "Aggiungi altro testo". Firefox genera errori "troppa ricorsione".
EricP,

3
Non utilizzare il plug-in di ridimensionamento di jQuery. È davvero lento e non preciso. Vedi la mia risposta per ottenere una soluzione migliore.
Marc J. Schmidt,

24
Questo NON rileva direttamente i cambiamenti di dimensione. è solo un sottoprodotto di un listener di eventi di ridimensionamento. un cambiamento di dimensione può avvenire in molti altri modi.
vsync,

4
Cosa succede se il ridimensionamento del div deriva dal cambiamento di stile o dom e non dal ridimensionamento della finestra?
timore del

9

È possibile utilizzare iframeo objectutilizzare contentWindowo contentDocumentsul ridimensionamento. Senza setIntervalosetTimeout

I passi:

  1. Imposta la posizione del tuo elemento su relative
  2. Aggiungi all'interno di un IFRAME nascosto assoluto trasparente
  3. Ascolta IFRAME.contentWindow- onresizeevento

Un esempio di 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>

Il 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')
})

Esempio in esecuzione

JsFiddle: https://jsfiddle.net/qq8p470d/


Vedi altro:


1
Una nota per coloro che non usano jquery, IFRAME.contentWindownon è disponibile fino a quando l' onloadevento non viene generato sull'iframe. Inoltre, potresti voler aggiungere lo stile visibility:hidden;, poiché l'iframe può bloccare l'input del mouse sugli elementi dietro di esso (almeno sembra "fluttuare" in IE).
James Wilkins,

3
Sebbene funzioni, si tratta di una soluzione pesante con il sovraccarico di creare un contesto di navigazione completamente nuovo solo per osservare la modifica delle dimensioni. Inoltre, in alcuni casi non è l'ideale o fattibile modificare la displayproprietà dell'elemento.
trusktr,

concordato, questa è una soluzione terribile come detto sopra
29er

Come ha scritto una soluzione così terribile?
Aminadav Glickshtein,

questo metodo funziona bene con lettori video e lettori audio che richiedono un ridimensionamento dinamico del contenuto. Sto usando questo metodo per ridimensionare l'output di wavesurfer.js.
David Clews,

8

Solo l'oggetto window genera un evento "ridimensiona". L'unico modo che conosco per fare quello che vuoi fare è eseguire un timer intervallo che controlla periodicamente le dimensioni.


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

Incredibilmente vecchio come questo problema, questo è ancora un problema nella maggior parte dei browser.

Come altri hanno già detto, Chrome 64+ ora viene fornito con Resize Observes in modo nativo, tuttavia, le specifiche sono ancora in fase di perfezionamento e Chrome è attualmente (dal 29-01-2019) dietro l'ultima edizione delle specifiche .

Ho visto un paio di buoni polifillamenti ResizeObserver in natura, tuttavia alcuni non seguono da vicino le specifiche che altri hanno problemi di calcolo.

Avevo un disperato bisogno di questo comportamento per creare alcuni componenti Web reattivi che potessero essere utilizzati in qualsiasi applicazione. Per farli funzionare bene devono conoscere le loro dimensioni in ogni momento, quindi ResizeObservers sembrava l'ideale e ho deciso di creare un polyfill che seguisse le specifiche il più vicino possibile.

Repo: https://github.com/juggle/resize-observer

Demo: https://codesandbox.io/s/myqzvpmmy9


Questa è sicuramente la risposta assillata per chiunque abbia a che fare con IE11 + compatibilità del browser.
ekfuhrmann,

3

Utilizzando Clay.js ( https://github.com/zzarcon/clay ) è abbastanza semplice rilevare le modifiche sulla dimensione dell'elemento:

var el = new Clay('.element');

el.on('resize', function(size) {
    console.log(size.height, size.width);
});

7
Fornisci la divulgazione appropriata dato che si tratta della tua biblioteca.
jhpratt GOFUNDME RELICENSING

Questo ha funzionato per me, dove ResizeSensor no, rompe il mio stile modale. Grazie Zzarcon :)
Máxima Alekz,

3

Questo post sul blog mi ha aiutato a rilevare in modo efficiente le modifiche alle dimensioni degli elementi DOM.

http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/

Come usare questo codice ...

AppConfig.addResizeListener(document.getElementById('id'), function () {
  //Your code to execute on resize.
});

Codice impacchettato utilizzato nell'esempio ...

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__);
            }
        }
    }
})();

Nota: AppConfig è uno spazio dei nomi / oggetto che utilizzo per l'organizzazione di funzioni riutilizzabili. Sentiti libero di cercare e sostituire il nome con qualsiasi cosa tu voglia.


3

Il mio plugin jQuery abilita l'evento "ridimensiona" su tutti gli elementi, non solo su window.

https://github.com/dustinpoissant/ResizeTriggering

$("#myElement") .resizeTriggering().on("resize", function(e){
  // Code to handle resize
}); 

1
Il tuo link puntava a una posizione che non esiste più. Ho cercato il nome del plugin e ho trovato una pagina che corrisponde alla tua descrizione. Dato che sembri essere l'autore del plugin, ho anche modificato la lingua della tua risposta per rendere esplicito che questo è il tuo lavoro. Le regole di questo sito sono tali che quando scrivi le risposte consiglia di usare qualcosa che hai sviluppato devi rendere esplicita la relazione.
Louis,

Questa non è un'ottima soluzione perché si esegue ripetutamente alcune funzioni in setTimer, il che significa che il browser sta costantemente bruciando CPU anche se non succede nulla. I proprietari di laptop e telefoni cellulari traggono vantaggio dalla soluzione che utilizza gli eventi del browser solo quando è presente qualche azione, come l'utilizzo dell'evento onScroll.
Roman Zenka,

2

Puoi provare il codice nello snippet seguente, copre le tue esigenze usando semplicemente javascript. ( esegui lo snippet di codice e fai clic sul collegamento a pagina intera per attivare l'avviso che il div viene ridimensionato se desideri testarlo. ).

Sulla base del fatto che questo è setIntervaldi 100 millisecondi, oserei dire che il mio PC non ha trovato troppa fame della CPU. (Lo 0,1% della CPU è stato utilizzato come totale per tutte le schede aperte in Chrome al momento testato.). Ma ancora una volta questo è solo per un div, se vuoi farlo per una grande quantità di elementi, allora sì, potrebbe essere molto affamato di CPU.

Puoi sempre utilizzare un evento click per interrompere comunque lo sniffing 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>

È possibile controllare il violino anche

AGGIORNARE

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>

Fiddle aggiornato


2

Questa è praticamente una copia esatta della risposta principale, ma invece di un collegamento, è solo la parte del codice che conta, tradotta in IMO più leggibile e più facile da capire. Alcune altre piccole modifiche includono l'uso di cloneNode () e non l'inserimento di html in una stringa js. Piccola roba, ma puoi copiarla e incollarla così com'è e funzionerà.

Il modo in cui funziona consiste nel fare in modo che due div invisibili riempiano l'elemento che stai guardando, quindi inserendo un trigger in ciascuno di essi e impostando una posizione di scorrimento che porterà a innescare un cambio di scorrimento se le dimensioni cambiano.

Tutto il merito reale va a Marc J, ma se stai solo cercando il codice pertinente, eccolo qui:

    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

Pura soluzione Javascript, ma funziona solo se l'elemento viene ridimensionato con il pulsante di ridimensionamento CSS :

  1. memorizzare le dimensioni dell'elemento con offsetWidth e offsetHeight ;
  2. aggiungi un listener di eventi onclick su questo elemento;
  3. quando attivato, confronta i valori correnti offsetWidthe quelli offsetHeightmemorizzati e, se diverso, fai quello che vuoi e aggiorna questi valori.

1

Ecco una versione semplificata della soluzione di @nkron, applicabile a un singolo elemento (anziché una matrice di elementi nella risposta di @nkron, complessità che non mi serviva).

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

Il listener e l'osservatore di eventi possono essere rimossi da:

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

utilizzando la risposta Bharat Patil è sufficiente restituire false all'interno del callback del bind per evitare il massimo errore di stack, vedere l'esempio seguente:

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

0

Questa è una domanda davvero vecchia, ma ho pensato di pubblicare la mia soluzione a questo.

Ho provato ad usare ResizeSensordal momento che tutti sembravano avere una cotta abbastanza grande. Dopo l'implementazione, però, mi sono reso conto che la Query Element richiede che l'elemento in questione abbia una posizione relativeo absoluteapplicato ad esso, il che non ha funzionato per la mia situazione.

Ho finito per gestirlo con un Rxjs intervalinvece di una scala setTimeouto requestAnimationFramecome implementazioni precedenti.

La cosa bella del sapore osservabile di un intervallo è che puoi modificare il flusso, tuttavia qualsiasi altro oggetto osservabile può essere gestito. Per me, un'implementazione di base era sufficiente, ma potresti impazzire e fare tutti i tipi di fusioni, ecc.

Nell'esempio seguente, sto monitorando le variazioni di larghezza del div interno (verde). Ha una larghezza impostata al 50%, ma una larghezza massima di 200 px. Il trascinamento del dispositivo di scorrimento influisce sulla larghezza del div wrapper (grigio). Puoi vedere che l'osservabile si attiva solo quando la larghezza del div interno cambia, il che si verifica solo se la larghezza del div esterno è inferiore a 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>


-1

Window.onResizeEsiste solo nelle specifiche, ma puoi sempre utilizzare IFrameper generare nuovo Windowoggetto all'interno del tuo DIV.

Si prega di controllare questa risposta . C'è un nuovo piccolo plugin jquery , portatile e facile da usare. Puoi sempre controllare il codice sorgente per vedere come è fatto.

<!-- (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...
}

Questa è una soluzione altamente inefficace se hai div ridimensionabili.
suricactus,

-1

ho pensato che non potesse essere fatto, ma poi ci ho pensato, puoi ridimensionare manualmente un div tramite style = "resize: both;" per fare ciò devi fare clic su di esso, quindi ha aggiunto una funzione onclick per controllare l'altezza e la larghezza dell'elemento e ha funzionato. Con solo 5 righe di javascript puro (sicuramente potrebbe essere ancora più breve) 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
Questo calcola solo quando viene generato un evento click che non fa parte del requisito della domanda.
Rob Evans,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.