Nắm bắt sự kiện Zoom zoom của trình duyệt trong JavaScript


162

Có thể phát hiện, sử dụng JavaScript, khi người dùng thay đổi thu phóng trong một trang không? Tôi chỉ đơn giản muốn bắt một sự kiện "phóng to" và trả lời nó (tương tự như sự kiện window.onresize).

Cảm ơn.


13
Tôi tin rằng các trình duyệt mới hơn sẽ kích hoạt sự kiện onresize khi trang được phóng to.
eprebello

1
Tôi có một vấn đề tương tự, nhưng tôi không chỉ muốn biết khi nào thay đổi thu phóng, tôi cũng muốn biết giá trị của thu phóng khi trang của tôi tải.
Nosredna

3
Thực sự không phải là một bản sao. Câu hỏi ở đây là về việc bắt sự kiện, không xác định mức thu phóng.
Assaf Lavie

5
@eprebello - có, nhưng nó không làm mất hiệu lực nhận xét của tôi
HorusKol

7
Tôi muốn xác nhận về 'onresize' xảy ra trong các trình duyệt mới nhất. Cho đến nay tôi thấy Chrome mới (33), FF (28), IE (11 và 11 ở Chế độ 9) đều kích hoạt chính xác sự kiện khi bạn phóng to hoặc thu nhỏ.
Brock

Câu trả lời:


77

Không có cách nào để chủ động phát hiện nếu có zoom. Tôi tìm thấy một mục tốt ở đây về cách bạn có thể cố gắng thực hiện nó.

Tôi đã tìm thấy hai cách để phát hiện mức thu phóng. Một cách để phát hiện các thay đổi mức thu phóng phụ thuộc vào thực tế là các giá trị phần trăm không được phóng to. Giá trị phần trăm liên quan đến chiều rộng khung nhìn và do đó không bị ảnh hưởng bởi thu phóng trang. Nếu bạn chèn hai yếu tố, một yếu tố có vị trí theo tỷ lệ phần trăm và một yếu tố có cùng vị trí tính bằng pixel, chúng sẽ di chuyển xa nhau khi trang được phóng to. Tìm tỷ lệ giữa các vị trí của cả hai yếu tố và bạn đã có mức thu phóng. Xem trường hợp thử nghiệm. http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

Bạn cũng có thể làm điều đó bằng cách sử dụng các công cụ của bài viết trên. Vấn đề là bạn ít nhiều đưa ra những phỏng đoán có giáo dục về việc trang có được phóng to hay không. Điều này sẽ hoạt động tốt hơn trong một số trình duyệt hơn so với khác.

Không có cách nào để biết trang có được phóng to hay không nếu họ tải trang của bạn trong khi thu phóng.


1
Người ta có thể kiểm tra các tham số kích thước bên trong trình xử lý onload cho cơ thể. Thật kỳ lạ, khi gỡ lỗi IE8 so với 9, có vẻ như trình xử lý onresize cho phần thân được truyền tài liệu trong IE8, trong khi IE9 vượt qua cửa sổ, cũng như Chrome.
Walter K

Nếu bạn đặt hai phần tử ở cùng một vị trí và tải trang trong khi phóng to, sẽ không có sự dịch chuyển giữa hai phần tử? Điều này sẽ không cho biết nếu trang đã được phóng to hay chưa?
vijayant

cũng vậydocument.body.offsetWidth
Samy Bencherif

Sử dụng một phương thức như thế này cũng sẽ kích hoạt khi người dùng thay đổi kích thước cửa sổ, vậy tại sao không sử dụng trình lắng nghe sự kiện thay đổi kích thước? Trong trường hợp đó cũng là một giải pháp khả thi.
hewiefreeman

12

