Ändern Sie die Größe des div-Elements

80

jQuery hat das resize()Ereignis -, funktioniert aber nur mit window.

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

Das funktioniert gut! Aber wenn ich das Ereignis einem div-Element hinzufügen möchte, funktioniert es nicht.

Z.B

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

Ich möchte einen Rückruf starten, wenn sich die Größe eines div-Elements geändert hat. Ich möchte kein Größenänderungsereignis starten - nur ein Ereignis, um zu überprüfen, ob sich die Größe eines div - Elements geändert hat.

Gibt es eine Lösung dafür?

TJR
quelle
2
Größenänderungsereignisse werden nur für Fensterobjekte ausgelöst (und iframes möglicherweise?).
BiAiB
3
Schauen Sie sich diese Seite an - benalman.com/code/projects/jquery-resize/examples/resize
Elen
Dies könnte helfen: resizeObserver. developer.mozilla.org/en-US/docs/Web/API/ResizeObserver . Unterstützt von Chrome 64, Firefox 69 ...
Captain Puget

Antworten:

35

DIVLöst kein resizeEreignis aus, sodass Sie nicht genau das tun können, was Sie codiert haben. Sie können sich jedoch mit der Überwachung der DOM-Eigenschaften befassen .

Wenn Sie tatsächlich mit so etwas wie Größenänderungen arbeiten und dies die einzige Möglichkeit für ein Div ist, seine Größe zu ändern, wird Ihr Größenänderungs-Plugin wahrscheinlich einen eigenen Rückruf implementieren.

David Hedlund
quelle
Sie können das Ereignis zum Ändern der Fenstergröße mit $ (window) .trigger ("resize") auslösen.
Laurent
32

Ich war nur an einem Trigger interessiert, wenn eine Breite eines Elements geändert wurde (mir ist die Höhe egal), also habe ich ein jquery-Ereignis erstellt, das genau das tut, indem ich ein unsichtbares iframe-Element verwende.

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

Es erfordert das folgende CSS:

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

Sie können es hier in Aktion sehen widthChanged fiddle

Panos Theof
quelle
Das ist die richtige Antwort. Das Anhängen des Ereignisses an das Fenster eines Iframes ist viel weniger hackig als ein Intervall.
Kevin Beal
1
Dies ist perfekt! Ich habe meine komplett js basierend gemacht, indem ich das Stylesheet dynamisch hinzugefügt habe: 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
Das ist reines Genie.
Thomas
Ich werde es verwenden, aber ich frage mich: Welche Rolle spielen der Timer und das setTimeout? Ist es wie ein "Entprellen" / Drosseln, um zu verhindern, dass zu viele Größenänderungen erkannt werden, wenn der Benutzer die Größe des Elements ändert?
Mathieu
Ja, um zu verhindern, dass der Trigger "widthChanged" zu oft aufgerufen wird
Panos Theof
21
// 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
quelle
7

Ich habe das jquery-Plugin jquery.resize erstellt. Verwenden Sie resizeObserver, wenn dies unterstützt wird, oder eine Lösung, die auf dem Bildlaufereignis marcj / css-element-queries basiert , kein setTimeout / setInterval.

Sie verwenden nur

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

oder als Resizer Plugin

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

Ich habe dies für jQuery Terminal erstellt und in ein getrenntes Repo- und npm-Paket extrahiert, aber in der Zwischenzeit bin ich zu verstecktem Iframe gewechselt, weil ich Probleme mit der Größenänderung hatte, wenn sich das Element im Iframe befand. Ich kann das Plugin entsprechend aktualisieren. Sie können sich das iframe-basierte Resizer-Plugin im jQuery Terminal-Quellcode ansehen .

BEARBEITEN : Neue Version verwendet Iframe und ändert die Größe des Fensterobjekts, da die vorherigen Lösungen nicht funktionierten, wenn sich die Seite im Iframe befand.

EDIT2 : Da der Fallback Iframe verwendet, können Sie ihn nicht mit Formularsteuerelementen oder Bildern verwenden. Sie müssen ihn dem Wrapper-Element hinzufügen.

EDIT3 :: Es gibt eine bessere Lösung mit resizeObserver Polyfill , die Mutationsbeobachter verwendet (wenn resizeObserver nicht unterstützt wird) und sogar im IE funktioniert. Es gibt auch TypeScript-Typisierungen.

jcubic
quelle
Das war eine großartige Idee. Wirklich gute Arbeit.
Marco Luzzara
6

was ist damit:

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

Übrigens, ich schlage vor, dass Sie dem Div eine ID hinzufügen und $ ("div") in $ ("# yourid") ändern. Es wird schneller und es wird nicht kaputt gehen, wenn Sie später andere Divs hinzufügen

