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

更新 : 2019-03-22 css

之前覺得 hammer 的觸發順序是 parent -> child 和咱們經常使用的 js 冒泡相反 . git

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

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

<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 個. angular2

left 獲取到 left, keat 獲取到 right app

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

 

 

 

更新 : 2019-03-12 ide

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 的順序, 反過來就不觸發了. ui

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 事件. 

若是你有好方法歡迎你留意告訴我哦. 

相關文章
相關標籤/搜索