开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
微信小程序的页面有4个基本文件,分别是wxml、wxss、js、json,wxml相当于html文件,wxss相当于css,js文件里是逻辑代码,json是配置文件。本文主要分析的是跟视图层相关的wxml和wxss文件,探究其在小程序内的编译过程。
WXML文件编译
WXML编译流程
整个wxml是类似于模板+数据
的形式组成,wxml的编译会先编译出结构生成函数,然后再结合data生成Virtual Dom,最后形成Dom Tree。整体流程如图所示:
wcc编译WXML
wxml通过wcc工具进行编译,首先来找到wcc编辑工具,把控制台调为top选项
,然后执行help()
。
再执行index为8的方法
openVendor()
,打开工具文件夹。
把wcc
复制出来,以编译home页面wxml为例,执行如下方法。
./wcc -d index.wxml >> home.js
$gwx方法
分析编译出来的home.js文件可以看到,整体上其实是一个函数$gwx
,它用于后续virtual dom的编译。
/*v0.5vv_20200413_syb_scopedata*/window.__wcc_version__='v0.5vv_20200413_syb_scopedata';window.__wcc_version_info__={"customComponents":true,"fixZeroRpx":true,"propValueDeepCopy":false};
var $gwxc
var $gaic={}
$gwx=function(path,global){
...
}
生成virtual dom
结合开发者工具home页面对应的webview,可以看到$gwx函数执行后会生成generateFunc函数
。
再执行generateFunc,就能得到
virtual dom
,这种最终转换成虚拟dom的形式,跟vue框架的编译流程有些类似,优点是不用频繁操作dom来改变页面,以一种低成本的方式达到页面动态渲染。
接着看下home页面的index.wxml文件结构。
<!-- /pages/home/index.wxml -->
<view class="home">
<view class="home-msg">
<text>{{msg}}</text>
</view>
</view>
然后分别执行不带参数和不参数的generateFunc方法。
var decodeName = decodeURI("./pages/home/index.wxml")
var generateFunc = $gwx(decodeName)
// 不传入参数
generateFunc()
// 传入参数
generateFunc({msg: 'home page'})
得到如下的虚拟dom结构,可以看到在tag为wx-view的数组中会直接把参数填入children,用于后续渲染。
WXSS文件编译
WXSS编译流程
wxss文件的编译同wxml类似,也是通过编译工具完成。先是用wcsc编译工具把wxss文件编译成js文件,再转换后把样式插入到style中
,如下图所示:
wcsc编译WXSS
同上一样,使用openVendor()打开WeappVendor文件夹,复制出wcsc工具,还是以home页面为例,粘贴到home目录下,执行如下命令进行编译。
./wcsc -js index.wxss >> wxsstojs.js
得到wxss对应的js文件,如下图所示,可以看到整个js文件其实是对一些设备信息进行定义后,执行setCsstoHead方法。
setCssToHead方法
setCssToHead方法从函数名称上很好理解,就是把css设置到head中,使其起作用进行样式渲染,这样整个环节就完成了。
// setCssToHead方法
var Ca = {};
var css_id;
var info = info || {};
var _C = __COMMON_STYLESHEETS__
function makeup(file, opt) {
...
}
if ( !style )
{
var head = document.head || document.getElementsByTagName('head')[0]; // 获取head节点
style = document.createElement('style'); // 创建style标签
style.type = 'text/css'; // 设置type
style.setAttribute( "wxss:path", info.path ); // 设置属性
head.appendChild(style); // 把style插入到head
...
}
从上面代码可以清楚的看到把style插入到head的过程,比较简单,就不一一解读了。
可能有个疑问,整个js是怎么执行的,看下home页面对应的webview,是通过eval方法
执行了。
插入的style和原始wxss文件做个对比,发现基本上差不多,但rpx已转成了px,这点后面讲。
// pages/home/index.wxss
.home {
display: flex;
flex-direction: column;
align-items: center;
}
.home-msg {
margin-top: 400rpx;
}
彩蛋环节
rpx转成px
rpx是微信小程序的单位,开发者在写样式无需做兼容转化就能直接用,我们来看下小程序内部转化的逻辑。
在wxss编译后的js文件中,有个transformRPX方法
,进行rpx转px,实际上就是rpx值 / 基础宽度750 * 设备宽度
。
// wxsstojs.js
var eps = 1e-4;
var transformRPX = window.__transformRpx__ || function(number, newDeviceWidth) {
if ( number === 0 ) return 0;
number = number / BASE_DEVICE_WIDTH * ( newDeviceWidth || deviceWidth ); // rpx换算成px单位值
number = Math.floor(number + eps); // 精度处理
if (number === 0) { // 计算值过小处理
if (deviceDPR === 1 || !isIOS) {
return 1;
} else {
return 0.5;
}
}
return number;
}
写在最后
本文写到这里结束了,欢迎支持下,点赞+关注+评论三连!