Quark-Renderer----第十篇

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的事件处理有着至关重要的作用。

猜你喜欢

转载自blog.csdn.net/qq_53259920/article/details/121546184