宝哥软件园

megao-网易考拉小程序解决方案

编辑:宝哥软件园 来源:互联网 时间:2021-12-05

Megalo是基于Vue的小程序框架(没错,也是基于Vue的小程序框架),但它不仅支持微信小程序,还支持支付宝小程序,同时还支持在开发中使用更多的Vue功能。

背景

对于用户来说,小程序可以提供更好的体验,但是对于开发者来说,要让一个应用在多个平台上运行,需要编写多套代码。如何提高小程序开发的效率是很多开发者头疼的问题。

业内也有相关的解决方案,比如taro和mpvue,都是基于REAT和vue的开发模式,让开发者可以用知名的REAT或者vue模式开发小程序,提高开发效率。

mpvue的发布给了我们很多启发。之前,我们基于RegularJS(网易开发的前端框架)开发了一个名为mpregular的小程序框架。在mpregular的开发和实际使用过程中,我们发现如果小程序框架支持的功能只是原框架的一个子集(例如不支持过滤器和模板复杂表达式),开发效率会大大降低。

因此,我们在方案上进行了很多尝试,旨在支持更多的功能,减少小程序与开发前H5的差异。目前mpregular已经在考拉的小程序业务中得到广泛应用,相关业务的开发学员都表示学习成本变低了,跨终端业务(H5和小程序)的开发效率提高了近一倍。

经过一段时间的验证,我们决定用vue再次实施这个方案,一是适应技术栈的变化和升级,二是为社区做一点工作,这样就有了megalo。

特性

支持更多模版语法特性

相比其他小程序开发模式,megalo更接近Vue的原生开发模式,因为它支持的功能更多。

megalo  -- 网易考拉小程序解决方案(图1)

从表中可以看出,megalo最大的特点之一是它支持更多的Vue语法特性。这意味着,如果您需要将现有的Vue代码迁移到一个小程序中,您不需要做太多的更改。因为您的代码可能会使用大量的筛选器、限定范围的槽和复杂的表达式插值。

基本语法

支持vue的基本模板语法,包括v-for和v-if。ClassStyle和ClassStyle的绑定方式没有限制,官方用法支持。

!- v-if v-for - div v-for='(item,I)在列表' div v-if=' isEven(I)' { { I } }-{ { item } }/div/div!-style class-div : class=' class object '/div div : class=' { active : true } '/div div : class='[active class,error class]'/div div : style=' { color : activeColor,font size : font size ' px ' } '/div div 3360 style=' style object '/div div 3360 style='[基本样式,超车样式]/'

div容器Card div slot=' head ' { title } }/div div我是body/div slot=' foot '我是foot/div/Card/Container List : List=' List ' span slot-scope=' scope props ' { scope props . item . label } }/span/List gt

;<div>

复杂表达式 & filter

可以在模版里面写复杂表达式、调用实例上的方法,当然也可以用更简洁的 filter 语法,跟平时用 Vue 开发一样。

