JavaScript'te tarayıcının "zum" etkinliğini yakalayın


162

Kullanıcı bir sayfadaki yakınlaştırmayı değiştirdiğinde JavaScript kullanarak algılamak mümkün müdür? Sadece bir "zoom" olayı yakalamak ve buna yanıt vermek istiyorum (window.onresize olayına benzer).

Teşekkürler.


13
Yeni tarayıcıların, sayfa yakınlaştırıldığında onresize olayını tetiklediğine inanıyorum.
epascarello

1
Benzer bir sorunum var, ancak sadece zumun değiştiğini bilmek istemiyorum, sayfam yüklendiğinde zumun değerini bilmek istiyorum.
Nosredna

3
Gerçekten bir kopya değil. Buradaki soru, zum seviyesini belirlemek değil, olayı yakalamakla ilgilidir.
Assaf Lavie

5
@epascarello - evet, ama yorumumu geçersiz
kılmıyor

7
En yeni tarayıcılarda 'onresize' işlemini onaylamak istiyorum. Şimdiye kadar, yeni set Chrome (33), FF (28), IE (9. Modda 11 ve 11), yakınlaştırdığınızda veya uzaklaştırdığınızda olayı doğru şekilde tetiklediğini görüyorum.
Brock

Yanıtlar:


77

Bir yakınlaştırma olup olmadığını aktif olarak tespit etmenin bir yolu yoktur. Burada bunu nasıl uygulayabileceğiniz konusunda iyi bir giriş buldum.

Zoom seviyesini tespit etmenin iki yolunu buldum. Zoom seviyesi değişikliklerini tespit etmenin bir yolu yüzde değerlerinin zoom yapılmamasına dayanır. Yüzde değeri görünüm genişliği ile ilişkilidir ve bu nedenle sayfa yakınlaştırmasından etkilenmez. Biri yüzde olarak ve biri piksel olarak aynı konuma sahip iki öğe eklerseniz, sayfa yakınlaştırıldığında birbirlerinden uzaklaşırlar. Her iki öğenin konumları arasındaki oranı bulun ve yakınlaştırma seviyesine sahip olun. Test senaryosuna bakın. http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

Bunu yukarıdaki yazının araçlarını kullanarak da yapabilirsiniz. Sorun, sayfanın yakınlaştırılıp büyütülmediğine dair az çok eğitimli tahminler yapmanızdır. Bu, bazı tarayıcılarda diğer tarayıcılardan daha iyi çalışır.

Sayfanızı yakınlaştırılmış durumdayken yüklüyorlarsa, sayfanın büyütülmüş olup olmadığını anlamanın bir yolu yoktur.


1
Gövde için yükleme yükleyici içindeki boyut parametrelerini kontrol edebilirsiniz. İlginçtir ki, IE8'e karşı 9 hata ayıklamasında, gövde için onresize işleyicinin IE8'deki belgeyi geçirirken, IE9 da Chrome gibi pencereden geçer.
Walter K

İki öğeyi tam olarak aynı konumlara yerleştirirseniz ve sayfa yakınlaştırılmış durumdayken yüklenirse, iki öğe arasında yer değiştirme olmaz mı? Bu, sayfanın zaten yakınlaştırılmış olup olmadığını söylemez mi?
vijayant

ayrıcadocument.body.offsetWidth
Samy Bencherif

Bir kullanıcı pencereyi yeniden boyutlandırdığında böyle bir yöntem kullanıldığında da tetiklenir, neden sadece resize olay dinleyicisini kullanmıyorsunuz? Bu durumda aynı zamanda uygun bir çözümdür.
hewiefreeman

12

