DIV'nin boyutu nasıl değişti?


352

Aşağıdaki örnek html yaşadım,% 100 genişliğe sahip bir DIV var. Bazı elementler içerir. Pencerelerin yeniden boyutlandırılması yapılırken, iç elemanlar yeniden konumlandırılabilir ve div'in boyutu değişebilir. Ben div'ın boyut değişikliği olayını kanca mümkün olup olmadığını soruyorum? ve nasıl yapılır? Şu anda geri arama işlevini hedef DIV'deki jQuery resize olayına bağladım, ancak konsol günlüğü çıktısı yok, aşağıya bakın:

Yeniden Boyutlandırmadan Önce resim açıklamasını buraya girin

<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
Resize olayını belirtilen div öğesine bağladığınız için bu çalışmaz. Ancak resize olayı, öğeniz için değil pencereyi tetikler.
Fatih Acet

setIntervalBurada olası bir çözüm olarak kullanabilirsiniz . clearIntervalÇalışmanız bittikten sonra döngüyü durdurmak için her zaman bir düğmeyi tıklatabilirsiniz.
Peter Darmis

1
2020'den beri ResizeObserver , IE hariç tüm büyük tarayıcılarda (Chrome, Safari, Firefox, Edge) çalışır. caniuse.com/#feat=resizeobserver
Dan

Yanıtlar:


265

Bir öğenin boyutunun değiştirilip değiştirilmediğini belirlemek için çok etkili bir yöntem vardır.

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

Bu kütüphane ResizeSensoryeniden boyutlandırma tespiti için kullanılabilecek bir sınıfa sahiptir.
Olay tabanlı bir yaklaşım kullanır, bu yüzden çok hızlıdır ve CPU zamanını boşa harcamaz.

Misal:

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

Değişiklikleri kontrol etmek için bir döngüdeki DOM / özelliklerini okumakla birlikte kullandığından lütfen jQuery onresize eklentisini kullanmayın . Bu inanılmaz yavaş ve yanlıştır, çünkü düzenin çökmesine neden olur .setTimeout()clientHeightclientWidth

Açıklama: Doğrudan bu kütüphane ile ilişkilendirildim.


8
@jake, IE11 desteği artık uygulanmaktadır.
Marc J. Schmidt

15
@Aletheios daha yakından bakmalısınız. requestAnimationFrame yavaş boyut tespiti için değil, tam tersi: CPU zamanından tasarruf etmek için gerçek olay tabanlı yeniden boyutlandırma sensörü tarafından tetiklenen tüm bu aşırı sayıda olayı düzeltir. Güncellenen dokümanları github.com/marcj/css-element-queries/blob/master/src/…
Marc J. Schmidt

6
@Aletheios Sanırım bir noktayı kaçırıyorsunuz: setTimeout sadece yanlış değil aynı zamanda cehennem kadar yavaş. Basit bir boole değerini denetleyen bir requestAnimationFrame, DOM özelliklerine karşı her zaman denetlenen bir setTimeout'tan daha hızlı büyüklük sıralarıdır. Bu setTimeout'un yanı sıra birkaç milisaniyede bir denir.
Marc J. Schmidt

9
@Orwellophile açıkçası hiçbir şey anlamadınız. Dahili olarak nasıl çalıştığına dair hiçbir fikriniz olmadığında cevapları düşürmeyi bırakın. Yine: css-element-query: boyut her değiştiğinde tetiklenen gerçek bir yeniden boyutlandırma olayı kullanır. Çok fazla etkinlik alacağınız için (örneğin drag'n'drop için) tetiklenen olayları 1 / kare'ye kadar düzeltmek için requestAnimationFrame basit bir boole değişkeni olup olmadığını kontrol etti. jquery eklentisi: Her denetimin çok yavaş olduğu, ancak aynı işlevselliğe sahip olması için sık sık kontrol edilmesi gereken her zaman DOM düzen sahne (denetleyiciHeight vb.) kontrol eden bir setTimeout kullanır.
Marc J. Schmidt

9
@Aletheios, @Orwellophile ve onlar tarafından yanıltılmış olabilecek herkes: requestAnimationFramevs setTimeoutilgisiz, bu kütüphane döngü yapmaz . requestAnimationFrameyalnızca geri aramalarınızı arama sıklığını azaltmak / azaltmak için kullanılır, yoklama yapmaz . MutationObserver teorik olarak benzer etki için kullanılabilir, ancak bunun aksine eski tarayıcılarda kullanılamaz. Bu son derece zekidir.
Han Seoul-Oh