Tôi đang sử dụng đoạn JavaScript này để phản ứng với các "sự kiện" Thu phóng.
Nó thăm dò chiều rộng cửa sổ. (Như được đề xuất trên trang này (mà Ian Elliott đã liên kết đến): http://novemberborn.net/javascript/page-zoom-ff3 [archive] )

Đã thử nghiệm với Chrome, Firefox 3.6 và Opera, không phải IE.

Trân trọng, 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
Điều gì về các dương tính giả với thay đổi kích thước cửa sổ?
gcb

5
Nhưng bạn có thể lọc ra những trường hợp đó khi bạn cũng thực hiện một trình xử lý onresize. Vì vậy, những điều cơ bản cho một giải pháp là ở đây tôi muốn nói.
Stijn de Witt

@StijndeWitt Sau khi đọc xong , tôi bắt đầu hiểu đường dẫn được đề xuất, bây giờ tôi đang nghiên cứu một giải pháp với việc lọc ra các sự kiện thay đổi kích thước, đặc biệt là trên thiết bị di động. Bất kỳ ai?
lowTechsun

Có lẽ bạn có thể sử dụng một giá trị khoảng cách để thay đổi kích thước và thu phóng? Ý tôi là zoom sẽ thay đổi độ rộng cửa sổ ngay lập tức theo> x pixel.
Sebastien

1
Dương tính giả là một vấn đề, yeah. Nó sẽ không loại bỏ 99,99% tất cả các dương tính giả bằng cách kiểm tra xem tỷ lệ khung hình có được duy trì không? Có kịch bản ghi nhớ tỷ lệ cuối cùng và tính tỷ lệ mới và kiểm tra xem chúng có giống nhau không. Kết hợp với chiều rộng là khác nhau và bạn nên có một cơ sở tốt
Biepbot Von Stirling 30/12/17

11

Tin tốt tất cả mọi ngườimột số người! Các trình duyệt mới hơn sẽ kích hoạt sự kiện thay đổi kích thước cửa sổ khi thu phóng được thay đổi.


Chrome và Firefox cho Android sẽ không kích hoạt sự kiện thay đổi kích thước khi phóng to.
lowTechsun

5
Đây không phải là tin tốt nếu bạn không muốn phóng to để kích hoạt sự kiện thay đổi kích thước.
Reahreic

12
Tin tốt hơn sẽ là một sự kiện thu phóng thực tế, khác với sự kiện thay đổi kích thước.
Vincent

3
Cả hai đều đúng. Đã chỉnh sửa.
Ben

cũng có thể thiết lập thu phóng bằng cách nào đó?
oldboy

9

Hãy xác định px_ratio như sau:

tỷ lệ px = tỷ lệ pixel vật lý với css px.

nếu có bất kỳ thu phóng Trang nào, pxes của khung nhìn (px khác với pixel) sẽ giảm và phải vừa với Màn hình để tỷ lệ (pixel vật lý / CSS_px) phải lớn hơn.

nhưng trong cửa sổ Thay đổi kích thước, kích thước màn hình giảm cũng như pxes. do đó tỷ lệ sẽ duy trì.

phóng to: kích hoạt sự kiện windows.resize -> và thay đổi px_ratio

nhưng

thay đổi kích thước: kích hoạt sự kiện windows.resize -> không thay đổi px_ratio

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

Điểm mấu chốt là sự khác biệt giữa CSS PX và Pixel vật lý.

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


Đây phải là câu trả lời được chấp nhận IMO. Hoạt động hoàn hảo cho đến nay, cảm ơn! Kết thúc nó thành một sự kiện tùy chỉnh nếu bất cứ ai quan tâm gist.github.com/souporserious/b44ea5d04c38c2e7ff32cd1912a17cd0 .
ăn tối

6

Điều này làm việc cho tôi:

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

Nó chỉ cần trên IE8. Tất cả các trình duyệt khác tự nhiên tạo ra một sự kiện thay đổi kích thước.


3

Có một plugin tiện lợi được xây dựng từ yonranđó có thể thực hiện phát hiện. Đây là câu hỏi được trả lời trước đây của anh ấy trên StackOverflow. Nó hoạt động cho hầu hết các trình duyệt. Ứng dụng đơn giản như thế này:

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

Bản giới thiệu


Không hoạt động trên Firefox cho Android 4.4.2. Ngoài ra trong FF cho điện thoại di động đánh dấu vào Always enable zoomnút trong tùy chọn Trợ năng. Bản demo sẽ không phản ứng với sự thay đổi.
lowTechsun

2

Tôi muốn đề xuất một cải tiến cho giải pháp trước đó với việc theo dõi các thay đổi về chiều rộng cửa sổ. Thay vì giữ mảng trình lắng nghe sự kiện của riêng bạn, bạn có thể sử dụng hệ thống sự kiện javascript hiện có và kích hoạt sự kiện của riêng bạn khi thay đổi độ rộng và liên kết các trình xử lý sự kiện với nó.

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

function pollZoomFireEvent() 
{ 

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

Điều tiết / gỡ lỗi có thể giúp giảm tỷ lệ cuộc gọi của trình xử lý của bạn.


1
Điều tiết / gỡ lỗi chỉ hữu ích nếu việc bỏ phiếu được kích hoạt bởi một số sự kiện khác (ví dụ như di chuyển chuột hoặc gõ phím).
fuzzyTew

1

Bạn cũng có thể lấy các sự kiện thay đổi kích thước văn bản và hệ số thu phóng bằng cách chèn một div chứa ít nhất một không gian không thể phá vỡ (có thể, bị ẩn) và thường xuyên kiểm tra chiều cao của nó. Nếu chiều cao thay đổi, kích thước văn bản đã thay đổi, (và bạn biết bao nhiêu - điều này cũng kích hoạt, tình cờ, nếu cửa sổ được phóng to ở chế độ toàn trang và bạn vẫn sẽ có được hệ số thu phóng chính xác, với cùng chiều cao / tỷ lệ chiều cao).



1

Trên iOS 10 có thể thêm người nghe sự kiện vào touchmovesự kiện và phát hiện, nếu trang được phóng to với sự kiện hiện tại.

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

Mặc dù đây là một câu hỏi cũ 9 năm, vấn đề vẫn tồn tại!

Tôi đã phát hiện thay đổi kích thước trong khi loại trừ thu phóng trong một dự án, vì vậy tôi đã chỉnh sửa mã của mình để làm cho nó hoạt động để phát hiện cả thay đổi kích thước và thu phóng độc quyền với nhau. Nó hoạt động hầu hết thời gian, vì vậy nếu hầu hết là đủ tốt cho dự án của bạn, thì điều này sẽ hữu ích! Nó phát hiện thu phóng 100% thời gian trong những gì tôi đã thử nghiệm cho đến nay. Vấn đề duy nhất là nếu người dùng bị điên (tức là thay đổi kích thước cửa sổ một cách khó khăn) hoặc cửa sổ bị trễ, nó có thể kích hoạt dưới dạng phóng to thay vì thay đổi kích thước cửa sổ.

Nó hoạt động bằng cách phát hiện thay đổi trong window.outerWidthhoặc window.outerHeightthay đổi kích thước cửa sổ trong khi phát hiện thay đổi trong window.innerWidthhoặc window.innerHeightđộc lập với thay đổi kích thước cửa sổ dưới dạng phóng to.

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

Lưu ý: Giải pháp của tôi giống như của KajMagnus, nhưng điều này đã làm việc tốt hơn với tôi.


2
Tôi sẽ không bỏ phiếu vì tôi có thể thấy bạn có một giải pháp hiệu quả và tôi hiểu mã của bạn làm gì, nhưng tôi không khuyên bạn nên sử dụng một số ma thuật như 0.05ít nhất là không cung cấp một lời giải thích tốt. ;-) Ví dụ: tôi biết rằng trong Chrome, cụ thể, 10% là số tiền nhỏ nhất mà trình duyệt sẽ phóng to trong mọi trường hợp, nhưng không rõ ràng rằng điều này đúng với các trình duyệt khác. fyi, luôn đảm bảo mã của bạn được kiểm tra và sẵn sàng bảo vệ hoặc cải thiện nó.
Nolo

cách tiếp cận thú vị
oldboy

1

Đây là một giải pháp sạch:

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


đây có vẻ là một giải pháp khá hay và với Proxy, bạn thậm chí sẽ không cần phải chặn tài sản góa phụ bằng thiết bị chặn của mình - chúng tôi có chắc chắn rằng cập nhật DPR là điều mà tất cả các trình duyệt làm / nên làm khi người dùng đã phóng to? er .. cào ý tưởng đó - cửa sổ không thể được ủy quyền, có thể là một giải pháp tồn tại bằng cách sử dụng "matchMedia" nhưng vì đó chỉ là một điều đúng / sai, tôi không chắc chắn cách bạn kiểm tra các thay đổi đối với một giá trị tương tự như DPR ...
Jon z

0

Sự kiện thay đổi kích thước hoạt động trên các trình duyệt hiện đại bằng cách đính kèm sự kiện trên window, sau đó đọc các giá trị của bodyhoặc phần tử khác với ví dụ ( .getBoundingClientRect () ).

Trong một số trình duyệt trước đó, có thể đăng ký thay đổi kích thước trình xử lý sự kiện trên bất kỳ phần tử HTML nào. Vẫn có thể đặt thuộc tính onresize hoặc sử dụng addEventListener () để đặt trình xử lý trên bất kỳ phần tử nào. Tuy nhiên, thay đổi kích thước các sự kiện chỉ được kích hoạt trên đối tượng cửa sổ (tức là được trả về bởi document.defaultView). Chỉ các trình xử lý được đăng ký trên đối tượng cửa sổ sẽ nhận được các sự kiện thay đổi kích thước .

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

Một cách khác : API ResizeObserver

Tùy thuộc vào bố cục của bạn, bạn có thể xem để thay đổi kích thước trên một yếu tố cụ thể.

Điều này hoạt động tốt trên các bố trí «đáp ứng», vì hộp chứa được thay đổi kích thước khi thu phóng.

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>


Hãy cẩn thận để không làm quá tải các tác vụ javascript từ các sự kiện cử chỉ của người dùng. Sử dụng requestAnimationFrame bất cứ khi nào bạn cần vẽ lại.


0

Theo MDN, "matchMedia" là cách thích hợp để thực hiện điều này https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

hơi khó hiểu vì mỗi phiên bản chỉ có thể xem một MQ tại một thời điểm, vì vậy nếu bạn quan tâm đến bất kỳ thay đổi mức thu phóng nào, bạn cần tạo ra một loạt các công cụ đối sánh .. nhưng vì trình duyệt có trách nhiệm phát ra các sự kiện nên có thể vẫn hiệu quả hơn so với bỏ phiếu và bạn có thể điều tiết hoặc gỡ bỏ cuộc gọi lại hoặc ghim nó vào khung hình động hoặc một cái gì đó - đây là một triển khai có vẻ khá thú vị, hãy thoải mái trao đổi trong _thrption hoặc bất cứ điều gì nếu bạn đã phụ thuộc vào điều đó.

Chạy đoạn mã và phóng to và thu nhỏ trong trình duyệt của bạn, lưu ý giá trị được cập nhật trong đánh dấu - Tôi chỉ thử nghiệm điều này trong Firefox! Để tôi biết nếu bạn thấy bất kỳ vấn đề.

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

Tôi đang trả lời một liên kết 3 năm tuổi nhưng tôi đoán đây là một câu trả lời dễ chấp nhận hơn,

Tạo tập tin .css như,

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

VÍ DỤ:-

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

Đoạn mã trên làm cho kích thước của phông chữ '10px' khi màn hình được phóng to lên khoảng 125%. Bạn có thể kiểm tra mức thu phóng khác nhau bằng cách thay đổi giá trị '1000px'.


Mối quan hệ giữa max-widthtỷ lệ và tỷ lệ thu phóng là gì?
seebcakes

Mã này sẽ được thực thi trên mỗi màn hình <1000px và không liên quan gì đến thu phóng
Artur Stary

@ArturStary không có cách nào để phát hiện xem trình duyệt có được phóng to hay không nhưng có nhiều cách giải quyết và một trong số đó là những gì tôi đã đề cập trong câu trả lời của mình. Hơn nữa, tôi đã nói rằng bạn có thể thay đổi giá trị 1000px để kiểm tra các kích thước màn hình khác nhau sẽ cho hiệu ứng ở các mức thu phóng khác nhau
Saumil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.