问题:
项目开发中,有一块canvas画布,画布中滚动鼠标滚轮可以将canvas内的图片放大和缩小,但是在canvas中滚动鼠标滚轮时页面随着一起滚动,影响操作。所以想阻止默认的页面滚动事件
一开始在canvas的onWheel事件中使用
event.preventDefault();
但是不起效果,并且浏览器控制台报错
Unable to preventDefault inside passive event listener invocation
原因:
- 谷歌浏览器对event.preventDefault()(默认事件阻止)的检测机制变化导致。
- 老版本中,当用户触发定义的监听事件的时候,浏览器会主动检测对应的handler代码中是否有event.preventDefault(),以便进行默认事件阻止。但是这样做会增加响应时间,用户体验受到影响;所以谷歌改变了这个机制。
解决方法:
在页面中新增如下监听
canvas.addEventListener('wheel', rollImg, { passive: false });
- 新版本的chrome默认是passive:true;就是让chrome消极的去阻止默认事件,等价于不检测是否阻止默认事件,以达到提升浏览器性能的目的.但在这种情况下如果写了e.preventDefault(),相当于"违约,chrome就会在控制台报错 。
- 所以我们配置passive: false,这样就可以正常使用e.preventDefault()了
如有必要,记得卸载事件
canvas.removeEventListener('wheel', rollImg, {
passive: false,
});
页面代码
<canvas
ref={canvasRef}
style={{ width: '100%', height: '100%' }}
// onWheel={rollImg} // 通过事件绑定,这里就不要了,否则会触发2次
onMouseDown={onmousedown}
onMouseMove={onmousemove}
onMouseUp={onmouseup}
onMouseLeave={onmouseleave}
onMouseEnter={mouseenter}
onDoubleClick={handleDoubleClick}
></canvas>
// 滚动函数
function rollImg(event: any) {
event.preventDefault();
dbClickPosition = {
x: '',
y: '',
};
// 坐标转换
let canvas = canvasRef.current;
let pos = windowToCanvas(event.clientX, event.clientY, canvas);
if (event.deltaY < 0) {
if (scale < 10) {
scale *= 2;
imgX = imgX * 2 - pos.x;
imgY = imgY * 2 - pos.y;
}
} else {
if (scale > 0.1) {
scale /= 2;
imgX = imgX * 0.5 + pos.x * 0.5;
imgY = imgY * 0.5 + pos.y * 0.5;
}
}
drawCanvasFun();
}
useEffect(() => {
// 滚动事件,不用onwhell是因为没法阻止默认滚动事件
const canvas: any = canvasRef.current;
canvas.addEventListener('wheel', rollImg, { passive: false });
return () => {
canvas.removeEventListener('wheel', rollImg, {
passive: false,
});
};
}, []);
网友评论