251

Bunun için yeni bir standart, Chrome 64'te bulunan Yeniden Boyutlandırma Gözlemcisi API'sidir.

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>

Gözlemciyi Yeniden Boyutlandır

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

Çoklu doldurmalar: https://github.com/WICG/ResizeObserver/issues/3

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

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

Mevcut Destek: http://caniuse.com/#feat=resizeobserver


3
üretim siteleri için henüz yararlı değil, çünkü şu anda yalnızca Chrome bunu destekliyor. Ama kesinlikle burada en iyi çözüm! btw, uygulama durumuna hızlı bir genel bakış: chromestatus.com/feature/5705346022637568
Philipp

8
@Philipp Çok dolgu var.
Daniel Herr

2
Görünüşe göre hala tüm tarayıcılarda deneysel bir özellik caniuse.com/#feat=resizeobserver
Francesc Rosas

5
Bu yanıttan 2 yıl sonra bile tarayıcı desteği kasvetli: caniuse.com/#search=resizeobserver
Scrimothy

2
En son Chrome ve FF'de bir cazibe gibi çalışır.
Klemen Tušar

32

resizeOlayı, windowgenel bir html öğesine değil , nesneye bağlamanız gerekir .

Daha sonra bunu kullanabilirsiniz:

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

ve geri arama işlevi içinde divaramanın yeni genişliğini kontrol edebilirsiniz

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

Yani, sorunuzun cevabı hayır , resizeetkinliği bir div'a bağlayamazsınız .


124
bu cevap yeterince iyi değil. boyut değişiklikleri HERHANGİ bir pencere yeniden boyutlandırılmadan oluşabilir. hiç.
vsync

9
örneğin bir ayırıcı öğeniz varsa veya bir öğeye yalnızca metin veya başka bir içerik eklediğinizde.
Günter Zöchbauer

@anu doğru değil, örneğin javascript aracılığıyla DOM modifikasyonuna sahip olabilirsiniz, bu da CSS'nin her yapı için farklı mizanpaj boyutu ile sonuçlanan yeni yapıya uygulanmasına neden olur.
Antoniossss

29

Uzun vadede, ResizeObserver'ı kullanabilirsiniz .

new ResizeObserver(callback).observe(element);

Ne yazık ki şu anda birçok tarayıcıda varsayılan olarak desteklenmemektedir.

Bu arada, aşağıdaki gibi bir işlev kullanabilirsiniz. Çünkü, öğe boyutu değişikliklerinin çoğunluğu, pencerede yeniden boyutlandırma veya DOM'daki bir şeyi değiştirmekten gelecek. Pencerenin resize olayıyla pencere yeniden boyutlandırmasını dinleyebilir ve MutationObserver kullanarak DOM değişikliklerini dinleyebilirsiniz .

Sağlanan öğenin boyutu bu olaylardan birinin sonucu olarak değiştiğinde sizi geri arayacak bir işlev örneği:

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
Ne yazık ki, MutationObserver Shadow DOM'daki değişiklikleri algılayamıyor gibi görünüyor.
Ajedi32

@nkron, Ne yazık ki, CSS3 yeniden boyutlandırma kullanırsanız, kullanıcı elle yeniden boyutlandırıldığında yeniden boyutlandırma gerçekleşebilir. Bu olay yakalanamaz.
Pacerier

@ Ajedi32 Evet, ama MutationObserver'ı ShadowDOM içinde kullanabilirsiniz. Demek istediğim, bodybu örnekteki gibi izlemek yerine, bir öğeyi doğrudan izleyebilirsiniz. Bu aslında tüm vücudu izlemekten daha performanslı ve etkilidir.
trusktr

@ Ajedi32 Tek sorun, eğer Gölge DOM ağacı kapalıysa, o zaman iç kısımlara erişemezsiniz, ama bunun genellikle yapmanız gereken bir şey olduğunu ve gözlemlemeniz gerekiyorsa, böyle kapalı bir ağaç daha sonra tasarımda bir sorun olabilir. İdeal olarak, yalnızca erişiminiz olan kendi öğelerinizi gözlemlemeniz gerekir. İç boyutlandırmasını gözlemlemenizi gerektiren bir Shadow-DOM bileşeni düzgün tasarlanmamış olabilir. Belirli bir örneğiniz var mı? Eğer öyleyse, belki bir çözüm önermek için yardımcı olabilirim (çünkü ben de ilgileniyorum, ancak henüz bir örneğim yok).
trusktr

