最近用react作了一個H5端的頁面,主要實現了一個彈層滑動選擇的功能,效果如圖:
遇到了一個問題,當在底部彈出層進行滾動選擇城市區劃時,蒙版後的頁面也會隨着滾動。css
這種現象在開發過程當中常常會遇到,常規思路就是使用event.preventDefault
阻止父級元素的滾動:react
<div className="picker-column"> <div className="picker-scroller" style={style} onTouchStart={this.handleTouchStart} onTouchMove={this.handleTouchMove} onTouchEnd={this.handleTouchEnd} onTouchCancel={this.handleTouchCancel} > {this.renderItems()} </div> </div>
滾動事件代碼片斷git
handleTouchMove = (event) => { event.preventDefault(); ... };
但這波操做事後,卻未能如願以償,在調試的時候Chrome的告警,如冷冷的冰雨打在個人臉上:
根據告警關鍵字用Google百度了一番,等到了以下結論:github
因爲瀏覽器必需要在執行事件處理函數以後,才能知道有沒有調用preventDefault()
,這就致使了瀏覽器不能及時響應滾動,略有延遲。因此爲了讓頁面滾動的效果如絲般順滑,從 chrome56 開始,在 window、document 和 body 上註冊的
touchstart
和touchmove
事件處理函數,會默認爲設置passive: true
。瀏覽器忽略 preventDefault() 就能夠第一時間滾動了。chrome
細細揣測一番,其實官方的考慮仍是有道理的,也是周到的。在CSS中提供了一個屬性touch-action
,用於指定某個給定的區域是否容許用戶操做,以及如何響應用戶操做。
據此,個人解決方案就是設置這個CSS屬性:瀏覽器
touch-action: none;
感受總算萬事大吉利了,那個手機試一把,用iPhone的Safari瀏覽器代開後,依然並無什麼卵用。是的,九成是瀏覽器兼容問題,查看CanIUse,果不其然。
那麼既然如此,剩下的解決方案,就只有在綁定事件的時候顯式的設置{ passive: false }
,查了一圈React文檔也沒發現,能夠支持配置這個屬性的方法。此處真心感嘆一句不如Vue方便,若是是Vue就能夠這麼寫:函數
<div v-on:touchmove.prevent="handleTouchMove"></div>
既然如此,就只能用原生的事件綁定了this
document.getElementById("picker").addEventListener('touchmove', this.handleTouchMove, { passive: false });
終於,世界和平了。spa