Bu JavaScript parçasını Zoom "olaylarına" tepki vermek için kullanıyorum.
Pencere genişliğini yoklar. (Bu sayfada bir şekilde önerildiği gibi (Ian Elliott'ın bağlı olduğu): http://novemberborn.net/javascript/page-zoom-ff3 [arşiv] )

IE ile değil Chrome, Firefox 3.6 ve Opera ile test edilmiştir.

Saygılarımızla, Magnus

var zoomListeners = [];

(function(){
  // Poll the pixel width of the window; invoke zoom listeners
  // if the width has been changed.
  var lastWidth = 0;
  function pollZoomFireEvent() {
    var widthNow = jQuery(window).width();
    if (lastWidth == widthNow) return;
    lastWidth = widthNow;
    // Length changed, user must have zoomed, invoke listeners.
    for (i = zoomListeners.length - 1; i >= 0; --i) {
      zoomListeners[i]();
    }
  }
  setInterval(pollZoomFireEvent, 100);
})();

8
Pencereleri yeniden boyutlandırılan yanlış pozitifler ne olacak?
GCB

5
Ancak bir boyutlandırma işleyicisi de uyguladığınızda bu durumları filtreleyebilirsiniz. Demek istediğim, çözümün temelleri burada.
Stijn de Witt

@StijndeWitt okuduktan sonra bu şimdi ben özellikle mobil cihazlarda, yeniden boyutlandırma olayları filtreleyerek ile bir çözüm üzerinde çalışıyorum, önerilen yolu anlamak başlıyorum. Kimse?
lowtechsun

Belki yeniden boyutlandırmak ve yakınlaştırmak için bir boşluk değeri kullanabilirsiniz? Yani yakınlaştırma pencere genişliğini anında> x piksel değiştirecek.
Sebastien

1
Yanlış pozitifler sorun, evet. En boy oranının korunup korunmadığını kontrol ederek tüm yanlış pozitiflerin% 99,99'unu ortadan kaldırmaz mı? Komut dosyasının son oranı hatırlamasını ve yeni oranı hesaplamasını sağlayın ve bunların aynı olup olmadığını kontrol edin. Genişlik farklı olduğu için birleştirin ve iyi bir tabana sahip olmalısınız
Biepbot Von Stirling

11

İyi haberler herkesbazı insanlar! Daha yeni tarayıcılar, zum değiştirildiğinde pencere yeniden boyutlandırma olayını tetikler.


Android için Chrome ve Firefox, yakınlaştırmada yeniden boyutlandırma etkinliğini tetiklemez.
lowtechsun

5
Yakınlaştırmanın yeniden boyutlandırma olayını tetiklemesini istemiyorsanız bu iyi bir haber değildir.
Reahreic

12
Daha iyi haberler, yeniden boyutlandırma etkinliğinden farklı, gerçek bir yakınlaştırma etkinliği olacaktır.
Vincent

3
Her ikisi de doğru. Düzenlenen.
Ben

bir şekilde zumu ayarlamak da mümkün mü?
oldboy

9

Px_ratio'yu aşağıdaki gibi tanımlayalım:

piksel oranı = fiziksel pikselin css piksele oranı.

herhangi bir yakınlaştırma Sayfayı, görüntü alanı pikselleri (piksel pikselden farklıdır) küçültür ve ekrana sığmalıdır, böylece oran (fiziksel piksel / CSS_px) büyür.

ancak Yeniden boyutlandırma penceresinde ekran boyutu piksellerin yanı sıra küçülür. böylece oran korunur.

yakınlaştırma: windows.resize olayını tetikle -> ve px_ratio'yu değiştir

fakat

yeniden boyutlandırma: trigger windows.resize olayı -> px_ratio'yu değiştirmez

//for zoom detection
px_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;

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

function isZooming(){
    var newPx_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
    if(newPx_ratio != px_ratio){
        px_ratio = newPx_ratio;
        console.log("zooming");
        return true;
    }else{
        console.log("just resizing");
        return false;
    }
}

Kilit nokta, CSS PX ve Fiziksel Piksel arasındaki farktır.

https://gist.github.com/abilogos/66aba96bb0fb27ab3ed4a13245817d1e


Bu kabul edilen cevap IMO olmalıdır. Şimdiye kadar kusursuz çalışıyor, teşekkürler! Herkes ilgileniyorsa özel bir etkinliğe sundu gist.github.com/souporserious/b44ea5d04c38c2e7ff32cd1912a17cd0 .
22'da çorba

6

Bu benim için çalışıyor:

        var deviceXDPI = screen.deviceXDPI;
        setInterval(function(){
            if(screen.deviceXDPI != deviceXDPI){
                deviceXDPI = screen.deviceXDPI;
                ... there was a resize ...
            }
        }, 500);

Yalnızca IE8'de gereklidir. Diğer tüm tarayıcılar doğal olarak bir yeniden boyutlandırma olayı oluşturur.


3

yonranAlgılamayı yapabilen inşa edilmiş şık bir eklenti var . İşte StackOverflow ile ilgili daha önce cevapladığı soru. Tarayıcıların çoğu için çalışır. Uygulama bu kadar basit:

window.onresize = function onresize() {
  var r = DetectZoom.ratios();
  zoomLevel.innerHTML =
    "Zoom level: " + r.zoom +
    (r.zoom !== r.devicePxPerCssPx
        ? "; device to CSS pixel ratio: " + r.devicePxPerCssPx
        : "");
}

gösteri


Android 4.4.2 için Firefox'ta çalışmaz. Ayrıca mobil cihazlar için FF'de Always enable zoomErişilebilirlik seçeneğindeki düğmeyi işaretleyin . Demo değişime tepki vermeyecek.
lowtechsun

2

Pencere genişliğindeki değişiklikleri izleyerek önceki çözümde bir iyileştirme önermek istiyorum. Kendi olay dinleyicileri dizinizi korumak yerine, mevcut javascript olay sistemini kullanabilir ve genişlik değişikliği üzerine kendi etkinliğinizi tetikleyebilir ve olay işleyicilerini buna bağlayabilirsiniz.

$(window).bind('myZoomEvent', function() { ... });

function pollZoomFireEvent() 
{ 

    if ( ... width changed ... ) {
        $(window).trigger('myZoomEvent');
    }
}

Kısma / geri alma, işleyicinizin arama oranını azaltmaya yardımcı olabilir.


1
Gaz kelebeği / debounce, yalnızca yoklama diğer bazı olaylar (örn. Fare hareketi veya tuşlar) tarafından tetiklenirse yararlıdır.
fuzzyTew

1

En azından kırılmaz bir alan (muhtemelen, gizli) içeren bir div enjekte ederek ve yüksekliğini düzenli olarak kontrol ederek metin yeniden boyutlandırma olaylarını ve yakınlaştırma faktörünü de alabilirsiniz. Yükseklik değişirse, metin boyutu değiştiyse (ve ne kadar olduğunu biliyorsunuz - bu da, aynı zamanda, pencere tam sayfa modunda yakınlaştırılırsa ve aynı yükseklikte / yükseklik oranı).


1
<script>
var zoomv = function() {
  if(topRightqs.style.width=='200px){
  alert ("zoom");
  }
};
zoomv();
</script>

1

İOS 10'da, etkinliğe bir olay dinleyicisi eklemek touchmoveve sayfanın geçerli etkinlikle yakınlaştırılıp yakınlaştırılmadığını tespit etmek mümkündür.

var prevZoomFactorX;
var prevZoomFactorY;
element.addEventListener("touchmove", (ev) => {
  let zoomFactorX = document.documentElement.clientWidth / window.innerWidth;
  let zoomFactorY = document.documentElement.clientHeight / window.innerHeight;
  let pageHasZoom = !(zoomFactorX === 1 && zoomFactorY === 1);

  if(pageHasZoom) {
    // page is zoomed
    
    if(zoomFactorX !== prevZoomFactorX || zoomFactorY !== prevZoomFactorY) {
      // page is zoomed with this event
    }
  }
  prevZoomFactorX = zoomFactorX;
  prevZoomFactorY = zoomFactorY;
});


1

Bu 9 yıllık bir soru olmasına rağmen, sorun devam ediyor!

Bir projede zoom hariçyken yeniden boyutlandırma algıladım, bu yüzden hem yeniden boyutlandırmak hem de birbirinden ayrı zum algılamak için çalışması için kodumu düzenledim. Çoğu zaman işe yarar, bu yüzden çoğu projeniz için yeterince iyiyse, bu yardımcı olacaktır! Şimdiye kadar test ettiğim zamanın% 100'ünü yakınlaştırmayı tespit ediyor. Tek sorun, eğer kullanıcı çıldırırsa (yani pencereyi büyük ölçüde yeniden boyutlandırırsa) veya pencere gecikirse, pencerenin yeniden boyutlandırılması yerine yakınlaştırma olarak tetiklenebilir.

Bu bir değişiklik tespit ederek çalışır window.outerWidthveya window.outerHeightbir değişiklik tespit ederken boyutlandırma penceresi olarak window.innerWidthveya window.innerHeightbir zoom olarak yeniden boyutlandırma penceresinden bağımsız.

//init object to store window properties
var windowSize = {
  w: window.outerWidth,
  h: window.outerHeight,
  iw: window.innerWidth,
  ih: window.innerHeight
};

window.addEventListener("resize", function() {
  //if window resizes
  if (window.outerWidth !== windowSize.w || window.outerHeight !== windowSize.h) {
    windowSize.w = window.outerWidth; // update object with current window properties
    windowSize.h = window.outerHeight;
    windowSize.iw = window.innerWidth;
    windowSize.ih = window.innerHeight;
    console.log("you're resizing"); //output
  }
  //if the window doesn't resize but the content inside does by + or - 5%
  else if (window.innerWidth + window.innerWidth * .05 < windowSize.iw ||
    window.innerWidth - window.innerWidth * .05 > windowSize.iw) {
    console.log("you're zooming")
    windowSize.iw = window.innerWidth;
  }
}, false);

Not: Çözümüm KajMagnus'unki gibi, ama bu benim için daha iyi çalıştı.


2
Ben işe yaramaz bir çözüm var görebiliyorum çünkü oy vermeyeceğim ve kodunuzun ne yaptığını anlıyorum, ama 0.05en azından iyi bir açıklama yapmadan gibi sihirli bir sayı kullanmanızı tavsiye etmem . ;-) Örneğin, Chrome'da, özellikle,% 10'un tarayıcının her durumda yakınlaştırma yapacağı en küçük miktar olduğunu biliyorum, ancak bunun diğer tarayıcılar için geçerli olduğu açık değil. fyi, kodunuzun her zaman test edildiğinden emin olun ve savunmak veya geliştirmek için hazırlıklı olun.
Nolo

ilginç bir yaklaşım
oldboy

1

İşte temiz bir çözüm:

// polyfill window.devicePixelRatio for IE
if(!window.devicePixelRatio){
  Object.defineProperty(window,'devicePixelRatio',{
    enumerable: true,
    configurable: true,
    get:function(){
      return screen.deviceXDPI/screen.logicalXDPI;
    }
  });
}
var oldValue=window.devicePixelRatio;
window.addEventListener('resize',function(e){
  var newValue=window.devicePixelRatio;
  if(newValue!==oldValue){
    // TODO polyfill CustomEvent for IE
    var event=new CustomEvent('devicepixelratiochange');
    event.oldValue=oldValue;
    event.newValue=newValue;
    oldValue=newValue;
    window.dispatchEvent(event);
  }
});

window.addEventListener('devicepixelratiochange',function(e){
  console.log('devicePixelRatio changed from '+e.oldValue+' to '+e.newValue);
});


bu oldukça hoş bir çözüm gibi görünüyor ve bir Proxy ile dul özelliğini önleyicinizle karıştırmanız bile gerekmiyor - DPR'yi güncellemenin, kullanıcı yakınlaştırıldığında tüm tarayıcıların yaptığı / yapması gereken şey olduğundan emin miyiz? er .. bu fikir çizik - pencere proxied olamaz, belki bir çözüm "matchMedia" kullanarak var ama bu sadece doğru / yanlış bir şey olduğundan, ben gibi bir analog değer değişiklikleri için test nasıl emin değilim DPR ...
Jon z

0

Resize olayı , olayı ekleyerek windowve ardından bodyveya öğesinin veya . ( .GetBoundingClientRect () ) ile başka bir öğenin değerlerini okuyarak modern tarayıcılarda çalışır .

Daha önceki bazı tarayıcılarda, yeniden boyutlandırma olay işleyicilerini herhangi bir HTML öğesine kaydetmek mümkün olmuştur. Onresize özniteliklerini ayarlamak veya herhangi bir öğeye bir işleyici ayarlamak için addEventListener () kullanmak hala mümkündür. Ancak, yeniden boyutlandırma olayları yalnızca pencere nesnesinde tetiklenir (örn. Document.defaultView tarafından döndürülür). Yalnızca pencere nesnesine kayıtlı işleyiciler yeniden boyutlandırma olayları alır .

window.addEventListener("resize", getSizes, false)
        
function getSizes(){
  let body = document.body
  console.log(body.clientWidth +"px x "+ body.clientHeight + "px")
}

Başka bir alternatif : ResizeObserver API'sı

Düzeninize bağlı olarak, belirli bir öğeyi yeniden boyutlandırmayı izleyebilirsiniz.

Yakınlaştırma sırasında kap kutusu yeniden boyutlandırıldığı için bu, «duyarlı» düzenlerde iyi çalışır.

function watchBoxchange(e){
 // console.log(e[0].contentBoxSize.inlineSize+" "+e[0].contentBoxSize.blockSize)
 info.textContent = e[0].contentBoxSize.inlineSize+" * "+e[0].contentBoxSize.blockSize + "px"
}

new ResizeObserver(watchBoxchange).observe(fluid)
#fluid {
  width: 200px;
  height:100px;
  overflow: auto;
  resize: both;
  border: 3px black solid;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-size: 8vh
}
<div id="fluid">
   <info id="info"></info> 