@trusktr Şu anda bir MCVE'm yok, ancak temelde bazı kullanıcı girişlerinin bir sonucu olarak boyutunu değiştirebilecek herhangi bir Shadow DOM öğesi bu sorunu tetiklemek için yeterli olacaktır. Örneğin, tıklandığında bazı ek bilgilerle genişleyen bir kutu. Tek tek öğeyi değil, sayfayı gözlemlediğimi unutmayın, çünkü ne olursa olsun sayfanın boyutu arttığında otomatik olarak aşağı kaydırmak istiyorum. Bir Shadow DOM öğesi genişletmesi, sayfanın daha uzun süre almasının birçok olası nedeninden yalnızca biridir.
Ajedi32

24

ResizeSensor.js büyük bir kütüphane parçasıdır, ama onun işlevselliğini azaltılmış BU :

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

Bu nasıl kullanılır:

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

Grafikler js bunu yapar.
Antoniossss

Sıkıştırdığınız için teşekkürler. Ben deneyeceğim :)
Tony K.

Bu ifadede eksik bir şey varparseInt( getComputedStyle(element) )
GetFree

2
Nasıl karıştı "let zIndex = parseInt (getComputedStyle (element));" geçerli? Kastettiğinizi varsayalım: "let zIndex = parseInt (getComputedStyle (element) .zIndex);
Ryan Badour

1
Yukarıdaki çözüm / kod tüm yeniden boyutlandırma olaylarını algılamaz (örneğin, bir kap sabit bir dosyayla yeniden boyutlandırıldığında alt olaylar için yeniden boyutlandırmayı algılamaz. Bkz. Jsfiddle.net/8md2rfsy/1 ). Kabul edilen cevap işe yarar (ilgili satırların çıkarılması).
newbee

21

Ben setTimeout()performansı yavaşlatmak gibi kesmek tavsiye ETMEM ! Bunun yerine, Div boyutu değişikliğini dinlemek için DOM mutasyon gözlemcilerini kullanabilirsiniz .

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>

İşte keman
Div boyutunu değiştirmeye çalışın.


debounceVerimliliği artırmak için yönteminizi yöntemde daha fazla sarabilirsiniz . debounceDIV'nin yeniden boyutlandırıldığı her milisaniyeyi tetiklemek yerine yönteminizi her x milisaniyede bir tetikleyecektir.


9
Bununla ilgili tek sorun, öğeye gerçekten bir mutasyon olmadıkça bir değişiklik bildirmemesi. Eklenen diğer öğeler nedeniyle öğe yeniden boyutlandırılırsa, bu çalışmaz.
Tony K.

@TonyK ile katılıyorum. Bu, MutationObserver ile tek sorunum ve şimdi bir öğe yeniden boyutlandırma kütüphanesi arıyorum
Murhaf Sousli

@JerryGoyal Div, <img> etiketi içerdiğinde çalışmaz. İlk durumda görüntü yüklenmez ve div boyutu 0 olarak ayarlanır ve yükten sonra div boyutu değiştirilir, ancak gözlemci tetiklenmez
Santhosh

15

En iyi çözüm, Element Sorguları olarak adlandırmaktır . Bununla birlikte, standart değildirler, herhangi bir belirtim yoktur - ve tek seçenek, bu şekilde gitmek istiyorsanız, kullanılabilir çoklu dolgular / kitaplıklardan birini kullanmaktır.

Öğe sorgularının arkasındaki fikir, sayfadaki belirli bir kapsayıcıya sağlanan alana yanıt vermesine izin vermektir. Bu, bir bileşenin bir kez yazılmasına ve ardından içeriğinin geçerli boyutuna göre ayarlanmasına rağmen sayfanın herhangi bir yerine bırakılmasına olanak tanır. Pencere boyutu ne olursa olsun. Bu, öğe sorguları ile medya sorguları arasında ilk gördüğümüz farktır. Herkes, bir noktada eleman sorgularını standartlaştıracak (veya aynı hedefe ulaşan bir şeyi) ve bunları yerel, temiz, basit ve sağlam hale getirecek bir spesifikasyonun yaratılmasını umuyor. Çoğu insan Medya sorgularının oldukça sınırlı olduğunu ve modüler tasarım ve gerçek yanıt verme için yardımcı olmadığını kabul eder.

Sorunu farklı şekillerde çözen birkaç çoklu dolgu / kütüphane vardır (yine de çözümler yerine geçici çözümler olarak adlandırılabilir):