Gavriel
quelle
Natürlich - es war nur ein Beispiel - benutze ich natürlich IDs und Klassen, um meine Elemente auszuwählen. Ich mag deine Idee - ich denke es würde funktionieren! Vielen Dank. Ich werde es in ein paar Minuten versuchen und werde ein Feedback geben.
TJR
Dies überwacht den DIV auf Größenänderungen, wenn das Fensterereignis resizeausgelöst wird. Es ist durchaus denkbar, dass sich die Größe des Div ändert, ohne dass unmittelbar eine Größenänderung des Fensters folgt. In diesem Fall würde das /* what ever */Teil nicht ausgewertet.
David Hedlund
Recht! Und das ist das Problem in meinem Projekt. Das div-Element befindet sich in einem äußeren Wrapper mit dem CSS-Attribut Overflow: hidden. Das Fenster ändert also nicht die Größe. Aber auf andere Weise wird das Beispiel gut funktionieren - ich habe es gerade getestet.
TJR
@Timo: Lauscht $(window).resizedem Vorgang der physischen Größenänderung des Browserfensters, indem Sie beispielsweise die untere rechte Ecke ziehen. Es gibt keine DOM-Ereignisse, die dieses Ereignis auslösen overflow:hiddenoder nicht. Diese Antwort geht nicht auf Ihr Problem ein. Es wäre sinnvoller, diesen Code in einem Timer auszuführen, als an einen zufälligen Ereignis-Listener angehängt zu werden, der wahrscheinlich nie ausgelöst wird. Es wäre noch besser, wenn Sie die DOM-Eigenschaftsüberwachung verwenden und auf einen Timer zurückgreifen könnten (oder ein Ereignis manuell an den Stellen auslösen könnten, an denen sich die Div-Größe ändern kann).
David Hedlund
Code für setInterval hinzugefügt. Sie müssen es fein einstellen, da 1000 ms möglicherweise zu viel für Sie sind. Andererseits kann eine zu niedrige Zahl Ihre CPU leicht töten. Wenn Sie wissen, dass Sie nicht mehr zuhören müssen, rufen Sie an: clearInterval (Timer)!
Gavriel
5

Es gibt ein wirklich schönes, benutzerfreundliches und leichtes Plugin (das native Browserereignisse zur Erkennung verwendet) für grundlegendes JavaScript und für jQuery, das dieses Jahr veröffentlicht wurde. Es funktioniert perfekt:

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

DrCord
quelle
1
Sie sagten, es wird nicht ständig abgefragt, aber es verwendet requestAnimationFrame: github.com/sdecima/javascript-detect-element-resize/blob/master/…
Muhammad Umer
1
Interessant: Das GitHub-Projekt, auf das verwiesen wird, wurde von diesem Blog-Beitrag inspiriert: backalleycoder.com/2013/03/18/… Der Code im Beitrag wurde jedoch später erheblich geändert, während das GitHub-Projekt den älteren Ansatz zu verwenden scheint. Es lohnt sich also, sich beide anzuschauen, bevor Sie sich für eine Verwendung entscheiden.
CF
2

Nur Fenster wird unterstützt, ja, aber Sie können ein Plugin dafür verwenden: http://benalman.com/projects/jquery-resize-plugin/

Nielsen Ramon
quelle
1
Nein, genau das hat OP versucht und darauf hingewiesen, dass es nicht funktioniert.
David Hedlund
Funktioniert in meinem Fall! : D
Phlegx
Verwenden Sie dazu setTimeout, was sehr teuer sein kann, wenn Sie es mehrmals verwenden.
Jcubic
0

Für eine Google Maps-Integration suchte ich nach einer Möglichkeit, um festzustellen, wann sich die Größe eines Div geändert hat. Da Google Maps immer die richtigen Abmessungen benötigt, z. B. Breite und Höhe, um richtig zu rendern.

Die Lösung, die ich gefunden habe, ist eine Delegation eines Ereignisses, in meinem Fall ein Tabulatorklick. Dies könnte natürlich eine Fenstergröße sein, die Idee bleibt dieselbe:

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.mapin diesem fall ist meine karte div. Da mein Elternteil beim Laden unsichtbar ist, sind die berechnete Breite und Höhe 0 oder stimmen nicht überein. Mit .bind(this)kann ich die Skriptausführung ( this.activate) an ein Ereignis ( click) delegieren .

Jetzt bin ich zuversichtlich, dass dies auch für Größenänderungsereignisse gilt.

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

Hoffe es hilft jedem!

Tim Vermaelen
quelle
0

Probieren Sie einfach diese Funktion aus (sie funktioniert möglicherweise nicht nur für Divs):

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

Sie können es so verwenden

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

UPDATE: Sie können auch einen progressiveren Watcher verwenden (er kann für alle Objekte verwendet werden, nicht nur für DOM-Elemente):

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

Probier es einfach:

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

Es wird jedes Mal "geändert" protokolliert, wenn Sie b, a.foo oder a.ext direkt ändern

KaMeHb
quelle
setIntervalkann ziemlich teuer werden, da es immer wieder versucht, die Größe zu ändern
Tonne
@ton: Ich denke du hast nicht ganz recht. Dies tritt nur auf, wenn versucht wird, die Größe eines Elements zu ändern, während die Größe geändert wird. : / Oder hast du dir Sorgen um die Leistung gemacht? In den neuesten Browsern funktioniert es auch auf "schweren" Websites perfekt
KaMeHb
Wenn Sie ein einfaches hinzufügen werden console.logkurz vor dem $.each, werden Sie es sehen alle drucken 100ms, wie Sie in der festgelegt habeninterval
Tonne
@ton: Du hast mich falsch verstanden. Ich weiß genau, wie es setIntervalfunktioniert. Es ist wie eine "lebendige" E-Mail - pingt ständig den Server an. Ich weiß es. Und was? Performance? Lesen Sie meinen Kommentar oben. Besorgt über irgendetwas anderes? Schreib mir, mein Freund.
KaMeHb
0

Sie können Ihren Text, Inhalt oder Attribut abhängig von der Bildschirmgröße ändern: 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
quelle
-2

Wenn Sie nur die Größe des Div selbst ändern möchten, müssen Sie dies im CSS-Stil angeben. Sie müssen einen Überlauf hinzufügen und die Größe der Eigenschaft ändern .

Unten ist mein Code-Snippet

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

<div id="div1">

</div>
Dillip Kumar Nayak
quelle
Diese Antwort gilt nicht für den ursprünglichen Beitrag. In der allgemeinen Diskussion geht es darum, auf Änderungen an der Größe eines Elements zu achten (und anschließend eine Aktion auszuführen) und nicht die Größe des Elements festzulegen.
MarsAndBack