</div>


Javascript görevlerini kullanıcı hareketleri olaylarından aşırı yüklememeye dikkat edin . Yeniden çizmeye ihtiyaç duyduğunuzda requestAnimationFrame kullanın .


0

MDN'ye göre, "matchMedia" bunu yapmanın doğru yoludur https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

bu biraz titiz çünkü her örnek aynı anda sadece bir MQ izleyebilir, bu yüzden herhangi bir yakınlaştırma seviyesi değişikliği ile ilgileniyorsanız, bir grup eşleştirici yapmanız gerekir ... ancak tarayıcı olayları yaymaktan sorumludur. oylamadan daha fazla performans gösterebilir ve geri çağrıyı kısaltabilir veya geri çekebilir veya bir animasyon karesine veya başka bir şeye sabitleyebilirsiniz - işte oldukça çabuk görünen bir uygulama, _throttle veya buna bağlıysanız her neyse değiştirmekten çekinmeyin.

Kod snippet'ini çalıştırın ve tarayıcınızda yakınlaştırın ve uzaklaştırın, biçimlendirmedeki güncellenen değeri not edin - Bunu yalnızca Firefox'ta test ettim! Ben herhangi bir sorun görüyorum biliyorum.

const el = document.querySelector('#dppx')

if ('matchMedia' in window) {
  function observeZoom(cb, opts) {
    opts = {
      // first pass for defaults - range and granularity to capture all the zoom levels in desktop firefox
      ceiling: 3,
      floor: 0.3,
      granularity: 0.05,
      ...opts
    }
    const precision = `${opts.granularity}`.split('.')[1].length

    let val = opts.floor
    const vals = []
    while (val <= opts.ceiling) {
      vals.push(val)
      val = parseFloat((val + opts.granularity).toFixed(precision))
    }

    // construct a number of mediamatchers and assign CB to all of them
    const mqls = vals.map(v => matchMedia(`(min-resolution: ${v}dppx)`))

    // poor person's throttle
    const throttle = 3
    let last = performance.now()
    mqls.forEach(mql => mql.addListener(function() {
      console.debug(this, arguments)
      const now = performance.now()
      if (now - last > throttle) {
        cb()
        last = now
      }
    }))
  }

  observeZoom(function() {
    el.innerText = window.devicePixelRatio
  })
} else {
  el.innerText = 'unable to observe zoom level changes, matchMedia is not supported'
}
<div id='dppx'>--</div>


