angular2 學習筆記 の 移動端開發 ( 手勢 )


更新 : 2019-03-22 

以前以為 hammer 的觸發順序是 parent -> child 和我們常用的 js 冒泡相反 . 

今天才知道原來 hammer 根本沒有冒泡或者捕獲的概念,你先綁定哪一個事件它就觸發哪一個. 暈 ~ 

hammer 還有一個看上去好像 bug 的問題 

<div id="keat" class="keat">
    <div id="left" class="left"></div>
    <div id="right" class="right"></div>
</div>
const left = new Hammer(document.getElementById('left'));
left.on('panstart', (e: HammerInput) => console.log(e.target));

const keat = new Hammer(document.getElementById('keat'));
keat.on('panstart', (e: HammerInput) => console.log(e.target));

如果我們起始點是 left 然后 10px 后在 right, 這時 hammer 觸發獲取到的 e.target 會有 2 個. 

left 獲取到 left, keat 獲取到 right 

如果我們依賴 e.target 做判斷要不要觸發 event handler 可能就會遇到坑了.  目前沒有辦法解決. 我是想辦法讓用戶避開這種交互. 

 

 

 

更新 : 2019-03-12 

double tap 

var manager = new Hammer(el);
const tap = manager.get('tap');
manager.remove('tap');

var doubleTap = new Hammer.Tap({
    event: 'doubletap',
    taps: 2
});

manager.add([doubleTap, tap]);

tap.requireFailure(doubleTap);
doubleTap.recognizeWith(tap);


manager.on('doubletap', function (e) {
    console.log('doubletap');
});

manager.on('tap', function (e) {
    console.log('tap');
});

留意 manager.add array 的順序, 反過來就不觸發了. 

double tap 和 tap 要互相認識一下. 因為彼此是有影響的.

 

 

 

更新 : 2018-01-31 (hammer 的坑)

hammer 的 pinch 在某種情況下會自動觸發 panEnd,很奇葩.

解決方法就是記入時間唄 

refer : https://github.com/hammerjs/hammer.js/issues/1134

 

hammer 有鬼, ghost click 

如果你使用 pan + click 你會發現觸發是這樣的 panStart->panMove->panEnd->click 

這個 browser 的行為有點不同 

browser 是 mousedown -> mouseup -> click 或者 mousedown -> mousemove -> 沒了 

只要有 move click 事件是不會觸發的. 

所以這點要特別留意, 如果你不希望這個 ghost click 發生, hammer 也給出了方法 

refer : 

http://hammerjs.github.io/tips/

https://gist.github.com/jtangelder/361052976f044200ea17

就是在 click 時做一個判斷. 

另外提一個奇葩場景,如果你 bind 了 dragStart 然后 event.preventDefault 那么這個 ghostclick 是會被取消的, 但是 dragStart 是否每一次都會觸發很難說 (我們看過 hammer 源碼,不過我覺得它視乎動了點手腳).

 

 

更新 : 2018-01-18 

今天開發的時候遇到了一些奇葩形象. 

看了看源碼理清一下之前沒有講清楚的點

1. ng 有 3 個 Event Plugin (自己想擴展多幾個是 ok 的), Dom Event Plugin, KeyBoard Event Plugin, HammerGesture Plugin 

