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