从 Wepy 到 UniApp 变形记( 三 )

五、核心设计实现5.1 wepy template 模版转换5.1.1 差异性梳理下面我们可以先来大致看一下wepy的模板语法和uniapp的模板语法的区别 。

从 Wepy 到 UniApp 变形记

文章插图
图:wepy模板和uni-app模板
从上图可以看出,wepy模板使用了原生微信小程序的wxml语法,并且在采用类似Vue的组件引入机制的同时,保留了wxml< import/ >、< include/ >标签的能力 。同时为了和wxml中循环渲染dom节点的语法做区别,引入了新的< Repeat/ >标签来渲染引入的子组件,而uni-app则是完全使用Vue风格的语法来进行开发 。
所以总结wepy和uni-app模板语法的主要区别有两点:
  1. wepy使用了一些特定的标签用来导入或者复用其他wxml文件例如< import >和< include > 。
  2. wxml使用了xml命名空间的方式来定义模板指令,并且对指令值的处理更像是使用模板引擎对特定格式的变量进行替换 。
下表列举一些两者模板指令的对应转换关系 。
从 Wepy 到 UniApp 变形记

文章插图
此外,还有一些指令的细节需要处理,例如在wepy中wx:key="id"指令会自动解析为wx:key="{{item.id}}",这里便不再赘述 。
5.1.2 核心转换设计编译器对template转换主要就需要完成以下三个步骤:
  1. 处理wepy引入的特殊的标签例如 。
  2. 将wxml中使用的指令、特殊标签等转换为Vue模板的语法 。
  3. 收集引入的组件信息传递给下游的wepy-page-transform模块 。
  • wepy特殊标签转换
首先我们会处理wepy模板中的特殊标签< import/ >、< include/ >,主要是将wxml的文件引入模式转换成Vue模板的组件引入模式,同时还需要收集引入的wxml的文件地址和展示的模板名称 。由于< include/ >可以引入wxml文件中除了< template/ >和< wxs/ >的所有代码,为了保证转换后组件的复用性,我们将引入的xx.wxml文件拆成了xx.vue和xx-incl.vue两个文件,使用< import/ >标签的会导入xx.vue,而使用< include/ >标签的会导入xx-incl.vue,转换import的核心代码实现如下:
transformImport() {// 获取所有import标签const imports = this.$('import')for (let i = 0; i < imports.length; i++) {const node = imports.eq(i)if (!node.is('import')) returnconst importPath = node.attr('src')// 收集引入的路径信息this.importPath.push(importPath)// 将文件名统一转换成短横线风格let compName = TransformTemplate.toLine(path.basename(importPath, path.extname(importPath)))let template = node.next('template')while (template.is('template')) {const next = template.next('template')if (template.attr('is')) {const children = template.children()// 生成新的组件标签例如// <import src="https://www.huyubaike.com/biancheng/components/list.wxml" />// <template is="subList" />=> <list is="subList" />const comp = this.$(`<${compName} />`).attr(template.attr()).append(children)comp.attr(TransformTemplate.toLine(this.compName), comp.attr('is'))comp.removeAttr('is')// 将当前标签替换为新生成的组件标签template.replaceWith(comp)}template = next}node.remove()}}具体的WXML文件拆分方案请看WXML转换部分 。
  • wepy 属性转换
上文中已经介绍了,wepy模板中的属性使用了命名空间+模板字符串风格的动态属性,我们需要将他们转换成Vue风格的属性 。转换需要操作模板中的节点及其属性,这里我们使用了cheerio,快速、灵活、类jQuery核心实现,可以利用jQuery的语法非常方便的对模板字符串进行处理 。
上述流程中一个分支中的转换函数会处理相应的wepy属性,以保证后续可以很方便的对转换模块进行完善和修改 。由于属性名称转换只是简单的做一下相应的映射,我们重点分析一下动态属性值的转换过程 。

经验总结扩展阅读