VisualViewport 实现 Mac 触控板的缩放检测

478 阅读2分钟

背景

最近在工作中,遇到了用户如果缩放浏览器窗口,或者使用 Mac 笔记本的触摸板缩放浏览器窗口时,Canvas 会模糊的问题,

原因很简单,缩放之后,浏览器的 window.devicePixelRatio 已经发生改变,所以要用最新的 devicePixelRatio 去绘制

【第3022期】虚拟键盘 API 的妙用

window.resize 为什么不行?

对于用户使用键盘,比如 commond + + 和 common + - 缩放时,事情很好办,使用 resize 事件即可

 <body>
     <h1>VisualViewport 测试</h1>
   </body>
   <script>
     window.addEventListener('resize', () => {
       console.log('resize', window.devicePixelRatio);
     });
   </script>

图片

那么如果换成 Mac 的触摸板双指缩放呢?

图片

尴尬了,window.resize 表示:大哥,超纲了?从图中可以看出来,事件没有相应

给力的 VisualViewport

面向 Google 编程了一段时间,总算找到了 浏览器的一个实验性功能,根据 MDN 的描述:

Visual Viewport API 提供了当前页面的视觉视口接口,即 VisualViewport 。对于每个页面容器来说(如 iframe),都存在有一个独立的 window 对象。每个页面容器的 window 对象都有一个独立的 VisualViewport 属性。
你可以使用 Window.visualViewport 获得对应 window 的视觉视口 API。

看起来似乎 Mac 的触控板缩放也是一种视觉改变,现在来试试,根据文档,它有两个接口

Events

通过使用 addEventListener () 或者将监听回调函数赋值给对应的 oneventname 属性,可以为对应的视口事件添加监听。

  • resize (en-US): 当视觉视口被改变时触发。也可以为 VisualViewport.onresize (en-US) 属性赋值来添加监听。
  • scroll (en-US): 当视觉视口滑动时触发。也可以为 VisualViewport.onscroll (en-US) 属性赋值来添加监听。

resize 似乎可以满足我们的需求,编写一点简单的代码,测试一下

 <body>
     <h1>VisualViewport 测试</h1>
   </body>
   <script>
     window.visualViewport.addEventListener('resize', (e) => {
       console.log(e.target.scale, window.devicePixelRatio);
     });
   </script>

首先还是使用键盘进行缩放,发现能正常响应,但是 e.target.scale 始终是 1

图片

接下来使用 Mac 触摸板进行双指缩放,效果如下:

图片

可以看到 e.target.scale 随着双指的缩放在改变,window.devicePixelRatio 始终是 1, 看起来的效果就像,使用了 css3 的 transform: scale 一样,元素的实际大小没变.

经过测试,可以看出,双指缩放 可以使用 e.target.scale 获取缩放比,键盘缩放,可以使用 window.devicePixelRatio , 使用 Math.max 取最大字就可以兼容两种情况

 window.visualViewport.addEventListener('resize', (e) => {
     const scale = Math.max(e.target.scale, window.devicePixelRatio);
     console.log('scale: ', scale);
 });

兼容性

还是有点恐怖,任重而道远!

图片

总结

这种冷门的 API (仅对我而言), 看似没啥用,有时却能解决大问题,看来平时还是要多积累知识才行,多看看 web.dev, 涨涨知识!。