2021SC@SDUSC
总述
上次我们对canvas的canvasPainter.js中的最后一部分做了分析总结,对于Quark Renderer渲染引擎来讲,它都是一个元素。那这些元素里有好多的属性,每个元素上面都有,比如说它当前的位置、缩放的状态、颜色、阴影、渐变等可视的属性。我们之前几次学习都是对canvas中的js文件进行了深度的解析,对于一些canvas中调用的其他文件也进行了学习。那么这次,我们对下一部分进行分析学习。
我们这次的学习部分是事件系统处理,事件系统也是比较有意思的一点,因为Canvas是一个很低级的很底层的API的接口,没有提供一些高层级的这种封装,那就意味着你要去做一些事件的时候就很麻烦,必须自己实现。通过对事件event包中的代码内容进行整体查看分析,可以得知整个Quark Renderer的事件系统是通过模拟DOM事件的设计来进行对事件的处理的。
对事件处理部分的分析
对Eventful.js 整体把控
事件系统里比较精华的部分就在Eventful.js的包里。所有跟事件相关的东西,都在该包中,负责对事件系统进行一些全局把控。该包中的函数也为不支持事件机制的类提供事件支持,其基本机制类似 W3C DOM 事件,需要事件机制的类可以 mixin 此类中的工具函数。
对具体方法分析
构造函数
首先是构造函数,需要参数,分别是一个对象,作为事件处理者,也就是当前事件处理函数执行时的作用域;还有一个函数,需要方法返回true才会执行;还有一个方法,该方法会在事件处理函数被调用之后执行;最后一个参数也是一个函数,该方法在添加或者删除事件监听的时候被调用。
let Eventful = function (eventProcessor) {
this._$handlers = {
};this._$eventProcessor = eventProcessor;this._$suspends = new Set();
};
该处理函数只会被调用一次,使用完然后就会被删除。该函数有四个参数,分别是event(事件名)、query(事件过滤条件)、handler(事件处理函数)、context(事件处理函数执行的上下文),在该函数中返回的值调用了on函数。下面我们分析on函数。
one: function (event, query, handler, context) {
return on(this, event, query, handler, context, true);},
该方法的作用是绑定事件处理函数,传入四个参数,分别是事件名、条件过滤条件、事件处理函数、以及事件处理函数执行的上下文。返回时on函数。
on: function (event, query, handler, context) {
return on(this, event, query, handler, context, false);},
on函数
在on函数中,我们看到他传入的值比one更多一个,是一个boolean值,表示是否只执行一次,我们传入的是true,其他参数都是一样的。在下面的函数代码中我们可以看到,有三个判断,分别对传入的参数进行了分析判断,第一个if是判断query是否为function,第二个参数是判断handler和event是否为不为null,第三个判断是对_h[event]进行判断,如果不存在就将该值设置为一个数组。
let _h = eventful._$handlers;if (typeof query === 'function') {
context = handler;handler = query;query = null;}
if (!handler || !event) {
return eventful;}
if (!_h[event]) {
_h[event] = [];}
在剩余部分中,对_h[event]进行遍历,判断他们的ctx和h是否对应context和handler,返回eventful。
然后定义一个wrap对象,将值都设置为在该方法中得到的参数。然后得到他们lastIndex和lastWrap,调用callListenerChanged函数,该函数主要对ventful._$eventProcessor.afterListenerChanged赋值为eventType
for (let i = 0; i < _h[event].length; i++) {
if (_h[event][i].ctx === context && _h[event][i].h === handler) {
return eventful;}}let wrap = {
h: handler,one: isOnce,query: query,ctx: context || eventful,callAtLast: handler.qrEventfulCallAtLast,};let lastIndex = _h[event].length - 1;let lastWrap = _h[event][lastIndex];lastWrap && lastWrap.callAtLast ? _h[event].splice(lastIndex, 0, wrap) : _h[event].push(wrap);callListenerChanged(eventful, event);return eventful;
off函数
有on函数就会有off方法与之对应,该方法的作用就是解除事件处理函数,需要传入的参数有三个,分别是事件名,如果参数为null,所有事件监听器都会被删除;事件处理函数handle,如果参数为null,所有事件监听器都会被删除;最后一个参数就是上下文context,显示页面。
该函数的主要操作时分别对参数进行判断,是否为null,然后进行上述的操作,确定删除的事件处理函数,在方法体中,我们可以看到使用了for循环来进行对绑定事件的遍历,找出符合不移除的事件,移入新的list中,然后删除原来的事件队列。
off: function (event, handler, context) {
let _h = this._$handlers;if (!event) {
this._$handlers = {
};return this;}if (handler) {
if (_h[event]) {
let newList = [];for (let i = 0, l = _h[event].length; i < l; i++) {
if (_h[event][i].ctx !== context && _h[event][i].h !== handler) {
newList.push(_h[event][i]);}}_h[event] = newList;}if (_h[event] && _h[event].length === 0) {
delete _h[event];}} else {
delete _h[event];}callListenerChanged(this, event);return this;},
isSilene、suspend、resume方法
除了这些函数之外,还有一些其他的函数,负责对事件的触发等发挥作用,如isSilene、suspend、resume等。isSilent方阿飞的作用是判断是否绑定了事件处理函数,返回的是处理函数的长度,如果为0就是未绑定,也就是未绑定。suspend函数的作用是挂起一个事件,被挂起的事件的不会被触发,在鼠标和触摸屏交互的过程中,经常需要把某个事件临时挂起以避免误触。而resume方法的作用是恢复触发,与suspend方法相对应。
isSilent: function (event) {
let _h = this._$handlers;return !_h[event] || !_h[event].length;},
suspend: function (eventName) {
this._$suspends.add(eventName);},
resume: function (eventName) {
this._$suspends.delete(eventName);},
trigger方法
最后一个方法,该方法时trigger,该方法的作用时触发一个事件,主要是对传入的参数(事件名)进行处理,先判断是否存在该事件名,然后再找出该事件,接着通过switch进行匹配。
if (this._$suspends.has(eventName)) {
return;}let _h = this._$handlers[eventName];let eventProcessor = this._$eventProcessor;
这是进行对查到的arglen进行长度匹配,从骨干网优化建议,对长度进行匹配。
let args = arguments;let argLen = args.length;switch (argLen) {
case 1:hItem.h.call(hItem.ctx);break;case 2:hItem.h.call(hItem.ctx, args[1]);break;case 3:hItem.h.call(hItem.ctx, args[1], args[2]);break;case 4:hItem.h.call(hItem.ctx, args[1], args[2], args[3]);break;case 5:hItem.h.call(hItem.ctx, args[1], args[2], args[3], args[4]);break;default:hItem.h.apply(hItem.ctx, args);break;}
总结
以上便是Eventful.js中的所有方法,再进行完整体分析后,我们从每个方法的实际作用展开的讨论,对于关键代码进行细节分析。总体而言,该js文件负责事件处理的核心,对于canvasRender的事件处理有着至关重要的作用。