企业网站包括哪些,游戏代理平台免费版,广西建设工程质量检测协会网站,中企动力企业电子商务概述#xff1a;
DOM的输入事件通过CCInputManager转化成cocos的输入事件#xff0c;由CCEventManager 分发给监听器。
监听器在通过回调函数(begin/move/end/cancel)告知事件派发对象#xff08;eventTarget#xff09;派发事件。
重要类#xff1a;
event#xff1…概述
DOM的输入事件通过CCInputManager转化成cocos的输入事件由CCEventManager 分发给监听器。
监听器在通过回调函数(begin/move/end/cancel)告知事件派发对象eventTarget派发事件。
重要类
event事件信息对象主要有触摸信息、鼠标信息、键盘信息等。
eventTarget 是一个事件派发的对象有注册删除和派发等功能等同于订阅-发布模式。
eventListener是一个事件监听器的对象主要用于创建触摸、鼠标、键盘等监听器。包含了类型、回调函数、优先级等。
eventManager是一个管理监听器的类主要是对监听器进行排序、分发等。
eventManager
属性
了解属性可以很好的知道这个类都有做了那些操作结合函数可以知道是监听器的存储方式划分监听器的对监听器都会做什么处理。 _listenersMap: {}, //key:listenerID value:_EventListenerVector_priorityDirtyFlagMap: {},//用来存储所有脏数据标记位的事件监听器keylistenerID value:boolean_nodeListenersMap: {},//key:node._id,value:listeners[] 存储节点的所有事件监听器_toAddedListeners: [],//存储将要添加的事件监听器_toRemovedListeners: [],//存储将要删除的事件监听器_dirtyListeners: {},//key:listenerID value: boolean_inDispatch: 0,//是否正在处理事件分派标记。 0 表示没有正在处理分派事件_isEnabled: false,//事件管理器是否开启_currentTouch: null,//当前正在处理的触摸事件对象_currentTouchListener: null,//当前正在处理的事件监听器对象_internalCustomListenerIDs: [],//用来存储自定义事件监听器ID
实现功能描述
该类是监听器的管理者因事件监听器有多种类型总共五个因此会对每种类型进行管理。因事件监听器有触发的先后所以在对事件监听器管理的时候加入了优先级概念。分为固定优先级、场景图优先级渲染顺序。
所以每种事件监听器类型都有下列存储结构是
_listenersMap _fixedListeners 用于存储固定优先级的监听器自定义监听器的优先级_sceneGraphListeners 用于存储场景图优先级的监听器就是node的gtOIndex 用于标记固定优先级小于大于0的界限索引值。因为场景图优先级默认等于0自定义优先级可0
事件监听器触发顺序如下
自定义优先级 priority0场景图优先级 listener 触发自定义优先级 priority0的listener 最后触发。gtOIndex的索引等于排序后监听器的priority等于0时在数组中的索引。
自定义优先级时priority值越小优先级越高值越小优先级越低。场景图优先级_localZOrder越大优先级越高。反之优先级越低。 为了可以管理节点上所有的事件监听器有一个以下数据结构
_nodeListenersMap 该数据存储着节点的所有类型的监听器方便对节点上的所有监听器进行选择性的暂停、恢复、删除等功能。
在分发事件监听器时有个很重要的排序过程其目的为了确定事件监听器的触发先后顺序。具体过程如下
与排序相关的几个属性:
_priorityDirtyFlagMap这个map映射存储的是事件监听器类型与脏标记的映射。keyListenerIDvaluedirtyFlag;_dirtyListeners暂时记录了有新的场景图优先级的监听器添加或者是恢复了被暂停的监听器。keyListener; valueboolean
因为每种监听器都有固定优先级和场景图优先级之分。如果有新的事件监听器添加或者恢复都会影响到新监听器相同类型的map数据排序顺序。
所以在每次dispatch的之前都会对脏数据进行更新暂时标记那种类型的监听器脏了。在具体的分发之前会依据标记进行重新排序后再分发。
排序完成之后_priorityDirtyFlagMap的value值都会标记位非脏数据。
同时有个optimize 点只在真正分发时进行一次排序并非在加入监听器或恢复监听器时排序。
另外需要注意的是节点的zIndex值被修改后不单单影响渲染顺序同时也会影响监听器的分发优先级。sortAllchildren
监听器的排序代码解析
自定义优先级排序算法就是根据设置的priority进行升序排序。priority 数值越小越早被分发。以下是场景图优先级的降序排序算法层级越高越早触发与自定义优先级相反。
其主要考虑的问题又如下几个1祖父孙关系。2非同父关系。3同父关系
/**
sort的compare函数。降序
compare(a,b){if(ab)return -1;if(ab)return 1;return 0;
}
**/
_sortEventListenersOfSceneGraphPriorityDes: function (l1, l2) {let node1 l1._getSceneGraphPriority(),node2 l2._getSceneGraphPriority();//此l1优先if (!l2 || !node2 || !node2._activeInHierarchy || node2._parent null)return -1;//l2 优先else if (!l1 || !node1 || !node1._activeInHierarchy || node1._parent null)return 1;/**1如果是祖孙关系节点则层级较浅的节点a会在查询一圈之后与层级较深节点b同时汇合在自己初始位置2如果是非祖孙关系节点与上述一致层级较浅的节点a优先到达祖父节点为空到达后从深层级节点初始位置开始最终循环d-s后ab的祖父节点相同。3如果是同父节点 直接退出循环总次数计算node1循环次数为空次数等于a,node2循环次数为空次数等于bconst max Math.max(a,b);const min Math.max(a,b);第一次循环min次之后其中一个节点开始从另一个节点的起始位置开始。接着在循环(max-min)次之后较深节点会再循环一个差值之后与层级浅的节点 有着共同的祖父节点。总循环次数等于 max。**/let p1 node1, p2 node2, ex false;while (p1._parent._id ! p2._parent._id) {p1 p1._parent._parent null ? (ex true) node2 : p1._parent;p2 p2._parent._parent null ? (ex true) node1 : p2._parent;}//node1 与node2 是祖父孙关系//同祖父孙关系较浅的节点a会一圈之后在自己初始位置与较深节点b重合。if (p1._id p2._id) {if (p1._id node2._id)// p1不等于node1(l1),p1比较深 l1优先return -1;if (p1._id node1._id)//p1等于node1p1比较浅l2优先return 1;}//到这一步已经确定不是祖孙关系了那就存在 同父或不同父//1extruep1与p2 是不同父节点直接对比节点_localZOrder。//2exfalse; 是同父节点因为降序所以反向减return ex ? p1._localZOrder - p2._localZOrder : p2._localZOrder - p1._localZOrder;}
这里需要注意的是_localZOrder 与zIndex、siblingIndex 区别
_localZOrder 是一个32位的数字前16存储着zIndex节点顺序后16位存储着子节点相对于在父节点下的索引位置。渲染顺序由_localZOrder 决定节点排序是比较_localZOrder值进行升序排序。_localZOrder 前16位存储的是zIndex后16位存储的事siblingIndex(setSiblingIndex)。zIndex权重比siblingIndex大如果zIndex 相同渲染顺序由siblingIndex决定。反之如果修改了zIndex再次修改siblingIndex毫无效果。修改zIndex时_localZOrder值是在下一帧才会改变当前帧并不会改变。
在事件监听器触发的过程中可能会添加新的监听器或者删除监听器。因此有了下列属性
_toAddedListeners当在添加新的监听器时遇到正在触发事件监听器时新的监听器或暂存在该数组中。
_toRemovedListeners当在添加新的监听器时遇到正在触发事件监听器时新的监听器或暂存在该数组中。
_inDispatch正在分发时1 不在分发时0
什么时候这些暂存的数据与总数据合并呢每帧的时候都会去检测是否有暂存数据存在如果有则与总数据合并即添加、删除。
监听器的吞噬与不吞噬监听的的吞噬情况由三种条件控制
事件的stopPropagation、stopPropagationImmediate 如果事件设置了停止派发则监听器的不吞噬也会暂停其他监听器也不会接受到信息。节点的hitTest 返回值 与 监听器的 swallowTouches 值设置。swallowTouchestrue吞噬 只会分发到自身监听器其他监听器不会被分发。swallowTouchesfalse; 不吞噬 下一个监听器也会被分发 依次循环 直到有一个监听器设置吞噬才不会往下传
参考代码_dispatchEventToListenersshouldStopPropagation
eventManager 分发流程 CCEvent、CClistener、event-target