S2 基于 Canvas 开发,在实际的业务场景开发中,我们发现有 2 种使用场景会导致 表格渲染模糊

  1. 不同 DPR 的设备之间来回切换:比如一台 Mac (视网膜屏), 外接一台显示器 (普通 2k 屏), 将浏览器移到外接设备查看
  2. 使用 Mac 触控板对页面进行缩放:双指缩放,来放大显示,而不是传统的 cmd + +, cmd + - 缩放浏览器窗口大小

默认开启高清适配,可以手动关闭

1
2
3
const s2Options = {
hdAdapter: false
}

首先看一下开启前后的对比图

关闭高清适配

开启高清适配

不同 DPR 设备间切换

对于这种场景,我们使用 matchMedia 来监听 DPR 的变化,更新 canvas 的尺寸,从而达到高清的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const { width, height } = s2Options
const devicePixelRatioMedia = window.matchMedia(
`(resolution: ${window.devicePixelRatio}dppx)`,
);

devicePixelRatioMedia.addEventListener('change', renderByDevicePixelRatio)

const renderByDevicePixelRatio = (ratio = window.devicePixelRatio) => {
const newWidth = Math.floor(width * ratio);
const newHeight = Math.floor(height * ratio);

// 内部的更新容器大小方法
changeSheetSize(newWidth, newHeight);
};

Mac 触控板双指缩放

区别于浏览器的放大缩小,普通的 resize 事件是无法触发的

1
2
// 触摸板双指缩放 无法触发
window.addEventListener('resize', ...)

普通浏览器窗口放大缩小

触控板双指缩放

那么如果解决呢?答案就是 使用 VisualViewport API, VisualViewport 可以被用做移动端的双指缩放监听,同样适用于 mac 触摸板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
window.viewport?.visualViewport?.addEventListener(
'resize',
this.renderByZoomScale,
);

const renderByZoomScale = debounce((e) => {
// 拿到缩放比 更新容器大小
const ratio = Math.max(e.target.scale, window.devicePixelRatio);
if (ratio > 1) {
const { width, height } = s2Options
const newWidth = Math.floor(width * ratio);
const newHeight = Math.floor(height * ratio);

// 内部的更新容器大小方法
changeSheetSize(newWidth, newHeight);
}
}, 350);

关闭高清适配

开启高清适配

完整代码

自定义设备像素比

表格默认使用设备当前像素比渲染,也就是 window.devicePixelRatio, 如果你觉得初始渲染就很模糊,可以手动指定表格按照 2 倍设备像素比来渲染

1
2
3
const s2Options = {
devicePixelRatio: 2
}