Önerilen benzer sorunlara başka çözümler de gördüm. Genellikle zamanlayıcıları veya kaputun altında Pencere / görünüm alanı boyutunu kullanırlar, bu gerçek bir çözüm değildir. Dahası, ideal olarak bu javascript veya html değil, esas olarak CSS çözülmesi gerektiğini düşünüyorum.


Öğe sorguları için + 1'tir, ancak bunları yakın zamanda görmeyi ummuyorum. Bu noktada AFAIK taslağı bile yok ... belki ilgili taraflardan biri bir araya getirip sunmalı?
Rob Evans

1
Bu elbette iyi bir fikir. Son bir sürüme ulaşmak uzun sürecek, çok dikkat çekilmesi gerekiyor. Bunu iyi bir şekilde tasarlamak benim için önemsiz görünmüyor. Tarayıcılar arası uyumluluk, dairesel bağımlılıklar, hata ayıklama, okunabilirlik ve bakım vb. Böylece mümkün olduğunca erken başlayalım :)
Stan

@Stan, bu sorunun Element Sorgusu'nun ne hakkında olduğu hakkında daha fazla ayrıntı ekleyerek daha iyi olabileceğini düşünüyorum.
Pacerier

15

Bu kütüphaneyi MarcJ'in çözümü çalışmadığında buldum:

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

Çok hafiftir ve CSS veya yalnızca HTML yükleme / oluşturma yoluyla doğal boyutlarda boyutları bile algılar.

Kod örneği (linkten alınmıştır):

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

Budur. 147 satır, kaydırma olaylarını kullanır. Div boyutu değişikliklerini en iyi nasıl algılayacağınıza ilişkin tam ve doğru cevabı istiyorsanız bu kodu okuyun. İpucu: "sadece bu kütüphaneyi kullan" değil.
Seph Reed

1
İnsanlar bu kütüphaneyi denemeden önce bu konuya bir göz atmalıdır .
Louis

13

Bu http://benalman.com/code/projects/jquery-resize/examples/resize/ adresine bir göz atın.

Çeşitli örnekleri var. Pencerenizi yeniden boyutlandırmayı deneyin ve kap öğelerinin içindeki öğelerin nasıl ayarlandığını görün.

Nasıl çalıştığını açıklamak için js keman ile örnek.
Bu kemana bir göz atın http://jsfiddle.net/sgsqJ/4/

Bu resize () olayı "test" sınıfına sahip elemanlara ve ayrıca pencere nesnesine ve $ ('. Test') pencere nesnesinin yeniden boyutlandırılmasında geri çağrılır. Resize () çağrılır.

Örneğin

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

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

İlginç. Bu jsfiddle sürekli müfettiş açık krom çöküyor ve "Daha fazla metin ekle" bağlantısını tıklatın. Firefox "çok fazla özyineleme" hatası veriyor.
EricP

3
Lütfen jQuery'nin yeniden boyutlandırma eklentisini kullanmayın. Gerçekten yavaş ve doğru değil. Daha iyi bir çözüm elde etmek için cevabımı görün.
Marc J. Schmidt

24
Bu, boyut değişikliklerini doğrudan ALMAZ. yalnızca yeniden boyutlandırma olayı dinleyicisinin bir yan ürünüdür. boyut değişiklikleri başka şekillerde de olabilir.
vsync

4
Div'in yeniden boyutlandırılması, pencere boyutuna göre değil, stil veya dom'daki değişiklikten kaynaklanıyorsa ne olur?
korku

9

Yeniden boyutlandırmada iframeveya objectkullanarak contentWindowveya kullanabilirsiniz contentDocument. Olmadan setIntervalveyasetTimeout

Adımlar:

  1. Eleman konumunuzu olarak ayarlayın relative
  2. Saydam bir mutlak gizli IFRAME içine ekleyin
  3. Dinle IFRAME.contentWindow- onresizeetkinlik

HTML örneği:

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

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

Koşu Örneği

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


Daha fazla gör:


1
Jquery kullanmayanlar için bir not, IFRAME.contentWindow , onloadolay iframe'de tetiklenene kadar kullanılamaz . Ayrıca, visibility:hidden;iframe arkasındaki öğelere fare girişini engelleyebileceği için stili eklemek isteyebilirsiniz (en azından IE'de "kayan" gibi görünüyor).
James Wilkins

3
Bu işe yarıyor olsa da, sadece boyut değişikliğini gözlemlemek için tamamen yeni bir göz atma bağlamı oluşturma yükü ile ağır bir çözümdür. Ayrıca, bazı durumlarda display, elemanın özelliğini değiştirmek ideal veya uygun değildir .
trusktr

