Vue.js 移動端 Web App 點擊穿透問題解決方案

描述

在近期的一個移動端項目中,有一個頁面需要有彈框提示,並且這個彈框通過關閉按鈕關閉。頁面當中使用了 iScroll 來實現頁面局部滾動,在 iScroll 的配置當中把 tap 和 click 事件都開啓了。
代碼如下:

this.myScroll = new IScroll(this.$refs.wrapper, {  mouseWheel: true,  click: true,  tap: true})

在實現過程中,遇到了一個奇怪的問題,由於按鈕的位置與彈框右上角的關閉按鈕位置一致,當我點擊按鈕時,彈框一閃而過。

效果如下:
效果圖

原因

什麼是點擊穿透?

假如頁面上有兩個元素A和B。B元素在A元素之上。我們在B元素的touchstart事件上註冊了一個回調函數,該回調函數的作用是隱藏B元素。我們發現,當我們點擊B元素,B元素被隱藏了,隨後,A元素觸發了click事件。

通過上網查找有關資料,翻閱了移動端的書籍,發現在手機端中,事件的觸發順序爲:touchstart -> touchmove -> touchend,而 click 事件有 300ms 的延遲,當 touchstart 事件把B元素隱藏之後,隔了300ms,瀏覽器觸發了 click 事件,但是此時B元素不見了,所以該事件被派發到了A元素身上。如果A元素是一個鏈接,那此時頁面就會意外地跳轉。

解決方案

1. 改用 touch 事件

由於項目使用的是 Vue.js,這裏就提供一下 Vue.js 的解決方法。使用了 vue-tap 的一個插件,具體使用方法參看官方文檔,在需要點擊事件的時候,通過 v-tap 指令來綁定。

// main.jsimport vueTap from 'v-tap' // 引入插件Vue.use(vueTap) // 全局註冊
v-tap="{methods:showReceiveModel}" // 在元素上綁定事件

2. 使用 fastclick 插件

這個也是在網上看到的,也可以解決點透問題,使用方法可以看 fastclick 的文檔,在這裏提供一下 Vue.js 的引入及使用

import FastClick from 'fastclick'; // 引入插件FastClick.attach(document.body, options); // 使用 fastclick

最終沒有使用這個方案是因爲有一些小 bug ,如 Fastclick 導致click事件觸發兩次的問題

其他

tap 一詞

對於 tap 這個詞,用過 Zepto 或 KISSY 等移動端js庫的人肯定對tap事件不陌生,做PC頁面時綁定 click,相應地手機頁面就綁定 tap。但原生的 touch 事件本身是沒有 tap 的,js庫裏提供的tap事件都是模擬出來的。

手機上響應 click 事件會有300ms的延遲,那麼這300ms到底是幹嘛了?瀏覽器在 touchend 後會等待約300ms,原因是判斷用戶是否有雙擊(double tap)行爲。如果沒有 tap 行爲,則觸發 click 事件,而雙擊過程中就不適合觸發 click 事件了。由此可以看出 click 事件觸發代表一輪觸摸事件的結束。

既然說tap事件是模擬出來的,我們可以看下 Zepto 對 singleTap 事件的處理。見 源碼 136-143 行,可以看出在 touchend響應 250ms 無操作後,則觸發 singleTap

參考

博文

書籍

  • 《移動 Web 手冊》


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