181

是否可以使用 JavaScript 检测用户何时更改页面的缩放比例?我只是想捕捉一个“缩放”事件并响应它(类似于 window.onresize 事件)。

谢谢。

4

16 回答 16

81

没有办法主动检测是否有缩放。我在这里找到了一个关于如何尝试实现它的好条目。

我发现了两种检测缩放级别的方法。检测缩放级别变化的一种方法依赖于百分比值未缩放的事实。百分比值是相对于视口宽度的,因此不受页面缩放的影响。如果您插入两个元素,一个具有百分比位置,另一个具有相同位置(以像素为单位),当页面缩放时,它们将分开。找到两个元素的位置之间的比率,你就得到了缩放级别。见测试用例。 http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

您也可以使用上述帖子的工具来完成。问题是您或多或少地对页面是否缩放进行了有根据的猜测。这在某些浏览器中会比其他浏览器更好。

如果他们在缩放时加载您的页面,则无法判断页面是否已缩放。

于 2009-06-15T12:59:11.640 回答
19

让我们定义 px_ratio 如下:

px 比率 = 物理像素与 css px 的比率。

如果任何一个缩放页面,视口 pxes(px 与 pixel 不同)会减小并且应该适合屏幕,因此比例(物理像素/ CSS_px)必须变大。

但在窗口大小调整中,屏幕尺寸和像素一样减小。所以这个比例会保持。

缩放:触发 windows.resize 事件 --> 并更改 px_ratio

调整大小:触发 windows.resize 事件 --> 不改变 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;
    }
}

关键是CSS PX和Physical Pixel的区别。

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

于 2018-08-24T16:06:10.063 回答
17

好消息每个人有些人!较新的浏览器将在缩放更改时触发窗口调整大小事件。

于 2016-08-09T20:06:55.247 回答
13

我正在使用这段 JavaScript 来响应 Zoom“事件”。
它轮询窗口宽度。(正如这个页面上的一些建议(Ian Elliott 链接到): http: //novemberborn.net/javascript/page-zoom-ff3 [archive]

使用 Chrome、Firefox 3.6 和 Opera 测试,而不是 IE。

问候,马格努斯

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);
})();
于 2010-08-29T19:44:24.493 回答
6

这对我有用:

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

它只需要在 IE8 上。所有其他浏览器自然会生成调整大小事件。

于 2012-06-26T12:02:00.087 回答
4

有一个漂亮的插件yonran可以进行检测。这是他之前在 StackOverflow上回答的问题。它适用于大多数浏览器。申请就这么简单:

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

演示

于 2013-01-20T02:06:44.330 回答
3

虽然这是一个 9 岁的问题,但问题仍然存在!

我在项目中排除缩放时一直在检测调整大小,因此我编辑了我的代码以使其能够检测调整大小和缩放相互排斥。它在大多数情况下都有效,所以如果大多数都对您的项目足够好,那么这应该会有所帮助!到目前为止,它在我测试的内容中检测到 100% 的缩放时间。唯一的问题是,如果用户变得疯狂(即痉挛地调整窗口大小)或窗口滞后,它可能会作为缩放而不是窗口调整大小触发。

它的工作原理是检测窗口大小的变化window.outerWidthwindow.outerHeight窗口大小的变化,同时检测窗口大小的变化window.innerWidthwindow.innerHeight独立于窗口大小的变化作为缩放。

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

注意:我的解决方案类似于 KajMagnus 的解决方案,但这对我来说效果更好。

于 2018-07-23T15:23:34.383 回答
3

resize 事件在现代浏览器上通过将事件附加到 上window,然后读取body或其他元素的值,例如(.getBoundingClientRect())。

在一些早期的浏览器中,可以在任何 HTML 元素上注册调整大小事件处理程序。仍然可以设置 onresize 属性或使用 addEventListener() 在任何元素上设置处理程序。然而,调整大小事件仅在窗口对象上触发(即由 document.defaultView 返回)。只有在窗口对象上注册的处理程序才会接收调整大小事件

⚠️ 调整标签大小或缩放以触发此代码段:

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

⬤ 另一种选择ResizeObserver API

根据您的布局,您可以注意调整特定元素的大小。

这适用于“响应式”布局,因为容器框在缩放时会调整大小。

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 任务超载。每当您需要重绘时,请使用requestAnimationFrame 。

于 2020-01-23T23:58:31.027 回答
2

我想建议通过跟踪窗口宽度的变化来改进以前的解决方案。您可以使用现有的 javascript 事件系统并在宽度更改时触发您自己的事件,并将事件处理程序绑定到它,而不是保留自己的事件侦听器数组。

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

function pollZoomFireEvent() 
{ 

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

Throttle/debounce可以帮助降低处理程序的调用率。

于 2011-05-04T11:54:51.417 回答
2

这是一个干净的解决方案:

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

于 2019-12-04T01:47:55.867 回答
2

根据 MDN,“matchMedia”是执行此操作的正确方法https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

这有点挑剔,因为每个实例一次只能观看一个 MQ,所以如果您对任何缩放级别更改感兴趣,您需要制作一堆匹配器。但由于浏览器负责发出事件,它可能仍然比轮询性能更高,您可以限制或消除回调或将其固定到动画帧或其他东西 - 这是一个看起来非常敏捷的实现,如果您已经依赖它,请随意交换 _throttle 或其他任何东西。

运行代码片段并在浏览器中放大和缩小,注意标记中的更新值 - 我只在 Firefox 中测试过!如果您发现任何问题,请让我知道。

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>

于 2020-03-11T17:48:52.560 回答
1

您还可以通过注入至少包含不可破坏空间(可能是隐藏的)的 div 并定期检查其高度来获取文本调整大小事件和缩放因子。如果高度发生变化,则文本大小发生了变化,(并且您知道多少 - 顺便说一句,如果窗口在全页模式下放大,您仍然会得到正确的缩放因子,高度相同 /高比)。

于 2011-05-22T00:16:23.400 回答
1
<script>
var zoomv = function() {
  if(topRightqs.style.width=='200px){
  alert ("zoom");
  }
};
zoomv();
</script>
于 2016-06-28T02:26:18.347 回答
1

在 iOS 10 上,可以为事件添加事件侦听器touchmove并检测页面是否随当前事件缩放。

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

于 2016-11-23T13:34:34.310 回答
-1

这是一种原生方式(主要框架无法放大Chrome,因为它们不支持被动事件行为


//For Google Chrome
document.addEventListener("mousewheel", event => {
  console.log(`wheel`);
  if(event.ctrlKey == true)
  {
    event.preventDefault();
    if(event.deltaY > 0) {
      console.log('Down');
    }else {
      console.log('Up');
    }
  }
}, { passive: false });

// For Mozilla Firefox
document.addEventListener("DOMMouseScroll", event => {
  console.log(`wheel`);
  if(event.ctrlKey == true)
  {
    event.preventDefault();
    if(event.detail > 0) {
      console.log('Down');
    }else {
      console.log('Up');
    }
  }
}, { passive: false });

于 2020-08-21T08:13:24.790 回答
-4

我正在回复一个 3 年前的链接,但我想这是一个更可接受的答案,

创建 .css 文件为,

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

例如:-

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

当屏幕缩放到大约 125% 时,上面的代码使字体大小为“10px”。您可以通过更改“1000px”的值来检查不同的缩放级别。

于 2013-11-04T03:13:56.473 回答