一、mousemove報treated as passive錯誤
其實這個問題出現有一段時間了,主要麻煩的是,以前沒有,後來,Chrome和Safari瀏覽器升級了,然後出現這個錯誤,而且就在一個月前,Chrome瀏覽器還只是黃色的警告,現在直接就紅色錯誤獻上。
例如,隨便新建一個空白頁面,寫上如下JavaScript代碼:
document.addEventListener('touchmove', function (event) { event.preventDefault(); });
然後在移動端模式下頁面上點擊滑來滑去記下,就可以看到一大堆錯誤:
[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See…
紅燦燦的報錯截圖如下:
這是因爲Chrome及其內核瀏覽器更新了一項新特性,具體見(打開看人品):https://www.chromestatus.com/features/5093566007214080
如果僅僅是錯誤,不影響功能其實還好,但是,這個報錯會影響我們之前運行很OK的交互操作,例如,自定義滾動,或者元素拖拽效果等,會觸發瀏覽器原生的滾動,產生不好的交互體驗效果。
如何解決這個問題呢?
我所知道的有兩個方法。
二、方法一:touch-action:none解決passive錯誤
加入如下CSS:
html { touch-action: none; }
報錯就會無影無蹤。
touch-action
是移動端一個與手勢觸摸密切相關的CSS屬性,原本源自windows phone手機,微軟系,後來被Chrome吸收借鑑,Firefox瀏覽器跟上,然後Safari也部分支持,目前已經可以說是在移動端可以暢行的CSS屬性。
支持的關鍵字值有:
touch-action: auto; touch-action: none; touch-action: pan-x; touch-action: pan-left; touch-action: pan-right; touch-action: pan-y; touch-action: pan-up; touch-action: pan-down; touch-action: pinch-zoom; touch-action: manipulation;
其中:
auto
是默認值,表示手勢操作什麼的完全有瀏覽器自己決定(如<meta>元素的
)。viewport
設置manipulation
表示瀏覽器只允許進行滾動和持續縮放操作,類似雙擊縮放這種非標準操作就不可以。想當初,click
事件在移動端有個300ms
延時,就是因爲避免和手機雙擊行爲發生衝突。然而,當我們設置了touch-action:manipulation
幹掉了雙擊行爲,則顯然,300ms
延時就不復存在,因此,下面的CSS聲明可以用來避免瀏覽器300ms
延時問題。html { touch-action: manipulation; }
上面2個關鍵字屬性值(auto
和manipulation
)是Safari唯一支持的兩個touch-action
屬性值,iOS Safari就是爲用戶操碎了心,就怕開發者把一些對用戶無障礙訪問有幫助的東西去掉,例如不支持touch-action:none
以及iOS10+中設置viewport
的user-scalable=no
已經無法阻止用戶手指縮放屏幕了,或許在Safari看來,對於一個網頁,沒有任何理由阻止用戶放大看你的網頁內容。
至於其他關鍵字,正如字面意思,要麼只能左移,要麼只能左右移動,要麼只能右移之類,具體如下:
none
表示不進行任何touch相關默認行爲,例如,你想用手指滾動網頁就不行,雙擊放大縮小頁面也不可以,所有這些行爲要自定義。pan-x
表示手指頭可以水平移來移去。pan-left
表示手指頭可以往左移動,移動開始後還是可以往右恢復的。pan-right
表示手指頭可以可以往右移動,移動開始後還是可以往左恢復的。pan-y
表示手指頭可以垂直移來移去。pan-up
表示手指頭可以往上移,移動開始後還是可以往下恢復的。pan-down
表示手指頭可以往下移,移動開始後還是可以往上恢復的。pan-zoom
表示手指頭可以用來縮放頁面。
上述部分關鍵字可以組合使用,分pan-y
, pan-up
, pan-down
和pan-x
, pan-left
, pan-right
以及pan-zoom
這三組,然後這三組關鍵字可以任意組合,例如:
.example { touch-action: pan-left pan-up pan-zoom; }
表示可以左移,上移和縮放。
此方法不足
1. iOS Safari瀏覽器不支持;
2. 幹掉了可能需要的原生的touch相關行爲。
不過主要問題還是iOS Safari瀏覽器不支持,第2點不足我們可以當我們需要阻止時候JS設置touch-action
爲none
,不需要在JS還原即可,不是大問題。
iOS Safari對於傳統移動網頁可以重要瀏覽器,不可忽略,怎麼辦,有沒有什麼其他方法呢?有!就是下面這個。
三、方法二:passive:false解決passive錯誤
問題代碼是:
document.addEventListener('touchmove', function (event) { event.preventDefault(); });
修復後的JavaScript代碼是:
document.addEventListener('touchmove', function (event) { event.preventDefault(); }, { passive: false });
也就是addEventListener
的第三個參數傳遞passive:false
,告訴瀏覽器,我這個事件就是不是消極的,是老子主動要這麼做的。瀏覽器此時也不好說什麼,然後,我們以前出問題的代碼就能正常運行了。
如果是Zepto.js語法下的事件呢,例如:
$(document).on('touchmove', function (event) { event.preventDefault(); });
根據我查看Zepto的源碼分析,目前並不支持,請使用原生的addEventListener
代替。
四、結束語
意外學到了CSS touch-action
相關的一些知識。有了touch-action:manipulation
,我們可以在網頁中放心大膽使用click
事件了,至於自定義的touch事件之流可以退出歷史舞臺了,哦也!