您的位置:首页 > 其它

02_核心概念--05_手势

2017-06-10 19:33 239 查看
除了标准的DOM事件,元素还能触发合成的手势事件。从浏览器的角度来看,有三个主要的类型,包括指针,触摸和鼠标事件-开始,移动和结束。
EventTouchPointerMouse
Starttouchstartpointerdownmousedown
Movetouchmovepointermovemousemove
Stoptouchendpointerupmouseup
通过解决这些事件的顺序和时间,框架能够合成更复杂的事件,例如drag,swipe,longpress,pinch,rotate和tap。ExtJS程序能够监听手势事件,如同监听其它事件一样,例如:Ext.get('myElement').on('longpress',handlerFunction);通过合成上述三种类型的事件,鼠标,指针和触摸,ExtJS能够让任何手势对任意输入作出反应。这意味着,不仅所有的手势事件可以触发,而且所有通过鼠标完成的单点手势(如tap,swipe等)也能够被触发。最终生成一个手势系统,该系统可以在各种输入类型的设备之间无缝地正常工作。ExtJS现在支持如下的手势:
GestureEvents
Taptap,tapcancel
DoubleTapsingletap,doubletap
LongPresslongpress
Dragdragstart,drag,dragend,dragcancel
Swipeswipestart,swipe,swipecancel
Pinchpinchstart,pinch,pinchend,pinchcancel
Rotaterotatestart,rotate,rotateend,rotatecancel
EdgeSwipeedgeswipe,edgeswipestart,edgeswipeend,edgeswipecancel

指针类型

在一些特殊情况下,应用需要监听由某种特定的输入设备(鼠标或触摸屏)触发的手势,而忽略其它类型的设备。ExtJS在事件对象上提供了一个pointerType属性来判断引起事件的输入设备的类型。
el.on('drag',function(e){
if(e.pointerType==='touch'){
//onlyhandletouch-drag,andignoremouse-drag
}
});

事件传播

事件在框架中的传播跟DOM事件在浏览器中的传播十分相似。不同点在于框架使用了一个事件代理模型,目的是为了支持手势识别。这意味着事件在一个单独的传播阶段被传递到DOM元素,这个传播阶段是在事件已经在DOM级别完成传播时发生的。

原生传播

事件监听器,是被直接附加到一个DOM元素上。当浏览器通过DOM结构传播事件时,事件监听器将会被调用。虽然理解原生传播的机制也是十分有用的,但在ExtJS中,直接附加的DOM监听器通常会因如下原因避免:*直接附加的监听器的触发顺序与其它监听器不一致。*从直接附加的监听器里调用stopPropagation会阻止手势识别的发生,也会阻止相关的合成传播。然而,在一些情况下,直接附加一个监听器到一个DOM元素上是十分必要的,例如,当使用ExtJS与其它框架一起解决问题时。这可以使用delegated事件选项来完成。
el.on({
mousedown:function(){
Ext.Msg.alert('mousedownfired-nativecapturephase');
},
//carefulwhenusingdelegated:false!thiscanhaveunintendedsideeffects
delegated:false,
//usethecaptureoptiontolisteninthecapturephase
capture:true
});
DOM级别的事件传播发生在两个阶段。第一个阶段是捕获阶段,在这个阶段,事件被派发到从DOM顶层开始的每个元素,从window对象开始,所有的经过事件传播途径的元素,直到事件的目标元素。捕获阶段过后,冒泡阶段就发生了。在冒泡阶段,事件从目标元素开始被传递,然后到它的祖先元素(例如父元素),直到它达到结构的最顶层。默认情况下,监听器是在冒泡传播阶段被触发的,但相关的部分监听器可以通过capture事件选项来设置到捕获阶段。

手势识别

在原生的事件冒泡到达窗体对象后,ExtJS执行手势识别。然后系统会合成一个或多个手势事件,这些事件一定会通过DOM传播。

合成传播

在手势识别阶段完成后,框架将派发原生的DOM事件,例如,mousedown或者touchmove,同时也会派发其它的手势事件,例如drag或者swipe,这些手势事件可以被看作是DOM事件的结果。跟原生传播一样,合成传播也发生在两个阶段,捕获阶段和冒泡阶段。合成传播在框架中对所有事件是默认的事件传播方式,在使用ExtJS的程序中也是被推荐使用的传播方式。使用合成传播方式能保证事件与其它事件按照合适的顺序触发,能够避免因为某些原因导致的传播停止而引起的异常。开发者不需要做任何事情来激活合成传播-下面的监听器使用了合成传播:
el.on('mousedown',function(){
Ext.Msg.alert('mousedownfired-syntheticbubblephase');
});
当然,使用capture选项可以将监听置于捕获阶段:
el.on({
mousedown:function(){
Ext.Msg.alert('mousedownfired-syntheticcapturephase');
},
capture:true
});

停止传播

在原生传播和合成传播过程中的任何一点,传播都可以被停止,不管是在捕获阶段还是在冒泡阶段。这阻止了事件被派发到任何还没有收到事件的元素上,同时也阻止了悬停的捕获和冒泡阶段的继续执行。例如,当一个事件被派发到一个元素时,阻止该传播会阻止事件冒泡到父元素:
parentEl.on('mousedown',function(){
//neverfiresbecausechildelementinbubblephasestopspropagationofmousedown
Ext.Msg.alert('mousedownfiredonchild');
});

