随着微信小程序的火爆及百度、头条小程序的持续推进,跨端开发的需求愈发迫切,业界随之出现了一系列的跨端框架,但对于H5平台跨端支持的都不太彻底:
Vue
技术栈的小程序框架:对于H5平台支持普遍较弱- 部分
React
技术栈的小程序框架:虽支持生成可在H5端运行的代码,但仅仅是代码可运行,离项目直接发行上线的目标还存在一定差距。
本文主要分享在实现uni-app
发行到H5平台时,在引擎实现、差异抹平、性能优化方面都做了哪些工作。
完整模拟小程序引擎
uni-app
设计的开发标准是:Vue.js的语法 小程序的API 条件编译扩展平台个性化能力。其中:
Vue.js
的语法在微信小程序端,uni-app
是在mpvue
的基础上增强实现的,在H5端则默认支持;- 而小程序的API,其实包括三个部分:框架 组件(UI) 接口(API),这三部分在微信小程序端是内置支持的,而
uni-app
若要发布到H5平台,则需完整模拟实现小程序运行时环境。
如下是一个简易的小程序运行时框架,核心是一个响应的数据绑定系统。
为实现小程序、H5两端的完整跨端,uni-app
在H5平台完整模拟实现了小程序的逻辑层和视图层,相比业界其它跨端框架,uni-app
在H5平台有如下几点实现更完善。
页面配置
小程序中的导航条、选项卡是通过配置文件生成的,配置后由原生组件进行渲染,uni-app
在H5平台同样兼容这些配置,不过会降级通过div
控件模拟实现,因此开发者无需单独为H5平台添加导航条或选项卡。
生命周期
uni-app
在H5平台实现了完整的小程序生命周期,为此填了很多坑。举一个详情页互跳的栗子:
详情A 打开 详情B,在通常的 web 端 SPA 方案中,会在详情A页面获取B详情的数据,仅会触发详情页A的
updated
生命周期,不会触发onHide
。但在小程序中,则会打开一个新的webview并加载详情B,此时会触发详情A的onHide
生命周期,也会触发详情B的onShow
生命周期。uni-app
完整模拟了小程序的生命周期,详情页之间互相切换时,会触发onHide
、onShow
等生命周期;这样的实现,即保证了两端兼容性,同时在详情B返回详情A时,详情A已被缓存,无需再次联网加载,也会有更高的性能。
事件处理
uni-app
对于页面事件处理函数支持更为全面,下拉刷新、上拉触底等常用函数均可在H5平台正常复用,无需二次开发。
组件规范
uni-app
H5平台的组件实现,有两个特点:
- 兼容的组件数量更多:比如
navigator
等组件在H5平台可正常跳转 - 组件属性、嵌套实现更接近小程序实现
抹平引擎差异
fixed元素遮挡
微信小程序是一种 native web 混合渲染的机制,比如小程序的导航条(navigationBar)、选项卡(tabBar)为原生组件,但H5平台为纯 web 渲染,导航条、选项卡均为 web 实现,这可能引发页面 fixed 元素 和导航条/选项卡位置发生互相遮挡的问题,如下一段 fixed 定位的代码:
代码语言:javascript复制.fixed{
position: fixed;
z-index: 9999;
bottom: 0px;//底部距离为0
background-color:peru;
}在不同平台上运行效果不同,如下图所示:
uni-app
通过引入css变量
解决这类问题,在编译到不同平台时,给css变量
设置对应的值。
有了css变量
,开发者若需处理 fixed 定位的元素,只需像如下方式编写即可:
.fixed{
bottom:var(--window-bottom)
}
css作用域
uni-app
在开发时遵循 Vue 单文件组件 (SFC) 规范,编译到微信小程序时会生成对应的 wxml 文件,最终运行时由 webview 渲染,iOS 平台由 WKWebView 渲染,Android 平台由 XWeb 引擎基于 Mobile Chrome 53 内核渲染。
uni-app
中的不同.vue
页面文件( 编译后的.wxml
文件),在小程序端会由不同的 webview 渲染,故 .vue
页面文件中的 css 作用域是天然隔离的,开发者无需在<style>
标签上增加scoped
属性。
但H5平台是一套SPA框架,无scoped
就会变成全局样式,影响其他页面。uni-app
在H5平台做了智能处理,自动增加了scoped
。
平台性能优化
性能一直是webapp首要关注的焦点,uni-app
发行到H5平台时也做了很多性能优化。
内置组件按需打包(Tree-Shaking)
uni-app
有8大类、几十个内置组件,但开发者实际开发时仅会使用其中的一部分组件,比如很多App不会用到map
、canvas
等组件,若打包时将uni-app
整个组件类库都打包进去,则会造成极大的资源浪费,延迟首页渲染速度。
uni-app
发行到H5平台时采用了摇树优化(Tree-Shaking)策略,将开发者项目中没用到的组件从整个框架中“摇”掉,保证编译后的 JS 文件最小化。
具体来说,uni-app
编译到H5平台时分为预编译、再编译两个阶段,预编译阶段通过vue-template-compiler
分析出来的AST
,映射生成项目中使用到的组件清单,然后再基于Webpack
插件将使用到的组件编译生成一个最小化的uni-app
框架文件。
我们以uni-app
的两个开源项目模板登录模板、看图模板为例,测试 Tree-Shaking 前后组件框架的大小,效果喜人,数据如下:
路由组件按需加载(Lazy-Loading)
当打包构建 SPA 应用时,Javascript 包会变得非常大,影响页面加载。虽然开发者基于Vue
的异步组件和 Webpack
的code-splitting 功能,可以实现路由组件的懒加载,但开发者需调整.vue
源码及Webpack
配置,有一定的学习门槛,且比较繁琐。
uni-app
在H5平台实现了自动按需加载路由组件,开发者无需调整组件开发方式,仅需关心业务实现即可。
其它方面
uni-app
为提升性能体验,在很多细节上都有特殊设计。比如常见的 SPA 框架一般采用div
区域滚动,uni-app
为改善用户体验,使用的是body
滚动,由此填了很多坑,比如不同页面的background-color
,若使用div
滚动,则在编译阶段就可完成样式定义,但基于body
滚动,就需要在页面前进、后退时动态设置body
的背景色。