kabul, bu yukarıda belirtildiği gibi korkunç bir çözüm
29er

Nasıl bu kadar korkunç bir çözüm yazdı?
Aminadav Glickshtein

bu yöntem, dinamik içerik yeniden boyutlandırması gereken video oynatıcılar ve ses oynatıcılarla iyi çalışır. Im wavesurfer.js çıktı yeniden boyutlandırmak için bu yöntemi kullanarak.
David Clews

8

Yalnızca window nesnesi bir "resize" olayı oluşturur. Ne yapmak istediğinizi bilmemin tek yolu, boyutu düzenli olarak kontrol eden bir aralık zamanlayıcısı çalıştırmaktır.


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

Şaşırtıcı derecede bu sorun kadar eski, bu hala çoğu tarayıcıda bir sorun.

Diğerlerinin söylediği gibi, Chrome 64+ artık Resize Observes ile yerel olarak geliyor, ancak spesifikasyon hala ince ayarlanıyor ve Chrome şu anda spesifikasyonun son sürümünün arkasında (2019-01-29 itibariyle) .

Birkaç iyi ResizeObserver çoklu doldurma gördüm, ancak, bazı yakından yakından takip ve diğerleri bazı hesaplama sorunları var.

Ben herhangi bir uygulamada kullanılabilecek bazı duyarlı web bileşenleri oluşturmak için bu davranış umutsuz ihtiyacı vardı. Onları güzel bir şekilde çalıştırmak için boyutlarını her zaman bilmeleri gerekir, bu yüzden ResizeObservers ideal geliyordu ve spesifikasyonu mümkün olduğunca yakından takip eden bir çoklu dolgu oluşturmaya karar verdim.

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

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


Bu kesinlikle IE11 + tarayıcı uyumluluğu ile uğraşan herkes için beset cevabıdır.
ekfuhrmann

3