-4

3 yaşındaki bir bağlantıya yanıt veriyorum ama sanırım burada daha kabul edilebilir bir cevap var,

.Css dosyasını şu şekilde oluşturun:

@media screen and (max-width: 1000px) 
{
       // things you want to trigger when the screen is zoomed
}

ÖRNEĞİN:-

@media screen and (max-width: 1000px) 
{
    .classname
    {
          font-size:10px;
    }
}

Yukarıdaki kod, ekran yaklaşık% 125'e yakınlaştırıldığında '10px' yazı tipinin boyutunu yapar. '1000px' değerini değiştirerek farklı zoom seviyesini kontrol edebilirsiniz.


max-widthVe yakınlaştırma oranı arasındaki ilişki nedir ?
16'da seebiscuit

Bu kod her <1000px ekranda yürütülür ve zoom ile ilgisi yoktur
Artur Stary

@ArturStary tarayıcının yakınlaştırılmış olup olmadığını tespit etmenin bir yolu yoktur, ancak birçok geçici çözüm vardır ve bunlardan biri cevabımda bahsettiğim şeydir. Dahası, farklı zoom seviyelerinin etkisini verecek farklı ekran boyutlarını kontrol etmek için
1000 piksel değerini değiştirebileceğinizi söylemiştim
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.