<div>  <div>{{ message.toUpperCase() }}</div>  <div>{{ toUpperCase( message ) }</div>  <div>{{ message | toUpperCase }}</div></div>

v-html

要使用v-html需要添加插件@megalo/vhtml-plugin,并引入模版解析库octoparse,在页面入口安装一下插件:

import Vue from 'vue'import VHtmlPlugin from '@megalo/vhtml-plugin'Vue.use(VHtmlPlugin)复制代码

利用v-html指令然后就可以在小程序中渲染 html 了。

<div v-html="'<h1>megalo</h1>'"></div>复制代码

更好的数据更新性能

小程序的官方明确说明,在调用setData更新数据时如果数据量过大或频率更高,会引发性能问题。megalo 在框架底层已经帮开发者对此进行优化,每次数据发生变化时,megalo 只会将视图中要展示的、且发生变化的数据进行更新,将setData的数据更新量最小化,同时对更新数据频率进行了限制。

像下面这段代码,如果视图只需要展示user.name这个字段的话,在进行数据同步时只会将user.name这个字符串更新到视图层,其余字段是不会同步到小程序的对象上的。

<div>{{ user.name }}</div><script>export default {  data() {    return {      user: {        name: 'kaola',        age: 3,        favorite: [          'encalyptus',          'sleeping'        ]      }    }  }}</script>

支持更多平台

今年以来,各大流量平台都在小程序领域有所动作,蚂蚁金服成立小程序事业部,百度、今日头条也纷纷推出自己的小程序。megalo 目前已经支持微信和支付宝小程序,百度小程序等平台的支持也在计划当中。

megalo -- 网易考拉小程序解决方案(图2)

微信和支付宝小程序

使用

使用 megalo 开发非常简单,只需在常见的 Vue 项目 webpack 构建配置上配置@megalo/target并引入@magalo/template-compiler即可。如果需要编译成支付宝小程序,只需要设置platform: 'alipay'。

const { createMegaloTarget } = require('@megalo/target');module.exports = {  target: createMegaloTarget( {    compiler: require('@megalo/template-compiler'),    platform: 'wechat'  } )  // 其他 webpack 配置,如 vue-loader 等};

接着,就可以像开发 Vue 应用一样去开发小程序。示例可以参考megalo-demo。

如果想用 typescript 进行开发,可以参考megalo-ts-simple。

实现

小程序在结构上主要有 Service(JavascriptCore) 和 View(WebView) 两部分组成(微信和支付宝小程序有着类似的结构,下文均以微信小程序为例,并简称为小程序),分别运行在独立的环境上,之间不具备共享数据通道,二者的通信方式是将数据封装在 js 脚本后传递。Page 实例就在 Service 中,通过setData方法将数据传递到 View。View 则通过事件绑定将视图层触发的事件传递给 Service。Service 层中无法操作视图层的 DOM 节点。

megalo -- 网易考拉小程序解决方案(图3)

实际开发中,小程序的逻辑和模版需要写在.js和.wxml两个文件中,分别在 Service 和 View 中执行。如果要将在浏览器端的 Vue 放到小程序中跑,需要将.vue文件中的 template 片段转换成.wxml文件,并对 Vue 的 runtime 部分改造,将其中的 DOM 操作移除,通过小程序的 Service 中的页面实例上的 API 与 View 进行通信。

最终的运行效果是,当 Vue 的 vm 上数据发生更新时,会重新渲染出 vdom,在的 patch 阶段,框架不在去操作 DOM,而是通过 Page 上的setData方法将变化的数据更新到视图层,完成 Vue 和 小程序的视图更新,这就是 megalo 底层所做的工作。

megalo -- 网易考拉小程序解决方案(图4)

megalo 的实现,主要分成以下四个部分,下面本文将对每个部分进行介绍。

生命周期

小程序中,每一个页面(Page)是一个实例,页面的生命周期钩子有很多,但和实例创建的两个关键生命周期分别是onLoad和onReady,它们分别在「页面加载,实例初始化后」和「初次页面渲染完成」时触发。Vue 的实例要和小程序实例建立起联系,则需要在小程序 Page 实例创建好以后,即在onLoad的钩子函数里,去初始化对应的 Vue 根实例,将页面实例page挂载到 Vue 实例的$mp上,此时也会触发 Vue 的生命周期钩子created。在页面初次渲染完成后,则会调用$mount方法,与在浏览器中挂载 DOM 节点不同,这里会将 Vue 实例上的数据初始化到视图层中。由此,Vue 实例就与小程序的 Page 实建立起了联系。

megalo -- 网易考拉小程序解决方案(图5)

除了这两个生命周期钩子以外,像小程序的onShow、onHide等生命周期钩子在触发时,也会尝试触发 Vue 实例上的同名钩子函数,实现两种实例间生命周期的绑定。在小程序页面退出销毁时,会触发onUnload钩子,此时 Vue 的实例也会跟着销毁。

模版转换

小程序有它特有的模版语法和文件名后缀,所以在构建阶段,我们会将.vue文件中的 template 部分提取出来并转换成对应的.wxml文件。标签名、语法都会进行相应的转换,如图所示。

megalo -- 网易考拉小程序解决方案(图6)

这一部分是在构建阶段完成的,这意味着,megalo 不支持 render 函数的写法。在构建阶段除了将模版转换成.wxml以外,还需要对模版中的每个节点进行转换,并在生产的 render 函数中加入相关的节点标记信息,数据映射和事件代理需要这些信息。

数据映射

由于无法直接操作视图层的 DOM,所以我们只能利用page.setData这个方法完成数据到视图层的映射。最简单暴力的方法,是将 Vue 实例上的所有数据统统收集起来,通过调用page.setData方法更新 Page 实例的数据,这个方法会将数据挂载到 Page 实例上,同时也会把数据传递给视图层。

megalo -- 网易考拉小程序解决方案(图7)

但是,这种粗暴的更新方式有两个弊端:

i. 全量更新vm上的数据是无法区分哪些数据是视图层需要的,冗余无用的数据会被更新到page实例上。像下图这个例子,视图层只需要展现两个字符串,如果vm上还存在两个大数组,它们也会被无脑同步到page上。

megalo -- 网易考拉小程序解决方案(图8)

ii. 同步到page实例上的数据其实就是原始数据,并不是视图层实际要展示的数据,所以展示数据的格式化与转换需要依赖小程序模版的解析能力,导致一些 Vue 支持的模版语法无法支持,例如 filter、复杂表达式、传递 class 对象等。

megalo -- 网易考拉小程序解决方案(图9)

当然以上两个弊端不会对功能开发造成影响,但在实际的业务开发中,会让开发体验不一致,尤其是 h5 代码迁移到小程序时,对效率影响颇大。为了解决这个问题,megalo 采用另一种方式,即将 render 时生成的 vnode 上的数据更新到视图,vnode 的数据就是已经处理好的展示数据,根据 vnode 构造每个节点的数据结构,再同步到视图层。

例如以下这段代码,在构建阶段 megalo 会对每个节点进行标记,使 render 时生成的 vnode 和模版中每个插值能够对应上。

<!-- 编译前的 Vue 模版 .vue --><div :class=“classObj”>  {{ date | format( 'YYYY' ) }}</div><!-- 编译后的小程序模版 .wxml --><view class="{{ node_1.class }}">  {{ node_1.text }}</view>

以这种方式实现的数据映射,只有视图层需要的两个字符串数据会被同步到小程序的 Page 实例上,其余数据则被认为与视图无关则不会进行同步。

export default {  data() {    return {      classObj: {        'kaola': true      },      date: new Date(),      users: {        // big object      }    }  }}

如下图所示,Vue 渲染出来的 vnode 会被以特定的数据结构映射到 page 上,再同步到小程序视图层。

megalo -- 网易考拉小程序解决方案(图10)

以这种方式实现的数据映射,可以更好地支持 Vue 的模版语法,且更大限度地减少更新视图时传输的数据量,从框架层面规避setData的性能问题。

事件代理

小程序视图触发事件后,会将event对象通知到 Page 实例,那么我们只需要将视图层中所有的事件都代理到page.proxy这个方法中,然后再靠这个方法从 Vue 的实例树上找到对应的vm和handler做事件处理。为了实现这一目的,在构建阶段对模版进行编译时,除了要将事件监听方法转换为proxy以外,还需要通过data-在元素上标记对应的组件compid和节点nodeid。

<!-- 编译前的 Vue 模版 .vue --><div @click="onClick"></div><!-- 编译后的小程序模版 .wxml --><view bindtap="proxy" data-compid="0" data-nodeid="0"></view>复制代码

事件触发时,proxy 方法会从 event 对象上获取对应的 id 信息和事件类型,进而从 Vue 的根 vm 开始查找,最终在 vnode 上找到对应的 handler 并执行事件处理,完成小程序事件到 Vue 实例的事件代理。

megalo -- 网易考拉小程序解决方案(图11)

现在与未来

目前,megalo 已经逐步在考拉的小程序应用开发中投入使用,但 megalo 的数据映射方案早已通过 mpregular 在考拉的大量小程序应用中得到了验证。现在,megalo 支持 typescript 开发,支持支付宝小程序。

百度智能小程序的支持也在计划之内,同时,我们还计划开发一个兼容个平台的 UI 组件库、API 库,尝试将跨 H5 和各小程序平台的应用开发之间的差异最小化,提升开发效率。

更多资讯
游戏推荐
更多+