React中禁止頁面滾動

最近用react做了一個H5端的頁面,主要實現了一個彈層滑動選擇的功能,效果如圖:
圖片描述
遇到了一個問題,當在底部彈出層進行滾動選擇城市區劃時,蒙版後的頁面也會隨着滾動。

這種現象在開發過程中經常會遇到,常規思路就是使用event.preventDefault阻止父級元素的滾動:

<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>

滾動事件代碼片段

handleTouchMove = (event) => {
    event.preventDefault();
    ...
};

但這波操作過後,卻未能如願以償,在調試的時候Chrome的告警,如冷冷的冰雨打在我的臉上:
圖片描述
根據告警關鍵字用Google百度了一番,等到了如下結論:

由於瀏覽器必須要在執行事件處理函數之後,才能知道有沒有調用 preventDefault() ,這就導致了瀏覽器不能及時響應滾動,略有延遲。

所以爲了讓頁面滾動的效果如絲般順滑,從 chrome56 開始,在 window、document 和 body 上註冊的 touchstarttouchmove 事件處理函數,會默認爲設置passive: true。瀏覽器忽略 preventDefault() 就可以第一時間滾動了。

圖片描述
細細揣測一番,其實官方的考慮還是有道理的,也是周到的。在CSS中提供了一個屬性touch-action,用於指定某個給定的區域是否允許用戶操作,以及如何響應用戶操作。
圖片描述
據此,我的解決方案就是設置這個CSS屬性:

touch-action: none;

感覺總算萬事大吉利了,那個手機試一把,用iPhone的Safari瀏覽器代開後,依然並沒有什麼卵用。是的,九成是瀏覽器兼容問題,查看CanIUse,果不其然。
圖片描述
那麼既然如此,剩下的解決方案,就只有在綁定事件的時候顯式的設置{ passive: false },查了一圈React文檔也沒發現,可以支持配置這個屬性的方法。此處真心感嘆一句不如Vue方便,如果是Vue就可以這麼寫:

<div v-on:touchmove.prevent="handleTouchMove"></div>

既然如此,就只能用原生的事件綁定了

document.getElementById("picker").addEventListener('touchmove', this.handleTouchMove, { passive: false });

終於,世界和平了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章