2. 所有的 plugin in 都必須在 app 級的 providers 去提供, lazy load 就遲了 (refer : https://github.com/angular/material2/issues/7905  and https://github.com/angular/angular/issues/19874) 

3. angular material 的 MatSliderModule 會去覆蓋 hammer 的 config ( 和我以前說到的方式是一樣的 ) . 

所以問題來了.

1. 你要 angular material 的 MatSliderModule 的手勢 work good, 那么就一定要在 app 級注入這個模塊, 或者提供它的手勢 override 在 app providers (原因是上面第 2 條)

2. 如果你自己有一套 hammer config 邏輯, 那么注定會和 material 的 config 打架 ( 上面的 第 3 條 ), ng 只運行一個 hammer config 

怎么破 ? 

目前沒有什么好方法. 大費周章的做法是, 開發一套 MyHammerGesture Plugin 並且把監聽 (pan)="do()"  換成 (myPan)="do()"  這樣就不會和它們打架咯. 

material team 給出了一個方向

https://github.com/angular/material2/issues/4595

大致上就是他們以后會使用 service, 我個人覺得把 config 讓出來給 app 是對的,如果我們寫自己的庫也應該自己封裝 hammer 而不是用掉只有一個的 config.

 

 

更新 : 2017-12-28

hammer 的綁定流程是, 選擇 element -> 實例化 hammer -> 設置 hammer (default 有些設置是關上的) -> 綁定監聽事件. 

pinch 和 rotate 設置默認是關上的, 想監聽就要先打開設置, 這 2 個事件 hammer 會使用 css touch-action : none 來禁止游覽器處理 touch (意思是說不能 scroll 了)

hammertime.get('pinch').set({ enable: true }); hammertime.get('rotate').set({ enable: true });

pan 和 swipe 默認設置是處理 horizontal 橫向而已, 直的話是游覽器的 scroll, touch-action : pan-y, 如果要監聽多點就打開設置 

hammertime.get('pan').set({ direction: Hammer.DIRECTION_ALL }); hammertime.get('swipe').set({ direction: Hammer.DIRECTION_VERTICAL });

以上是 hammer 的基本處理思路, 默認情況下讓游覽器可以 scroll. 要處理更多就自己設置吧. 

ng 方面. 之前(看下面) 有提到過了. 所有的手勢 ng 都會開啟 hammer 的 pinch 和 rotate 設置, 也就是說即使你只是寫了一個 (tap) 事件, 你的 element 就不能 scroll 了. 

為什么 ng 要這樣呢, 我也不知道. 可能懶得去理會吧. 全部開啟設置, 才能統一方式綁定 (pinch) 和 (rotate) 嘛. 

一直沒有好的解決方法 ng 沒什么接口方便我們覆蓋這個邏輯 

refer : https://medium.com/@TheLarkInn/creating-custom-dom-events-in-angular2-f326d348dc8b  (ng 自定義事件綁定)

ng 的 dom event 源碼 

https://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/events/dom_events.ts

https://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/events/event_manager.ts

https://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/events/hammer_gestures.ts

https://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/events/key_events.ts

幾個方法參考 : 

1. 直接調用 Hammer 不用 ng 的綁定 

2. 覆蓋 HammerGestureConfig.buildHammer 方法, 這個方法只能獲取到 element, 所以我們通過在 element 上面寫 data-need-rotate or data-need-pinch 之類的表達, 來實現不同情況下不同的 hammer 設置 

3. 覆蓋 HammerGesturesPlugin 來個統統重寫... 

我目前用了第 2 個 方案. 暫時挺着吧. 

 

 

更新 22-08-2017

hammerjs 的事件有不同的設置 options 

var myElement = document.getElementById('myElement');
var mc = new Hammer(myElement);
mc.get('pan').set({ direction: Hammer.DIRECTION_ALL });
mc.on("panleft panright panup pandown tap press", function(ev) {
    myElement.textContent = ev.type +" gesture detected.";
});

pan 事件默認的 direction 是沒有包含上下移動的, 那我們可以自己去設置它. 

而 Angular 默認會幫我們把所有的 hammer 都設置一遍如下的代碼

這 2 個設置會讓所有的 hammer element 無法滾動. 這個要注意哦. 

我們可以通過 overrides 去添加和覆蓋上面的邏輯. 

  providers: [{
    provide: HAMMER_GESTURE_CONFIG,
    useClass: MyHammerConfig
  }]


export class MyHammerConfig extends HammerGestureConfig {
    overrides = <any>{
        'pan': { direction : Hammer.DIRECTION_ALL } 
    }
}

大概這樣就可以了,不過呢這個 config 是全局的. 目前我還沒發放可以針對不同的 element 設置不同的 config .

可能需要直接調用 hammerjs 才可以了。

 

 

 

refer : 

http://hammerjs.github.io/

https://bevacqua.github.io/dragula/

 

手機 和 PC 在交互體驗上最大的區別是交互工具不同.

PC端,我們用滑鼠 

手機端, 我們用觸屏

滑鼠 vs 觸屏 

滑鼠有 hover 概念, 觸屏沒有.

觸屏能多點 (多種手勢), 滑鼠沒有.

responsive design 解決了視覺上的差異問題,卻沒有解決交互上的差異問題. 

hammerjs 幫我們解決的是滑鼠, 觸屏之前的差異問題.

比如 : 監聽各種手勢, click 的 delay 300ms 問題, touchmove 模擬成 mousemove 事件等等. 

angular 認可 hammerjs, 所以只要你 import hammerjs, 你可以直接這樣寫

<div (tap)="test()" >
  test
</div>

angular 會使用 hammerjs 的方法來綁定 tap 事件. 很方便吧 ?

使用 npm 加載 

  "dependencies": { 
    "hammer-timejs": "^1.1.0",
    "hammer-touchemulator": "0.0.2",
    "hammerjs": "^2.0.8", 
  },
  "devDependencies": { 
    "@types/hammerjs": "^2.0.34", 
  }

在 main.ts 里 import 就可以啦

import 'hammerjs';
import 'hammer-timejs';
import * as TouchEmulator from 'hammer-touchemulator';
TouchEmulator();

TouchEmulator 是 development 情況下的才使用的.

手機還有一個問題就是在 drag and drop. 原生游覽器的 drag and drop 在手機端支持的不好. 

很多人會用 touchmove 來模擬. 也就是 hammerjs 里面的 pan 事件. 

但是具體做法還是挺困難的. 

因為觸屏沒有 hover 概念, 也沒 touchover 事件, 所以當用戶 pan 的時候你並沒有辦法輕易的監聽 dragover 來處理事情. (比如你要做 sorting)

我在網上看了一些人的做法是通過 document.elementFromPoint(x,y) 來獲取交會的節點或則每一次 pan 的時候都通過 service 發布事件, 然后其它組件監聽, 在依據自己的 element.getBoundingClientRect 的 

position 來確定是否 over 到了 element. 簡單就說就是模擬 dragover 事件. 

如果你有好方法歡迎你留意告訴我哦. 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM