移動web開發之touch事件

来源:https://www.cnblogs.com/xiaohuochai/archive/2018/01/16/8293225.html
-Advertisement-
Play Games

前面的話 iOS版Safari為了向開發人員傳達一些特殊信息,新增了一些專有事件。因為iOS設備既沒有滑鼠也沒有鍵盤,所以在為移動Safari開發交互性網頁時,常規的滑鼠和鍵盤事件根本不夠用。隨著Android 中的WebKit的加入,很多這樣的專有事件變成了事實標準,導致W3C開始制定Touch ...


前面的話

  iOS版Safari為了向開發人員傳達一些特殊信息,新增了一些專有事件。因為iOS設備既沒有滑鼠也沒有鍵盤,所以在為移動Safari開發交互性網頁時,常規的滑鼠和鍵盤事件根本不夠用。隨著Android 中的WebKit的加入,很多這樣的專有事件變成了事實標準,導致W3C開始制定Touch Events規範。本文將詳細介紹移動端touch事件

 

概述

  包含iOS 2.0軟體的iPhone 3G發佈時,也包含了一個新版本的Safari瀏覽器。這款新的移動Safari提供了一些與觸摸(touch)操作相關的新事件。後來,Android上的瀏覽器也實現了相同的事件。觸摸事件會在用戶手指放在屏幕上面時、在屏幕上滑動時或從屏幕上移開時觸發。具體來說,有以下幾個觸摸事件

touchstart:當手指觸摸屏幕時觸發;即使已經有一個手指放在了屏幕上也會觸發
touchmove:當手指在屏幕上滑動時連續地觸發。在這個事件發生期間,調用preventDefault()可以阻止滾動
touchend:當手指從屏幕上移開時觸發
touchcancel:當系統停止跟蹤觸摸時觸發(不常用)。關於此事件的確切觸發時間,文檔中沒有明確說明

【touchenter 和 touchleave】

  觸摸事件規範中曾經包含touchenter和touchleave事件,這兩個事件在用戶手指移入或移出某個元素時觸發。但是這兩個事件從來沒有被實現。微軟有這兩個事件的替代事件,但是只有IE瀏覽器支持。某些情況下可以知道用戶手指滑入滑出某個元素是素是非常有用的,所以希望這兩個事件可以重返規範

  在觸摸事件中,常用的是touchstart、touchumove和touchend這三個事件,與滑鼠事件的對應如下

滑鼠         觸摸          
mousedown   touchstart 
mousemove   touchmove   
mouseup     touchend     

   [註意]touch事件在chrome模擬器下部分版本使用DOM0級事件處理程式的方式來添加事件無效

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    #test{height:200px;width:200px;background:lightblue;}
  </style>
</head>
<body>
<div id="test"></div>
<script>
  (function(){ 
    var 
      stateMap = {
        touchstart_index : 0,
        touchmove_index  : 0,
        touchend_index   : 0
      },
      elesMap = {
        touch_obj: document.getElementById('test')
      },
      showIndex, handleTouch;

    showIndex = function ( type ) {
      elesMap.touch_obj.innerHTML = type + ':' + (++stateMap[type + '_index']);
    };

    handleTouch = function ( event ) {
      showIndex( event.type );
    };

    elesMap.touch_obj.addEventListener('touchstart', function(event){handleTouch(event);}); 
    elesMap.touch_obj.addEventListener('touchmove', function(event){handleTouch(event);});
    elesMap.touch_obj.addEventListener('touchend', function(event){handleTouch(event);});
  })(); 

</script>
</body>
</html>

 

300ms

  300ms問題是指在某個元素執行它的功能和執行touch事件之間有一個300毫秒的間隔。滑鼠事件、焦點事件、瀏覽器預設行為等相較於touch事件,都存在著300ms的延遲

【點透】

  因為300ms的存在,會造成常見的點透問題。先來看例子

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    #test {position: absolute;top: 0;left: 0;opacity: 0.5;height: 200px;width: 200px;background: lightblue;}
  </style>
</head>
<body>
  <a href="https://baidu.com">百度</a>
  <div id="test"></div>
  <script>
    (function () {
      var
        elesMap = {
          touchObj: document.getElementById('test')
        },
        fnHide, onTouch;
      fnHide = function (type) {
        elesMap.touchObj.style.display = 'none';
      };
      onTouch = function (event) {
        fnHide();
      };
      elesMap.touchObj.addEventListener('touchstart', function(event){onTouch(event);});
    })(); 
  </script>
