Catch browser's “zoom” event in JavaScript

前端 未结 16 1577
眼角桃花
眼角桃花 2020-11-22 05:45

Is it possible to detect, using JavaScript, when the user changes the zoom in a page? I simply want to catch a \"zoom\" event and respond to it (similar to window.onresize e

16条回答
  •  名媛妹妹
    2020-11-22 06:07

    According to MDN, "matchMedia" is the proper way to do this https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

    it's a bit finicky because each instance can only watch one MQ at a time, so if you're interested in any zoom level change you need to make a bunch of matchers.. but since the browser is in charge to emitting the events it's probably still more performant than polling, and you could throttle or debounce the callback or pin it to an animation frame or something - here's an implementation that seems pretty snappy, feel free to swap in _throttle or whatever if you're already depending on that.

    Run the code snippet and zoom in and out in your browser, note the updated value in the markup - I only tested this in Firefox! lemme know if you see any issues.

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

提交回复
热议问题