Clay.js ( https://github.com/zzarcon/clay ) kullanarak öğe boyutundaki değişiklikleri tespit etmek oldukça basittir:

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

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

7
Lütfen kütüphaneniz olduğu için uygun açıklamayı sağlayın.
jhpratt GOFUNDME İLİŞKİSİ

Bu benim için çalıştı, ResizeSensor'un olmadığı yerde, modal tarzımı bozuyor. Teşekkürler Zzarcon :)
Máxima Alekz

3

Bu blog gönderisi, DOM öğelerindeki boyut değişikliklerini etkili bir şekilde tespit etmeme yardımcı oldu.

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

Bu kod nasıl kullanılır ...

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

Örnek tarafından kullanılan paket kod ...

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

Not: AppConfig, yeniden kullanılabilir işlevleri düzenlemek için kullandığım bir ad alanı / nesnedir. Adı aramak ve istediğiniz herhangi bir şeyle değiştirmekten çekinmeyin.


3

Benim jQuery eklentisi "yeniden boyutlandırmak" olayı sadece window.

https://github.com/dustinpoissant/ResizeTriggering

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

1
Bağlantınız artık mevcut olmayan bir yeri işaret ediyordu. Eklentinin adını aradım ve açıklamanıza karşılık gelen bir sayfa buldum. Eklentinin yazarı olarak göründüğünüz için, cevabınızın dilini de bunun sizin işiniz olduğunu açık hale getirmek için düzenledim. Bu sitenin kuralları öyle ki, cevap yazdığınızda geliştirdiğiniz bir şeyi kullanmanızı önerir , ilişkiyi açık yapmanız gerekir .
Louis

Bu harika bir çözüm değildir, çünkü setTimer'de bazı işlevleri tekrar tekrar çalıştırırsınız, bu da hiçbir şey olmasa bile tarayıcının sürekli CPU yaktığı anlamına gelir. Dizüstü bilgisayar ve cep telefonu sahipleri, yalnızca onScroll olayını kullanmak gibi bazı eylemler olduğunda tarayıcı olaylarını kullanan çözümden yararlanır.
Roman Zenka

2

Aşağıdaki snippet'te kodu deneyebilirsiniz, düz javascript kullanarak ihtiyaçlarınızı karşılar. ( kod snippet'ini çalıştırın ve div'ı test etmek isterseniz yeniden boyutlandırıldığı uyarısını tetiklemek için tam sayfa bağlantısını tıklayın. ).

Bunun bir setInterval 100 milisaniyeden bilgisayarımın çok fazla CPU aç bulamadığını söylemeye cesaret edeceğim. (Test edilen zamanda, CPU'nun% 0.1'i Chrome'da açılan tüm sekmeler için toplam olarak kullanıldı.). Ama sonra tekrar bu sadece bir div için, eğer bunu çok miktarda eleman için yapmak istiyorsanız evet çok CPU aç olabilir.

Div-yeniden boyutlandırmanın koklamasını yine de durdurmak için her zaman bir click olayı kullanabilirsiniz .

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>

Kemanı da kontrol edebilirsiniz

GÜNCELLEME

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>

Güncellenmiş Keman


2

Bu hemen hemen en iyi cevabın tam bir kopyasıdır, ancak bir bağlantı yerine, IMO'nun daha okunabilir ve anlaşılması daha kolay olacak şekilde çevrilen, kodun sadece bir kısmıdır. Birkaç başka küçük değişiklik arasında cloneNode () kullanımı ve html'nin bir js dizesine yerleştirilmemesi yer alır. Küçük şeyler, ancak bunu olduğu gibi kopyalayıp yapıştırabilirsiniz ve işe yarayacaktır.

Çalışma şekli, izlediğiniz öğeyi iki görünmez div yapmak ve sonra her birine bir tetikleyici koymak ve boyut değişirse bir kaydırma değişikliğinin tetiklenmesine yol açacak bir kaydırma konumu ayarlamaktır.

Tüm gerçek kredi Marc J'ye gider, ancak sadece ilgili kodu arıyorsanız, işte burada:

    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

İşte @nkron tarafından çözümün tek bir öğeye uygulanabilen basitleştirilmiş bir sürümü (@ nkron'un cevabındaki bir dizi eleman yerine, ihtiyacım olmayan karmaşıklık).

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

Olay dinleyicisi ve gözlemcisi aşağıdakiler tarafından kaldırılabilir:

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

Bharat Patil cevabı kullanarak maksimum yığın hatasını önlemek için sadece bağlama geri aramanızın içinde yanlış döndürün aşağıdaki örneğe bakın:

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

0

Bu gerçekten eski bir soru, ama çözümümü buna göndereceğimi düşündüm.

ResizeSensorHerkesin üzerinde büyük bir eziyet var gibi göründüğünden kullanmaya çalıştım . Yine de uyguladıktan sonra, kaputun altında Öğe Sorgusunun söz konusu öğenin konumunun relativeveyaabsolute uygulanmış

Bunu intervaldüz setTimeoutveya requestAnimationFramedaha önceki uygulamalar yerine bir Rxjs ile hallettim .

Bir aralığın gözlemlenebilir lezzeti hakkında güzel olan şey, akışı değiştirebilmenizdir, ancak diğer gözlemlenebilirler de işlenebilir. Benim için temel bir uygulama yeterliydi, ama delirebilir ve her türlü birleşimi vb.

Aşağıdaki örnekte, iç (yeşil) div'in genişlik değişikliklerini izliyorum. Genişliği% 50 olarak ayarlanmış, ancak maksimum genişliği 200 pikseldir. Kaydırıcıyı sürüklemek sarıcı (gri) div'in genişliğini etkiler. Gözlenebilir olanın yalnızca iç div'ın genişliği değiştiğinde ateş ettiğini görebilirsiniz, bu yalnızca dış div'ın genişliği 400 pikselden küçük olduğunda gerçekleşir.

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

Yalnızca Window.onResizespesifikasyonda bulunur, ancak her zaman DIV'nizin içinde IFrameyeni Windownesne oluşturmak için kullanabilirsiniz .

Lütfen bu cevabı kontrol edin . Taşınabilir ve kullanımı kolay yeni bir küçük jquery eklentisi var . Nasıl yapıldığını görmek için her zaman kaynak kodunu kontrol edebilirsiniz.

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

Yeniden boyutlandırılabilir div'leriniz varsa bu son derece etkisiz bir çözümdür.
suricactus

-1

Ben yapılamadı sanıyordum ama sonra düşündüm, elle div = = resize: both; " Bunu yapmak için üzerine tıklamak için elemanın yüksekliğini ve genişliğini kontrol etmek için bir onclick işlevi ekledi ve çalıştı. Sadece 5 satır saf javascript ile (daha kısa olabileceğinden emin olun) 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
Bu yalnızca sorunun gerekliliğinin bir parçası olmayan bir tıklama olayı tetiklendiğinde hesaplanır.
Rob Evans
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.