</body>
</html>

  淺藍色的半透明div被點擊(觸發touch事件)後,如果點擊位置正好位於鏈接的上方,則會觸發鏈接跳轉的預設行為。詳細解釋是,點擊頁面後,瀏覽器會記錄所點擊的頁面坐標,300ms後,在該坐標找到元素。在該元素上觸發點擊行為。因此,如果300ms內同一頁面坐標的上層元素消失後,300ms後在下層元素上觸發點擊行為。這就造成了點透問題

  造成這個問題,是因為觸摸屏幕的行為被重載(overload)了。在手指觸摸屏幕的瞬間,瀏覽器無法預知用戶是在輕觸(Tap)、雙觸(Double-Tap)、滑動(Swipe)、按住不放(Hold)還是其他什麼操作。唯一保險的做法就是等上一會兒看接下來會發生什麼

  問題是在於雙觸(Double-Tap)。即便是瀏覽器檢測出手指離開了屏幕,它仍然無法判斷接下來做什麼。因為瀏覽器無法知道手指是會再次回到屏幕,還是就此結束觸發輕觸事件以及事件級聯。為了確定這一點,瀏覽器不得不等待一小段時間。瀏覽器開發者找到一個最佳時間間隔,就是300毫秒

【解決辦法】

  1、在touch事件的事件處理程式中增加300ms的延遲

    (function () {
      var
        elesMap = {
          touchObj: document.getElementById('test')
        },
        fnHide, onTouch;
      fnHide = function (type) {
        elesMap.touchObj.style.display = 'none';
      };
      onTouch = function (event) {
        setTimeout(function(){
          fnHide();
        },300);
      };
      elesMap.touchObj.addEventListener('touchstart', function (event) { onTouch(event); });
    })(); 

  2、使用緩動動畫,增加300ms的過渡效果,註意display屬性無法使用transition

  3、加入中間層的dom元素,讓中間層接受這個穿透事件,稍後隱藏

  4、上下兩級都使用tap事件,但預設行為不可避免

  5、在document上的touchstart事件,阻止預設行為。

document.addEventListener('touchstart',function(e){
    e.preventDefault();
})

  接著,添加a標簽的跳轉行為

a.addEventListener('touchstart',function(){
  window.location.href = 'https://cnblogs.com';  
})

  但是,這種方法有副作用,會造成頁面無法滾動、文本無法選中等。如果在某個元素上,需要恢覆文本選中的行為,則可以使用阻止冒泡來恢復

el.addEventListener('touchstart',function(e){
    e.stopPropagation();
})

  

事件對象

【基礎信息】

  每個觸摸事件的event對象都提供了在滑鼠事件中常見的屬性,包括事件類型、事件目標對象、事件冒泡、事件流、預設行為等

   以touchstart為例,示例代碼如下

  <script>
    (function () {
      var
        elesMap = {
          touchObj: document.getElementById('test')
        },
        onTouch;
      onTouch = function (e) {
          console.log(e)
    };
      elesMap.touchObj.addEventListener('touchstart', function (event) { onTouch(event); });
    })(); 
  </script>

  1、currentTarget屬性返回事件正在執行的監聽函數所綁定的節點

  2、target屬性返回事件的實際目標節點

  3、srcElement屬性與target屬性功能一致

//當前目標
currentTarget:[object HTMLDivElement]
//實際目標
target:[object HTMLDivElement]
//實際目標
srcElement:[object HTMLDivElement]

  4、eventPhase屬性返回一個整數值,表示事件目前所處的事件流階段。0表示事件沒有發生,1表示捕獲階段,2表示目標階段,3表示冒泡階段

  5、bubbles屬性返回一個布爾值,表示當前事件是否會冒泡。該屬性為只讀屬性

  6、cancelable屬性返回一個布爾值,表示事件是否可以取消。該屬性為只讀屬性

//事件流
eventPhase: 2
//可冒泡
bubbles: true
//預設事件可取消
cancelable: true

【touchList】

  除了常見的DOM屬性外,觸摸事件對象有一個touchList數組屬性,其中包含了每個觸摸點的信息。如果用戶使用四個手指觸摸屏幕,這個數組就會有四個元素。一共有三個這樣的數組

  1、touches:當前觸摸屏幕的觸摸點數組(至少有一個觸摸在事件目標元素上)

  2、changedTouches :導致觸摸事件被觸發的觸摸點數組

  3、targetTouches:事件目標元素上的觸摸點數組

  如果用戶最後一個手指離開屏幕觸發touchend事件,這最後一個觸摸點信息不會出現在targetTouches和touches數組中,但是會出現在changedTouched數組中。因為是它的離開觸發了touchend事件,所以changedTouches數組中仍然包含它。上面三個數組中,最常用的是changedTouches數組

    (function () {
      var
        elesMap = {
          touchObj: document.getElementById('test')
        },
        onTouch;
      onTouch = function (e) {
          elesMap.touchObj.innerHTML = 'touches:' + e.touches.length
                                    + '<br>changedTouches:' + e.changedTouches.length
                                    + '<br>targetTouches:' + e.targetTouches.length;
      };
      elesMap.touchObj.addEventListener('touchstart', function (event) { onTouch(event); });
    })(); 

【事件坐標】

  上面這些觸摸點數組中的元素可以像普通數組那樣用數字索引。數組中的元素包含了觸摸點的有用信息,尤其是坐標信息。每個Touch對象包含下列屬性

clientx:觸摸目標在視口中的x坐標
clientY:觸摸目標在視口中的y坐標
identifier:標識觸摸的唯一ID
pageX:觸摸目標在頁面中的x坐標(包含滾動)
pageY:觸摸目標在頁面中的y坐標(包含滾動)
screenX:觸摸目標在屏幕中的x坐標
screenY:觸摸目標在屏幕中的y坐標
target:觸摸的DOM節點目標

  changedTouches數組中的第一個元素就是導致事件觸發的那個觸摸點對象(通常這個觸摸點數組不包含其他對象)。這個觸摸點對象含有clientX/Y和pageX/Y坐標信息。除此之外還有screenX/Y和x/y,這些坐標在瀏覽器間不太一致,不建議使用

  clientX/Y和pageX/Y的區別在於前者相對於視覺視口的左上角,後者相對於佈局視口的左上角。佈局視口是可以滾動的

    (function () {
      var
        elesMap = {
          touchObj: document.getElementById('test')
        },
        onTouch;
      onTouch = function (e) {
        var touch = e.changedTouches[0];
        elesMap.touchObj.innerHTML = 'clientX:' + touch.clientX + '<br>clientY:' + touch.clientY
          + '<br>pageX:' + touch.pageX + '<br>pageY:' + touch.pageY
          + '<br>screenX:' + touch.screenX + '<br>screenY:' + touch.screenY
      };
      elesMap.touchObj.addEventListener('touchstart', function (event) { onTouch(event); });
    })(); 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • getDimension() 返回float型px值 精確 getDimensionPixelOffset() 返回int型px值 直接把小數刪除 getDimensionPixelSize() 返回int型px值 進行四捨五入 ...
  • 今天在做項目的時候自定義了一個View,繼承了LinearLayout,結果,裡面的onDraw()方法一直無法被調用。 後來發現ViewGroup是預設不調用onDraw()方法的。 原因我們暫且不去深究,有一個很簡單的解決方法,那就是不要重寫onDraw()方法,而是重寫下麵的方法: 在該方法里 ...
  • 很多時候,我們需要獲取別人的apk的信息。但是我們看不到apk的代碼,對於apk的信息並沒有直接的方法獲取。那麼,我們要怎麼獲取apk信息呢? 這裡,我整理了兩個方法,親測可用。 第一種,直接使用Android Studiod打開第三方apk,查看AndroidManifest.xml,可以查看大部 ...
  • 源碼下載:http://download.csdn.net/download/jjhahage/10034519 PS:一般情況下,我們在寫android程式的時候,想要實現登錄註冊功能,可以選擇自己用servlet作為服務端來實現過濾沒有註冊過的用戶,但是太麻煩,而且不是隨時都可以用的。這裡介紹一 ...
  • 比如 你想加一個百度的外鏈:那麼你就寫一個 百度:https://www.baidu.com ...
  • 1、概述 所有的typeof返回值為‘object’的對象都包含一個內部屬性[[Class]],我們將它可以看做內部的分類,而非傳統面向對象意義的分類。這個屬性無法直接訪問,一般通過Object.prototype.toString來查看。 2、示例代碼 ...
  • 1. 使用 video 元素的 ControlList API 通過 ControList API,不僅可以通過設置 nodownload 來隱藏下載按鈕,還可以設置 nofullscreen 隱藏全屏按鈕, 以及noremoteplayback 等屬性,具體的示例可以參考 github pages ...
  • 細數了一下,居然已經有連續5天沒有寫JS代碼,簡直醉了,這樣學習怕是根本學不好哦。 我在這裡定下一個規矩,晚上6點半鐘必須要回來,而且是必須要到圖書館寫代碼,9點半鐘一定要開始寫博客,確保每天有3個整小時的時間來學習JavaScript。 已經是1月中下旬了,自己知道自己的處境,現在基本上就只會一個 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...