前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

# 前言

本章内容分解:

  • web普通事件原理
  • 小程序事件系统源码解读
  • 小程序线程通讯协议

# 事件系统

回顾一下微信小程序的双线程架构设计,我们在WXML中进行事件绑定,假设我们绑定一个Tap事件和motto参数在WXML中如下:

image.png

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

image.png

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

image.png

这里会有一个疑问🤔️,在小程序架构中WXML在视图线程进行渲染,.js文件在逻辑线程进行解析运行。并不在一个线程。他们之间是如何进行绑定的呢?比较浅显的理解就是类型vue一样的双向绑定。那么我们就带着这个疑问进行逐步解析。

# 事件系统

什么是事件?

  • 事件是视图层到逻辑层的通讯方式。
  • 事件可以将用户的行为反馈到逻辑层进行处理。
  • 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
  • 事件对象可以携带额外信息,如 id, dataset, touches。

事件可以绑定在组件上,在Exparser组件系统章节的时候我们讲解到了Shadow DOM的事件系统。

这里我们缕清一下思路,上面的WXML例子中,从底层逻辑上来讲,我们还没有进行事件绑定,我们只不过在小程序的WXML结构中声明了一个键值对而已。因为WXML需要经过几道工序的处理,处理成HTML结构才可以完成事件绑定。所以这里要记好这个概念。

随后我们将WXML进行virtualDOM编译,这里的编译就是virtualDOM章节中我们使用过的$gwx函数,我们来看一下我们声明的tap键值对编译在了哪里。

image.png

可以看到找到我们声明事件标记的层级中,attr属性内部有bindtap: bindTextTap键值对。那么这个DOM结构是怎么进行事件解析的呢?

解析的算法在底层基础库WAWebview.js文件中,我们现在此提前解析一下事件模块完整的流程,为了防止到后面底层基础库章节再讲的话,知识形成不了闭环。

我这里解析的基础库版本为2.11.0。

底层基础库中解析virtualDOM函数applyProperties源码如下,attr属性解析,包含事件解析。

image.png

返回的l函数源码:

image.png

可以看到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函数源码如下:

image.png

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

image.png

这样的话只要tap事件触发的话,就会调用这个回调方法。

这里我还把上面我们打印的event信息值与这里的c对象进行比对,如下:

image.png

可以看到数据结构是一样的,但是注意,目前在触发sanData方法之前这些逻辑的解析包括event参数的组装都是在渲染层的底层基础库WAWebview.js中完成的,也就是说还在渲染线程中。

那么没有错,sendData方法就是向逻辑线程发送event数据的方法。

两线程之间的通讯逻辑讲解放在了下一章节。这里并不影响事件系统的逻辑闭环,我们整理一下流程并继续分析。

事件系统-渲染层流程图.png

事件绑定完了,那么用户触发的流程是怎样的,我们继续探索。

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

image.png

在源码26012行中可以找到mouseup事件的原生监听方法,如果用户触发的话将执行函数E,函数S,函数L。这里的函数E并不是前面绑定函数的函数E,因为是压缩代码,这里不要理解错了。

看一下函数E源码,内部返回一些坐标信息、目标元素信息等。

image.png

主要看函数S源码:

fe
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