本系列文章是针对5+App的,与uni-app无关。uni-app不存在切换白屏问题
提升HTML5的性能体验系列文章目录导航:
- [提升HTML5的性能体验系列之一 避免切页白屏]
- 提升HTML5的性能体验系列之二 列表流畅滑动
- 提升HTML5的性能体验系列之三 流畅下拉刷新
- 提升HTML5的性能体验系列之四 使用原生UI(nativeUI)
- 提升HTML5的性能体验系列之五 webview启动速度优化及事件顺序解析
- 提升HTML5的性能体验系列之六 降低内存占用
窗体切换白屏的现实问题
HTML5的性能比原生差很多,比如切页时白屏、列表滚动不流畅、下拉刷新和上拉翻页卡顿。
在低端Android手机上,很多原生App常用的功能和体验效果都很难使用HTML5技术模拟。
我们首先来看第一个问题,如何避免切页白屏。
浏览器的页面在切换时,由于其页面加载机制,在跳转到下一个页面时,先要请求联网、载入页面代码、构建dom、渲染,最后才显示出来。
在最终结果渲染完毕前,会出现几十毫秒甚至数秒的白屏。原生App是没有这个问题的。
虽然使用SPA单页应用模型,即ajax+div切换也可以避免白屏,但把所有页面写在一个SPA页面里,简单几个页面还行。但页面多了手机上也跑不起来,初始化非常慢,首页必然白屏,而且工程大了代码那个乱。。。被坑过的人自然知道。
解决窗体切换白屏的方案
标准HTML5无法解决,我们就使用扩展的手段。
HTML5+是一套增强HTML5的规范,它可以用JS调用几十万原生API。
想要解决切页白屏这个问题,需要使用plus.webview类来做MPA多页应用(不是SPA单页应用)。
plus.webview类是对原生的webview对象的js化封装,使用js可以操作webview。
解决白屏的原理是:把每个页面当作一个webview,但用js来控制它就像控制div一样。动画时通过原生的view动画飘webview进来而不是通过css动画飘div进来
同时webview之间相互独立,不会出现SPA下不同页面js和css冲突的问题。
通过操作webview来避免切页白屏,有几种常见的做法:
1、动画先飘不会白屏的原生title进来
既然webview加载慢,转场动画会白屏。原生view加载快,不会白屏。那么能不能使用原生view呢,或者至少动画时先飘一个原生view的title进来,也不会整屏白屏。
HBuilder7.2起,提供了plus.nativeObj.View,也就是原生的view对象(以下简称nview),可以使用js向原生的view直接写字、绘图(注意是原生view不是webview)。
从HBuilder8.8起,优化了nview和Webview的关系,为Webview引入了titleNView和subNView,是从属于Webview的原生界面。titileNView也称ntitle,进一步对title的原生化做了简化了操作,在plus.webview的style里,可以配置titleNView,如下示例:
plus.webview.create('new.html', 'new', {'titleNView':{'backgroundcolor':'#FFFFFF','titletext':'标题栏','titlecolor':'#FF0000'}});
这样创建webview时,会自带一个原生的title,文字、颜色、是否有返回箭头、分割线这些都可以设置,见http://html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewTitleNViewStyles。还可以通过getTitleNView()方法得到一个nview对象,自由的向上面写字、绘图、处理点击响应。参考nview文档http://html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View
如果只是简单修改,比如修改title文字,也可以通过重设TitleNView的style来实现:
plus.webview.currentWebview().setStyle({titleNView:{titleText:'new text'}})
在mui框架中,进一步简化封装了mui.openWindowWithTitle()方法,参考http://dev.dcloud.net.cn/mui/window/#openWindowWithTitle
上面title有了,中间空白处可以先转个plus.nativeUI.waiting的原生雪花或显示加载中,这样转场时就不会飘白屏了。
一般本地页面加载都很快,转场动画300毫秒结束时,页面也渲染出来了。
另外提供几个让HTML页面渲染快的方法
- 页面渲染尽量不用js做,想要渲染快,就直接写HTML和css渲染,js渲染的界面显示更慢。
- 少用padding、margin,尽量写简单的代码,让页面一次渲染到位,而不是反复触发重绘。
- 减少图片尺寸,不要使用背景图(最常见的性能问题均来自于此)
理解了titleNView,我们再来看subnview。
同理,subnview也是原生渲染的view,它可用于更大面积的原生渲染。
在流应用里的唯品会中,商品详情界面的加载速度那么快,就是因为使用了subnview。参考视频http://v.qq.com/x/page/k05051mc143.html。
一般业务有titleNView就够了,追求极致体验的业务可以使用subnview。
所谓追求极致,就是要求在100毫秒渲染,动画期间就要完成联网和渲染。即使原生应用,大部分业务也是在动画完成后才渲染界面的。
使用subnview要在页面里大量通过js构造界面,不太直观。HBuilder8.3.3起,新增了wap2app项目,其中引入了nview模板,新建一个nview文件,可以使用类vue的方式开发,参考http://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/12757。后续会把nview模板引入到5+应用开发中。
延伸:既然有nview,那是不是可以使用nview做完整界面,废除webview?类似react native那样。
DCloud一直遵循的是HTML5+的规范和理念,即不推翻HTML,而是在HTML做的不好的地方强化补足。
即使在动画期间大量使用了subnview,但滚动后的完整的页面仍然应该是HTML的。
这样的解决方案即能满足用户体验要求,又能兼容好HTML5,是更好的解决方案。
早些年mui曾推荐使用过head和body分开载入的方案,此方案已废弃,由这里描述的原生title方案替代。
2、预加载html
既然HTML渲染慢,是否可以后台预加载,需要使用时直接动画进来?
当然是可以的。所谓预载,即后台预载新页面的HTML文件及资源,使用时直接调出这个已经创建好的webview。
尤其是从一个列表页面反复打开详情页面,仅仅是其中的数据不同,此时应该预载和复用详情Webview。
在Hello mui里有一个列表到详情的最佳实践示例,就是使用了这个思路,强烈建议大家在列表到详情时研究使用这个示例。文章参考http://ask.dcloud.net.cn/article/12575
只要服务器返回数据不拖后退,一样可以实现100毫秒渲染,动画期间完成联网和渲染。
预加载,由于不显示出来,并不会过多增加资源占用。(同时显示在屏幕上的webview不要超过3个,隐藏在后台的webview不要超过10个)
如果是list转到content,不同的item点击只是一个页面,完全可以使用预载。
但如果页面不同且较多,此时不建议预载太多Webview。后台预载太多webview需要耗很长,会抢cpu,此时用户如果在前台显示的Webview里操作比如滚动列表,会感觉到卡。
mui框架的窗体函数封装
mui框架为了简化窗体管理的工作,把一些常用的窗体模型做了简化封装。
但对于复杂的窗体切换,仍需开发者搞明白上面提到的窗体切换原理。
mui的init方法,通过参数封装了preload,这样就可以方便的预载webview。
mui的openWindow方法,封装了显示waiting,载入新页面,处理动画,关闭waiting等工作。
mui的openWindowWithTitle()方法,封装了原生title。
mui的back样式控制,自动封装了窗体的隐藏和关闭。
这些方法具体参考mui的js API。
启动后首页的白屏
首页是没有预加载的概念的。
首页的控制基本都在manifest里进行。
有2个与启动白屏有关的manifest设置。
1.launchwebview
在launchwebview里可以配置首页的titlenview,以及使用subnview制作tab。
这样顶部和底部实际上是由原生引擎渲染的,可以迅速显示。
参考文章:基于subnview模式的原生tab
- splashscreen
启动封面的图片如何关闭是在manifest里配置的。
默认是在首页的webview的loaded事件发生后关闭。但又提供了若干选项。
不管你的首页是白屏了还是觉得进入太慢了,都可以控制。
在工程下manifest.json里找到plus、splashscreen节点,这里有event选项,可以配置是在哪个事件时close splash,默认是loaded,也可以配成titileUpdate、rendering、rendered。
默认配置loaded事件是偏保守的,避免有的开发者首页代码写的不高效,导致白屏。
如果你的首页代码效率高、渲染快,则推荐配置成titileUpdate事件。
还有一种手动控制splash关闭的技巧,如果splashscreen节点下的autoclose设置为false,即手动,可以在首页代码里写js控制封面图片的消失时机。
此时在首页合适的位置,比如说联网结束或业务上的其他时间点,调用js关闭封面图片,plus.navigator.closeSplashscreen();
但不管什么方法,5+引擎的splash显示时间不会超过6秒,如果6秒内开发者仍不能做到首页渲染,那么用户会看到白屏。
关于如何优化启动速度,可以参考这篇文章http://ask.dcloud.net.cn/article/571
5+动画详解
这篇文章详细描述了5+提供的各种原生动画的特点及优化技巧,是必读文章http://ask.dcloud.net.cn/article/225
Android5的动画花屏、分块渲染解决方案
如果你遇到了相关问题,可以参考http://ask.dcloud.net.cn/article/12837
后记
不管使用哪种方法,都要注意一点,手机App的HTML页面必须本身性能足够高。
这是老生常谈的问题,但现实中还是大量App因为这个问题而导致性能体验出问题。
编写干净整洁、一次渲染的页面非常重要。
现在太多开发者在研究模式、框架,让页面渲染要经历二次、甚至四五次重绘才能完成。在短短几百毫秒的动画期间,这么干要不让页面卡、要不让渲染慢。
dom层级简单点,不要嵌套太多。
减少css二次渲染,就是少用复杂的选择器,少用padding、margin这些会二次修正页面的css。
如果追求极致的话,那jquery、zepto这些框架也不要使用,手机上都是webkit引擎,直接写document的api操作dom即没有兼容问题又没有效率问题。
2018年8月,DCloud推出了uni-app,这个产品自动优化了预载、原生组件,如果你无法把HTML5+的app优化的足够好,不如直接使用uni-app。无需优化天然达到微信小程序水准。
58 个评论
要回复文章请先登录或注册
8***@qq.com
5***@qq.com
Fanta
1***@qq.com
wfc1870
这个昵称真好
臻厚
jqr
pioneer
好冷