el.on('mousedown',function(e){
Ext.Msg.alert('mousedownfiredonchild');

//immediatelystoppropagatingtheeventanyfurther
e.stopPropagation();
});
停止在捕获阶段的传播会取消整个冒泡过程。
el.on({
mousedown:function(e){
Ext.Msg.alert('mousedown-capturephase');

//stoppingpropagationduringthecapturephasecausestheentire
//bubblephasetobeskipped
e.stopPropagation();
},
capture:true
});

el.on('mousedown',function(){
//neverfiresbecausepropagationofmousedowneventwasstoppedpriorto
//bubblephase
Ext.Msg.alert('mousedown-bubblephase');
});

手势传播

当一个手势事件被识别时,它会通过DOM层级随着原生事件传播,而手势事件是通过这些原生事件合成的。在一些情况下,多个手势的识别可以同时发生。当这种情况发生时,手势传播会集中在一套单独的捕获或冒泡阶段。例如,假设一个DOM层级结构里面,A元素包含B元素,B元素又包含C元素。假设一个touchmove事件在最里面的C元素上触发了,那么这个touchmove事件符合了drag和swipe手势触发的条件。一旦识别到两个事件,drag和swipe发生,手势发布者发布touchmove,dragstart和swipestart事件,并把这三个事件传送到层级结构的每个元素。

声明手势

有时,在相同层级结构中的元素可以监听冲突的手势。在上面的示例中,想像一下,元素A正在监听swipe事件,同时它的子组件,元素B,在监听drag事件。当元素B处理dragstart事件时,它或许想要阻止当前的手势被swipe事件打断,因为元素A的swipe处理函数或许会与元素B的drag处理函数一起被触发。要想达到这个目的,必须通过调用事件对象上的claimGetture方法来声明drag手势。el.on('dragstart',function(e){e.claimGesture();});一旦claimGesture在dragstart事件对象上被调用,在该事件接下来的时间,该手势就会被识别为一个drag手势(直到用户抬起手指或释放鼠标按钮)。所有与swipe手势相关的事件(swipestart,swipe,swipeend)将会停止触发。此外,因为swipe事件被取消,一个swipecancel事件将会在传播层级结构中被传递到每个元素。

浏览器对手势的处理(触摸动作)

浏览器会自动处理特定的触摸手势,执行默认的行为作为反馈,例如滚动或缩放。这些行为被叫做'touchactions'(触摸动作)。浏览器实现的经典的触摸动作如下:
GestureTouchAction
drag(horizontal)horizontalscroll
drag(vertical)verticalscroll
pinchzoom
doubletapzoom
那些为这些手势实现了它们自己的处理函数的ExtJS应用程序,当这些手势事件被处理时,或许需要禁用一个或多个浏览器默认的触摸处理行为。例如,一个可拖动的元素在它被手动时最希望阻止它的容器的滚动。这个可以通过设置元素的touchAction来实现。//instructthebrowsernottoscrollwhile"el"isbeingdraggedel.setTouchAction({panX:false,panY:false});在CSS的touch-action属性出现并支持相同的值后,ExtJS里的触摸行为的概念被模式化。在后台,框架在浏览器支持使用CSS的touch-action的地方使用它(在那些实现了PointerEvents的浏览器上),在TouchEvents的浏览器上呢,它也会模仿相同的行为。
CSSNameExtJSName
pan-xpanX
pan-ypanY
pinch-zoompinchZoom
double-tap-zoomdoubleTapZoom
当处理组件时,要避免的直接在它们的元素上调用setTouchAction,而是使用组件的touchAction配置项来代替。例如,下面的面板的主元素不允许浏览器垂直滚动,而且它的body元素也不允许pinch-to-zoom(通过捏操作来缩放)或者垂直滚动,因为它通过DOM继承了它的父节点的touchAction。Ext.create('Ext.panel.Panel',{touchAction:{panY:false,body:{pinchZoom:false}},listeners:{drag:function(e){//handledragonthepanel'smainelement},pinch:{element:'body',fn:function(e){//handlepinchonthepanel'sbodyelement}}}});

从长按到拖动

在触摸设备上,有时很难判断一个触摸操作是还应该滚动或拖动一个对象。通常通过时间临界值来判断用户的操作意图。在一个元素上按的时间够长并且手势转换为一个拖操作而不是滚动。现在这项判断可以使用新的可用的startDrag方法,该方法在longpress事件函数里执行。el.on('longpress',function(e){   e.startDrag();});在指针事件浏览器(IE和Edge),当元素被拖动时,你必须在元素上设置相应的触摸行为以阻止浏览器滚动。
el
.setTouchAction({
   panX
:
false,
   panY
:
false
});在触摸事件浏览器(Chrome和Safari)中,为了阻止滚动,配置元素的触摸操作行为也是没有必要的。相反,你可以在拖动事件对象上调用preventDefault方法来阻止滚动的发生。
el
.on('drag',
function(
e
)
{
   e
.preventDefault();
});当preventDefault方法在指针事件型浏览器上阻止滚动不起作用时,在触摸事件型浏览器上,它的优点在于在它能决定是否在运行时允许滚动,而不是提前声明一个触摸行为。对于只需要支持触摸事件型浏览器的应用来说,这将是一个很有用的技巧,然而,对于跨平台应用来说,你必须使用touchActin来阻止滚动。 

视口缩放

这篇指南假定视窗缩放在你的应用中是可用的。比较经典的做法是添加如下的meta标签到你的html页面:<metaname="viewport"content="width=device-width,initial-scale=1,maximum-scale=10,user-scalable=yes">应用如果想禁用视窗绽放应该用如下的meta标签来替换上面的标签:<metaname="viewport"content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">我们推荐一起应用视窗缩放功能,因为它对于视力受损者提高了访问性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: