# 前言

前一章节我们看到了WXSS文件编译后的源码,没有错WXML文件业务要进行编译步骤,这一章节就带大家一步一步刨析WXML编译后的源码。

# WXML

第一步,跟WXSS章节一样,去寻找用于编译WXML文件的可以执行文件WCC。

在微信开发者工具控制台中,执行openVender()。

image.png

可以看到就在WXCS上边就是WCC可执行文件。我们还是一样的操作。把WCC可执行文件拷贝到pages/logs目录下面,如下图所示。

image.png

WCC可执行文件的具体使用命令可以通过--help查看到。

image.png

执行命令$ ./wcc -d logs.wxml >> wxml.js

image.png

可以看到pages/logs目录下多了一个wxml.js文件,这个就是编译之后的js文件,我们来看一下里面的具体结构。

image.png

这部分代码不像WXSS编译出来的代码可以直接观看,而是进行了压缩混淆。基本上是不可读的。但是我们还是可以一点一点去分析这到底是怎么运行的,我们继续往下看。

可以看出,整体代码结构就是一个函数,函数名称为$gwx。它的作用是生成虚拟dom树,用于渲染真实节点。内部还有一些边界函数。比如有意思的 _n函数里面包含一个提示:

image.png

英文的意思是超出Dom限制,请检查是否有任何错误,DOM数量不可以超过16000个。但是比较之前的版本,这个提示可没有这么友好,它是这个样子的:

image.png

汉译我就不放在这里了哈哈,有兴趣的自己翻译一下,我们继续。

但是这个时候我们只知道$gwx是个函数,但是怎么调用呢?继续去渲染层代码中进行寻找。还是打开渲染层控制台Elements中,control + F 进行寻找即可,首先我们可以看到编译后的函数在渲染层也有一套。如下图:

image.png

可以看到编译后的WXML文件以js的形式插入到了渲染层的<script>标签中。对比WXSS编译后用eval执行还是有区别的。

但是在这个script标签中插入了$gwx函数之后并没有执行这个函数。我们继续查找,看看$gwx函数是在哪里执行的,并且需要传入哪些参数。

image.png

在渲染层继续查找就找到了$gwx函数执行的地方,我们提取出来看一下。

    var decodeName = decodeURI("./pages/index/index.wxml")
    var generateFunc = $gwx(decodeName)

这时候就知道了$gwx函数的参数正是WXML文件的业务路径。如上图是在。这里注意一下,为了后方讲解顺利,我们把WCC执行文件放在了pages/logs目录下,所以我们这里传入$gwx函数的路径是./pages/logs/logs.wxml。

我们在渲染层的控制台中执行一下$gwx函数并传入参数。

image.png

可以看到执行$gwx函数后的返回值generateFunc也是一个函数。我们再次执行这个函数,看一下返回值。

image.png

generateFunc函数的返回值是一颗树状结构,就是该页面wxml对应的js对象形式表示的dom树。

那为什么$gwx函数不直接返回虚拟DOM树呢,而是先返回generateFun?是因为需要注入动态数据。再看一下编译前的WXML文件结构。

image.png

可以看到内部需要动态接受几个变量

  • logs 是一个数组
  • log 是个字符串
  • index 循环索引

generateFunc函数在执行的时候需要动态注入这些数据,我们手动注入一些假数据看一下生成出来的虚拟DOM树与前面没有注入数据的有什么区别。

image.png

可以看到我们传入了动态数据logs,相对应的虚拟DOM树中也渲染出来了这条动态数据,在wx-text标记的children中可以看到,因为logs.wxml内部结构是一个循环,所以前面没有传递参数进去的时候,并没有渲染循环体内部的DOM节点。传进动态数据之后就可以看到循环体内部的DOM节点也被渲染了出来。

渲染出对应的虚拟DOM树之后,之后要干嘛呢?我们还得回到渲染层找一下generateFunc的位置,看看它之后干了什么。查找方法参照前面control + f方法。

image.png

最开始的两行,是我们去探索$gwx函数作用的时候查找到的,并分析了一下,再次看到这段代码的时候我们已经知道了generateFunc就是接受动态数据,并生成虚拟DOM树的函数。

这段代码核心的区域就是CustomEvent,自定义事件,自定义事件在讲解Shadow DOM的时候重点提到过。在这里再次出现了,可以看到这里的逻辑如下:

  • 如果没有有generateFun那么body标记内部展示 decodeName + "not found",并输处错误日志
  • 如果有,检查window或++global环境中自定义事件CustomEvent是否存在。CE及为CustomEvent缩写
  • document.dispatchEvent 触发自定义事件 将generateFunc当作参数传递给底层渲染库,这里后边章节讲到,我也会与这里相互呼应。
  • 在触发自定义事件的时候,添加当前时间节点,可以理解为生命周期pageFrame_generateFunc_ready。

这样完整的virtualDOM渲染流程就完毕了,猜一下后续,肯定有地方需要去接收这个ready状态,那么问题来了,动态数据是怎么传过来的?下个章节我们讲解小程序的通讯系统

阅读全文