passive event listener

本文探讨了Chrome51引入的PassiveEventListener特性,旨在优化移动端应用滑动流畅度。通过理解preventDefault与被动监听器的工作原理,提供两种解决方案:CSS样式设置与JS事件监听优化。

今天在编写移动端app的时候,一个报错引起了我的注意,报错如下:

Unable to preventDefault inside passive event listener
 due to target being treated as passive.

因为自己以前也没有见过这个错误,所以百度了下,这个特性是从Chrome 51 开始的,旨在提升页面的流畅度,具体的解释如下(摘自SegmentFault):

当你触摸滑动页面时,页面应该跟随手指一起滚动。如果你绑定了一个触摸事件(大概执行 200 毫秒),浏览器就犯迷糊了:如果你在事件绑定函数中调用了 preventDefault,那么页面就不应该滚动;但是浏览器一开始不知道你有没有调用,只能先执行你的函数,等 200 毫秒后,浏览器才知道,“哦,原来你没有阻止默认行为,好的我马上滚”。此时,页面开始滚。

经统计,80% 左右的触摸事件都没有被 preventDefault 阻止,这些等待的时间都被浪费掉了。使用 Passive Event Listeners,开发者能够提前告诉浏览器:“我不调用 preventDefault 函数来阻止事件默认行为”,那么浏览器就无需等待事件执行完成,而是直接执行默认行为(滚动)。

在这里我们就有必要来了解一下addEventListener方法,该方法接收三个参数,window.addEventListener(type, fn, { passive: false }),type表示监听事件类型的字符串,fn作为事件调用的函数,第三个参数默认为false,表示浏览器检测使用的preventDefault。

从passive event listener 被引进Chrome开始,我们就可以通过给addEventListener 设置第三个参数{passive:true}来避免浏览器对prevent Default 的检测,从而使滑动显得比较流畅,当我们给addEventListener 设置了{passive: true}时,这个监听器也就被称为passive event listener。

解决方案:
理解了出现这个问题的原理,我们就来说说解决问题的方案:
1、设置全局css样式

*{
	//当触控事件发生在元素上时,不进行任何操作
	touch-action: none;
 }

2、使用JS的时间监听方法来解决

window.addEventListener('type',fn,{passive: true});

总结:
其实这个问题不会造成页面的崩溃,但是它的的确确的影响了性能的优化,所以来记录下自己的解决方法。

### 问题原因 在 Chrome 51 版本以后,浏览器增加了新的事件捕获机制 Passive Event Listeners,该特性主要用于优化页面的滑动性能,当前仅支持 mousewheel/touch 相关事件。当项目没有为这些事件添加 `passive` 选项,并且添加了会阻塞滚动的事件监听器时,就会出现 `Added non-passive event listener` 警告。例如,添加了非被动的 `wheel` 或 `touchmove` 事件监听器,浏览器无法预先知道该监听器是否会调用 `preventDefault()` 来阻止默认滚动行为,从而影响滚动性能,因此会发出警告[^2]。 ### 解决方案 #### 使用 `default-passive-events` 可以使用 `default-passive-events` 来解决该问题,它可以为某些事件启用被动事件侦听器。基本上,每次声明新的事件侦听器时,它都会自动设置 `{ passive: true }`。安装方法如下: ```bash npm install default-passive-events ``` 安装完成后,在项目中引入使用即可。 #### 手动添加 `passive` 选项 在添加事件监听器时,手动添加 `{ passive: true }` 选项。以下是一个示例代码: ```javascript // 假设 element 是要添加事件监听器的元素 element.addEventListener('mousewheel', function(event) { // 事件处理逻辑 }, { passive: true }); ``` #### 在 Vue3 中解决 在 Vue3 项目中,如果使用了 Element UI Plus 出现该警告,可以参考以下代码: ```javascript import normalizeWheel from 'normalize-wheel-es'; import '../../utils/index.mjs'; import { isChrome, isFirefox } from '../../utils/browser.mjs'; const mousewheel = function(element, callback) { if (element && element.addEventListener) { const fn = function(event) { const normalized = normalizeWheel(event); callback && Reflect.apply(callback, this, [event, normalized]); }; if (isFirefox()) { element.addEventListener("DOMMouseScroll", fn); } else if (isChrome()) { element.addEventListener("mousewheel", fn, {passive: true}) } else { element.onmousewheel = fn; } } }; const Mousewheel = { beforeMount(el, binding) { mousewheel(el, binding.value); } }; export { Mousewheel as default }; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值