📣 背景

最近在工作中,遇到了用户如果缩放浏览器窗口,或者使用 mac 笔记本的触摸板缩放浏览器窗口时,canvas 会模糊的问题,
原因很简单,缩放之后,浏览器的 window.devicePixelRatio  已经发生改变,所以要用最新的 devicePixelRatio 去绘制

window.resize 为什么不行?

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

1
2
3
4
5
6
7
8
<body>
<h1>VisualViewport 测试</h1>
</body>
<script>
window.addEventListener('resize', () => {
console.log('resize', window.devicePixelRatio);
});
</script>

2021-03-31 16.42.38.gif

那么如果换成 mac 的触摸板双指缩放呢?
2021-03-31 16.44.01.gif
尴尬了,window.resize 表示:大哥,超纲了?从图中可以看出来,事件没有相应

给力的 VisualViewport


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

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


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

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

1
2
3
4
5
6
7
8
<body>
<h1>VisualViewport 测试</h1>
</body>
<script>
window.visualViewport.addEventListener('resize', (e) => {
console.log(e.target.scale, window.devicePixelRatio);
});
</script>


首先还是使用键盘进行缩放,发现能正常响应,但是 e.target.scale  始终是 12021-03-31 16.50.49.gif

接下来使用 mac 触摸板进行双指缩放,效果如下:
2021-03-31 16.53.17.gif

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

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

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

兼容性

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

image.png

🔭 总结

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