English
uni-app
在非 H5 端运行时,从架构上分为逻辑层和视图层两个部分。逻辑层负责执行业务逻辑,也就是运行 js 代码,视图层负责页面渲染。
虽然开发者在一个 vue 页面里写 js 和 css,但其实,编译时就已经将它们拆分了。
逻辑层是运行在一个独立的 jscore
里的,它不依赖于本机的 webview,所以一方面它没有浏览器兼容问题,可以在 Android4.4 上跑 es6 代码,另一方面,它无法运行 window
、document
、navigator
、localstorage
等浏览器专用的 js API。
`
jscore
或 v8
的基础上新增了一批浏览器专用 API,比如 dom;jscore
上补充了一批手机端常用的 JS API,比如扫码。h5 和小程序平台,以及 app-vue,视图层是 webview。而 app-nvue 的视图层是基于 weex
改造的原生渲染视图。
关于 webview,在 iOS 上,只能使用 iOS 提供的 Webview(默认是 WKWebview
)。它有一定的浏览器兼容问题,iOS 版本不同,它的表现有细微差异(一般可忽略)。
Android 上小程序大多自带了一个几十 M 的 chromium webview,而 App 端没办法带这么大体积的三方包,所以 App 端默认使用了 Android system webview,这个系统 webview 跟随手机不同而有差异。当然 App 端也支持使用腾讯 X5 引擎,此时可以在 Android 端统一视图层。
所以 uni-app 的 js 基本没有不同手机的兼容问题(因为 js 引擎自带了),而视图层的 css,在 app-vue 上使用系统 webview 时会有手机浏览器的 css 兼容问题。此时或者不要用太新的 css 语法,或者集成腾讯 x5 引擎。
逻辑层和视图层分离,好处是 js 运算不卡渲染,最简单直接的感受就是:窗体动画稳。
如果开发者使用过 App,应该有概念,webview 新窗体一边做进入动画,一边自身渲染,很容易卡动画。而 uni-app 则无需写预载代码,新窗体渲染快且动画稳定。
However, the separation of the two layers also brings a disadvantage, that is, it will cause loss while the two layers communicate with each other.
iOS 还好,但 Android 低端机上,每次通信都要耗时几十毫秒。平时看不出来影响,但有几个场景表现明显。
不管小程序还是 app,不管 app-vue 还是 app-nvue,都有这个两层通信损耗的问题。
解决这类问题,在 webview 渲染和原生渲染引用了不同的做法:
在 app-vue 和微信小程序上,提供了一种运行于视图层的专属 js,微信叫做wxs。
wxs 中可以监听手势,以 uni ui 的 swiperAction 组件为例,手指拖动,侧边的列表菜单项要跟手滑出,此时就需要使用 wxs 才能实现流畅效果。还有插件市场里一些自定义下拉刷新的插件,通过 wxs 实现了更高的性能体验。
uni-app 支持把 wxs 编译到微信小程序、App 和 H5 中。
微信里对 wxs 限制较多,只能实现有限的功能。app 端提供了更强大的renderjs,并兼容到 H5 平台。
比如 canvas 动画,微信的 canvas 无法通过 wxs 操作,js 不停绘制 canvas 动画因通信折损而无法流畅。uni-app 的 app-vue 里的 canvas 对象设计在 webview 视图层的,通过 renderjs 可以在视图层直接操作 canvas 动画,将不再有通信折损,实现更流畅的效果,详见:renderjs
在 app-nvue 里,逻辑层和视图层的折损一样存在。包括 react native 也有这个问题。所以也千万别以为原生渲染就多么高级。
weex 提供了一套 bindingx 机制,可以在 js 里一次性传一个表达式给原生层,由原生层解析后根据指令操作原生的视图层,避免反复跨层通信。这个技术在 uni-app 里也可以使用。
bindingx 作为一种表达式,它的功能不及 js 强大,但手势监听、动画还是可以实现的,比如 uni ui 的 swiperAction 组件在 app-nvue 下运行时会自动启用 bindingx,以实现流畅跟手。
For complex pages, when updating data in a certain area, you need to make this area a component, so that only this component is updated when updating data, otherwise the data of the entire page will be updated, causing click delays to be stuck.
比如微博长列表页面,点击一个点赞图标,赞数要立即+1,此时这个点赞按钮一定要做成组件。否则这个+1 会引发页面级所有数据的从 js 层向视图层的同步。
app-nvue 和 h5 不存在此问题。造成差异的原因是小程序目前只提供了组件差量更新的机制,不能自动计算所有页面差量。
If a large number of large image resources are used in the page, the switching of pages will be stagnated, and the system memory will increase, even crash with a white screen.
尤其是不要把多张大图缩小后显示在一个屏幕内,比如上传图片前选了数张几 M 体积的照片,然后缩小在一个屏幕中展示多张几 M 的大图,非常容易白屏崩溃。
对大体积的二进制文件进行 base64,也非常耗费资源。
在 uni-app
中,定义在 data 里面的数据每次变化时都会通知视图层重新渲染页面。所以如果不是视图所需要的变量,可以不定义在 data 中,可在外部定义变量或直接挂载在 vue 实例上,以避免造成资源浪费。
页面初始化时,逻辑层如果一次性向视图层传递很大的数据,使视图层一次性渲染大量节点,可能造成通讯变慢、页面切换卡顿,所以建议以局部更新页面的方式渲染页面。如:服务端返回 100 条数据,可进行分批加载,一次加载 50 条,500ms 后进行下一次加载。
Deep nested nodes often need to occupy more memory when the page is initialized and built, and they will be slower when traversing nodes, so it is recommended to reduce deep nested nodes.
有些 nvue 页面在 Android 低端机上初次渲染时,会看到从上到下的渲染过程,这往往都是因为组件过多导致的。每个组件渲染时都会触发一次通信,太多组件就会阻塞通信。
HBuilder X 3.6.9+ 已支持暗黑模式。详情
App.vue
里,可以加速页面样式渲染速度。App.vue
里面的样式是全局样式,每次新开页面会优先加载 App.vue
里面的样式,然后加载普通 vue 页面的样式。"style": {
"app-plus": {
"background":"#000000"
}
}
在 App 端 uni-app
的 nvue 页面可是基于 weex 升级改造的原生渲染引擎,实现了页面原生渲染能力、提高了页面流畅性。若对页面性能要求较高可以使用此方式开发,详见:nvue。