移动开发框架剖析(二) Hammer专业的手势控制
瀏覽器底層并沒有給元素提供類似,單擊,雙擊,滑動,拖動這些直接可以用的控制接口,一切的手勢動作都只能通過模擬出來。移動端瀏覽器唯一給我們提供的就只是mousedown -> mousemove -> mouseup三種最基本的事件接口。那么我們只能通過這些簡單的接口模擬出復雜的手勢出來。
常規的做法流程:
1.給元素上綁定三個事件,mousedown ,mousemove,mouseup
2.在交互的時候,用戶只觸發mousedown,mouseup沒有觸發mousemove,就可以單算是一次點擊的動作, 這里可以是 單擊,雙擊與長按,具體可以通過間隔的時間判斷
3.如果mousemove觸發了,自然就是滑動與拖動了
當然手勢還要涉及到多點操作縮放與旋轉的處理,就之后在討論。
?
先拋開流程,我們要知道設計一個手勢庫需要考慮的問題,至少有2點:
1.運行的平臺
2.用戶的手勢
?
那么我們可以總結市面上的終端設備有那么三種:
1 手機/pad移動端
2 pc類
3 還有種帶觸摸屏的電腦一類
?
用戶的手勢行為大體分:
單擊tap , 雙擊doubletap,平移pan,滑動swipe,長按press,縮放pinch,旋轉rotate
?
從設計的角度來講,有著不同的兼容與選擇問題,卻又有著一些相同的共性與處理我們要如何去組織結構?
當然依舊是OOP設計了,抽出父類,實現繼承,引入策略模式
我們看看Hammer在結構上是如何實現這類設計的
常規來說手勢的處理,要分為初始化與執行期。初始化的時候構建所有相關的參與與方法
hammer源碼里面分幾大塊:
1. Hammer類,一個簡單的工廠方法,用來創建一個管理和初始化默認的識別器。Hammer.defaults配置一些基本的選項
包括針對每種識別器的配置與元素CSS屬性的設置
2. Manager類,整個庫的管理類。內部初始化了input輸入對象,所有手勢對象,元素css設置對象touchAction
3. InputHandler類,事件回調的具體加工類,用來生成包裝后的事件對象與派發事件到每一個識別器
4. TouchAction類,設置元素的touchAction屬性
5. Input類,事件處理類。用來處理綁定與銷毀,事件句柄的回調。每一個輸入類都需要繼承
6. Recognizer類,所有識別器需要繼承的基類
以上就是整個庫的類塊了,當然5與6都是屬于基類繼承的,在代碼運行的時候就自動構建完畢了
?
關于繼承inherit方法
hammer用的是傳統的類似繼承
function inherit(child, base, properties) {var baseP = base.prototype,childP;childP = child.prototype = Object.create(baseP);childP.constructor = child;childP._super = baseP;if (properties) {extend(childP, properties);} }只繼承了原型的方法,因為原型都是共享的,如果放置屬性可以被任何一個繼承的子類所有修改,所以屬性的繼承需要用call方法
繼承的子類有一個私有屬性 _super指向父類,同時還能額外的擴展方法
inherit(MouseInput, Input, {handler: function MEhandler(ev){} }子類MouseInput繼承父類Input類的所有原型方法,并擴展了handler方法
?
輸入設備初始化繼承:就是通過什么設備觸發動作(PC,手機,ipad等等)
輸入設備hammer分為
MouseInput,PointerEventInput,SingleTouchInput,TouchInput,TouchMouseInput
我們看看最簡單的桌面PC的鼠標輸入處理MouseInput,其余的結構基本類似。
function MouseInput() {this.evEl = MOUSE_ELEMENT_EVENTS;this.evWin = MOUSE_WINDOW_EVENTS;//用來禁止TouchMouse事件this.allow = true; // used by Input.TouchMouse to disable mouse events//鼠標按下的狀態this.pressed = false; // mousedown stateInput.apply(this, arguments); }inherit(MouseInput, Input, {handler: function MEhandler(ev){..// } }MouseInput初始化了幾個必要的判斷屬性,然后就只handler方法, 此外還集成了Input輸入類
比如我們調用
new MouseInput(callback)的時候,通過Input.apply(this, arguments)去初始化了基類input類,然后基類內部的init綁定了事件,并且把事件的回調,
this.domHandler指向了外部的callback回調,其實也就是handler方法了
addEventListeners(this.element, this.evEl, this.domHandler);?
另一個基類就是Recognizer
因為我們把用戶的行為分為單擊tap , 雙擊doubletap,平移pan,滑動swipe,長按press,縮放pinch,旋轉rotate,那么類似相同點我們也必須抽象成一個基類
Recognizer比如復雜,留在執行期的時候講解。
?
Hammer 使用:
var mc = new Hammer(el);那么內部的構建
function Hammer(element, options) {options = options || {};//配置手勢識別器參數options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);return new Manager(element, options); }可見最終是Manager構建的對象實例了
Manager內部,通過createInputInstance創建一個輸入環境的實例對象,創建一個輸入環境的實例對象
this.input = createInputInstance(this);createInputInstance的作用主要是用來選擇當然的平臺,不同的平臺會調用不同的手勢輸入處理,這里就有策略選擇了的處理了
function createInputInstance(manager) {var Type;var inputClass = manager.options.inputClass;if (inputClass) {Type = inputClass;} else if (SUPPORT_POINTER_EVENTS) {Type = PointerEventInput;} else if (SUPPORT_ONLY_TOUCH) {Type = TouchInput; //移動手機端} else if (!SUPPORT_TOUCH) {Type = MouseInput; //桌面} else {Type = TouchMouseInput;} }如果是桌面PC端,我們就會走MouseInput
return new MouseInput(manager, inputHandler);這樣把具體的通過Input類綁定的回調放到MouseInput的handler處理了,最終的回調會進入總處理inputHandler類
inputHandler類就會遍歷所有的手勢識別器把輸入的input傳入
manager.recognize(input);每一個識別器各自處理其行為了,當然這里面倒是如何觸發,手勢識別器如何判斷是那種手勢,就放一章了。
?
官方:http://hammerjs.github.io/
我的:https://github.com/JsAaron/hammer-js
?
總結
以上是生活随笔為你收集整理的移动开发框架剖析(二) Hammer专业的手势控制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux shell取变量的子串26种
- 下一篇: ldconfig和ldd用法