# 前言
本章内容分解:
- web普通事件原理
- 小程序事件系统源码解读
- 小程序线程通讯协议
# 事件系统
回顾一下微信小程序的双线程架构设计,我们在WXML中进行事件绑定,假设我们绑定一个Tap事件和motto参数在WXML中如下:

然后我们在.js文件中进行声明处理函数和data:

这样的话小程序当前页面上会有一个Hello Wrold文本展示,并且点击此文本后,文本内容将会更改为Clicked!!。并且绑定函数有一个参数event,打印如下:

这里会有一个疑问🤔️,在小程序架构中WXML在视图线程进行渲染,.js文件在逻辑线程进行解析运行。并不在一个线程。他们之间是如何进行绑定的呢?比较浅显的理解就是类型vue一样的双向绑定。那么我们就带着这个疑问进行逐步解析。
# 事件系统
什么是事件?
- 事件是视图层到逻辑层的通讯方式。
- 事件可以将用户的行为反馈到逻辑层进行处理。
- 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
- 事件对象可以携带额外信息,如
id,dataset,touches。
事件可以绑定在组件上,在Exparser组件系统章节的时候我们讲解到了Shadow DOM的事件系统。
这里我们缕清一下思路,上面的WXML例子中,从底层逻辑上来讲,我们还没有进行事件绑定,我们只不过在小程序的WXML结构中声明了一个键值对而已。因为WXML需要经过几道工序的处理,处理成HTML结构才可以完成事件绑定。所以这里要记好这个概念。
随后我们将WXML进行virtualDOM编译,这里的编译就是virtualDOM章节中我们使用过的$gwx函数,我们来看一下我们声明的tap键值对编译在了哪里。

可以看到找到我们声明事件标记的层级中,attr属性内部有bindtap: bindTextTap键值对。那么这个DOM结构是怎么进行事件解析的呢?
解析的算法在底层基础库WAWebview.js文件中,我们现在此提前解析一下事件模块完整的流程,为了防止到后面底层基础库章节再讲的话,知识形成不了闭环。
我这里解析的基础库版本为2.11.0。
底层基础库中解析virtualDOM函数applyProperties源码如下,attr属性解析,包含事件解析。

返回的l函数源码:

可以看到applyProperties中有一个forIn循环去遍历virtualDOM中的attr属性。然后执行e函数。这里可知e函数的参数及为attr对象中的属性名称key。
e函数中有很多的if,是用来判断特殊的属性名称的,我们绑定的tap事件键值对是bindtap: bindTextTap,key也就是bindtap,事件绑定的前缀有很多比如bind、catch,看到第10行左右的if中用正则if (n = e.match(/^(capture-)?(mut-)?(bind|catch):?(.+)$/))判断attr中的属性名是否为事件属性。如果是事件属性的话执行E函数,并且转换为exparser组件系统中的attr属性名称exparser:info-attr-。
我们来看一下解析到事件attr属性名后,E函数做了什么,E函数源码如下:

可以看到E函数中首先通过addListener方法进行了事件绑定,这个方法也是封装自我们熟知的 window.addEventListener,只不过tap与原生click方法之间有一层映射关系。addListener的事件触发的回调函数中组装了函数的event信息值,并且触发了sendData方法,方法标记为SYNC_EVENT_NAME.WX_EVENT,在源码中值为11。

这样的话只要tap事件触发的话,就会调用这个回调方法。
这里我还把上面我们打印的event信息值与这里的c对象进行比对,如下:

可以看到数据结构是一样的,但是注意,目前在触发sanData方法之前这些逻辑的解析包括event参数的组装都是在渲染层的底层基础库WAWebview.js中完成的,也就是说还在渲染线程中。
那么没有错,sendData方法就是向逻辑线程发送event数据的方法。
两线程之间的通讯逻辑讲解放在了下一章节。这里并不影响事件系统的逻辑闭环,我们整理一下流程并继续分析。

事件绑定完了,那么用户触发的流程是怎样的,我们继续探索。
前面我们提到小程序的事件都是和js原生事件相互转换的,小程序的tap事件底层是由web的mouseup事件转换来的,小程序tap事件的触发分为几个过程,首先底层实现是用web的mouseup事件触发了tap事件,底层为window绑定捕获阶段的mouseup事件。

在源码26012行中可以找到mouseup事件的原生监听方法,如果用户触发的话将执行函数E,函数S,函数L。这里的函数E并不是前面绑定函数的函数E,因为是压缩代码,这里不要理解错了。
看一下函数E源码,内部返回一些坐标信息、目标元素信息等。

主要看函数S源码:
