窗体切换白屏的现实问题

HTML5的性能比原生差很多,比如切页时白屏、列表滚动不流畅、下拉刷新和上拉翻页卡顿。
在低端Android手机上,很多原生App常用的功能和体验效果都很难使用HTML5技术模拟。
我们首先来看第一个问题,如何避免切页白屏。

浏览器的页面在切换时,由于其页面加载机制,在跳转到下一个页面时,先要请求联网、载入页面代码、构建dom、渲染,最后才显示出来。
在最终结果渲染完毕前,会出现几十毫秒甚至数秒的白屏。原生App是没有这个问题的。
虽然使用SPA单页应用模型,即ajax+div切换也可以避免白屏,但把所有页面写在一个SPA页面里,页面多了手机上也跑不起来,初始化非常慢,首页必然白屏,而且工程大了代码那个乱。。。被坑过的人自然知道。

解决窗体切换白屏的4种方案

标准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.0起,进一步对title的原生化做了简化了操作,在plus.webview的style里,可以配置navigationbar(以下简称nbar),如下示例:

plus.webview.create('http://m.weibo.cn/u/3196963860', 'testid', {'navigationbar':{'backgroundColor':'#D74B28','titleText':'导航栏标题','titleColor':'#CCCCCC'}})

这样创建webview时,会自带一个原生的title,文字、颜色、是否有返回箭头、分割线这些都可以设置,还可以通过getNavigationbar()方法得到一个nview对象,自由的向上面写字、绘图、处理点击响应。参考nview文档http://html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View

在mui框架中,进一步简化封装了mui.openWindowWithTitle()方法,参考http://dev.dcloud.net.cn/mui/window/#openWindowWithTitle

上面title有了,中间空白处可以先转个plus.nativeUI.waiting的原生雪花或显示加载中,这样转场时就不会飘白屏了。
一般本地页面加载都很快,转场动画300毫秒结束时,页面也渲染出来了。

另外提供几个让HTML页面渲染快的方法
- 页面渲染尽量不用js做,想要渲染快,就直接写HTML和css渲染,js渲染的界面显示更慢。
- 少用padding、margin,避免错位重绘。比如界面绘制开始是一个样子,然后很快位置移动进行重绘,这样很低效,容易闪屏。
- 减少图片尺寸

延伸:既然有nview,那是不是可以使用nview做完整界面,废除webview?
DCloud一直遵循的是HTML5+的规范和理念,即不推翻HTML,而是在HTML做的不好的地方强化补足。
从技术角度,除了原生title,开发者当然在动画时扩大nview的区域甚至整屏nview,这样动画时可以迅速显示整屏内容。但DCloud认为这也仅限于动画时这一屏幕,完整的页面仍然应该是HTML的。

早些年mui曾推荐使用过head和body分开载入的方案,此方案已废弃,由这里描述的原生title方案替代。

- 2、预加载html

既然HTML渲染慢,是否可以后台预加载,需要使用时直接动画进来?
当然是可以的。所谓预载,即后台预载新页面的HTML文件及资源,使用时直接调出这个已经创建好的webview。
Hello mui、36kr等项目源码,都使用了预载思路。
以新闻类app为例,启动首先载入资讯列表list页面,然后后台创建了一个隐藏的webview,加载了一个内容模板content页面。
在点击list页面的一个新闻item时,调用webview的窗体控制动画,把content页面侧滑进屏幕。
但content页面仅仅是一个模板而没有数据,在content页面刚侧滑进屏幕时,在content页面有一个“加载中”的提示。
紧接着content页面开始执行ajax请求,联网加载数据并显示出来。
我们可以在list页面的item点击里,一边移动窗体,一边通知新页面执行ajax。webview间相互传递消息使用webview的evalJS方法。
示例代码如下:

var webviewContent;
document.addEventListener('plusready', function(){ //扩展的js对象在plusready后方可使用
webviewContent = plus.webview.create("content.html");
});
function clicklist (id) { //list点击item后的事件
webviewContent.show("slide-in-right",200);
}

在mui框架里,对这个过程进行了简化封装,使用preload参数来控制。参考:http://dev.dcloud.net.cn/mui/window/#preload

预加载,由于不显示出来,并不会过多增加资源占用。(同时显示在屏幕上的webview不要超过3个,隐藏在后台的webview不要超过10个)
如果是list转到content,不同的item点击只是一个页面,完全可以使用预载。
但如果页面不同且较多,后台预载太多webview会有点慢。这里的慢不是会造成手机慢,而是预载是耗时间的。
预载这些网页时手机CPU消耗比较高,此时如果滑动列表,会发现滑动不流畅。

-3、等待webview渲染后再做动画

如果不使用前2种方案,为了不让转场动画飘白屏,我们也可以先等待webview渲染,渲染完毕在做动画显示。
即点击准备进入新页面时,先在屏幕上显示一个原生雪花(plus.nativeUI.waitting),然后后台创建一个不显示的webview,等待webview渲染后再做动画进来。

function clicklist (id) { //list点击item后的事件
var nwaiting = plus.nativeUI.showWaiting();//显示原生等待框
webviewContent= plus.webview.create("content.html");//后台创建webview并打开show.html
webviewContent.addEventListener("rendered", function() { //注册新webview的渲染完成事件
nwaiting.close(); //新webview的载入完毕后关闭等待框
webviewContent.show("slide-in-right",200); //把新webview窗体显示出来,显示动画效果为速度200毫秒的右侧移入动画
}, false);
}

上面的代码示例,就是等待webviewContent这个webview的rendered事件发生后,再调用动画api飘进来。
类似rendered的事件有好几个,详见http://ask.dcloud.net.cn/article/571
一般本地HTML页面,推荐使用titleupdate事件替代rendered事件,这个事件发生更早,可以更早的启动动画。
但是等待渲染完毕再做动画终究是会造成动画启动慢,体验不好,官方还是推荐使用方案1和2的原生title和预载。

-4、高级技巧:预截图

一般情况有上述几种方法就够了。但预截图的能力HTML5+也是提供了的,高手可以适时使用。
预加载虽然可以避免白屏的发生,但窗体动画有时不流畅,有些新窗体移入过程中,还在不停联网获取数据,不停重绘界面,导致窗体进入动画感觉卡顿,此时还有一个高级技巧是截图动画。
5+ runtime提供了一个plus.nativeObj.Bitmap的对象,同时webview对象提供了一个截图方法,可以把webview显示区域保存到bitmap对象中。此外webview的动画方法中支持传bitmap,这样给开发者提供了一个性能调优的手段。
我们可以预载一个webview,然后把这个webview预先截图下来,然后在窗体移入时在动画参数里传入保存这个截图的bitmap对象,这样窗体移动时,移动的就不是webview,而是移动的图片,这样能让窗体动画流畅许多。
流畅度:飘nview图>飘webview>飘div。
一般场景下飘webview就够了,在特别追求极致的环境下,可以飘图,流畅度杠杠的。
举个实例:从商品列表到商品详情界面,为了让点击响应速度更快,我们完全可以把商品详情里的非数据部分预截图,从列表点击时先popin动画飘一张提前截好的图进来,同时在图上面把商品名称写上去,同时ajax联网加载商品的json数据并渲染,然后在关闭假图。

mui框架的窗体函数封装

mui框架为了简化窗体管理的工作,把一些常用的窗体模型做了简化封装。
但对于复杂的窗体切换,仍需开发者搞明白上面提到的窗体切换原理。
mui的init方法,通过参数封装了preload,这样就可以方便的预载webview。
mui的openWindow方法,封装了显示waiting,载入新页面,处理动画,关闭waiting等工作。
mui的openWindowWithTitle()方法,封装了原生title。
mui的back样式控制,自动封装了窗体的隐藏和关闭。
这些方法具体参考mui的js API

启动后首页的白屏

首页是没有预加载的概念的。
启动封面的图片如何关闭是在manifest里配置的。
默认是在首页的webview的loaded事件发生后关闭。但又提供了若干选项。
不管你的首页是白屏了还是觉得进入太慢了,都可以控制。
在工程下manifest.json里找到plus、splashscreen节点,这里有event选项,可以配置是在哪个事件时close splash,默认是loaded,也可以配成titileUpdate、rendering、rendered。
如果autoclose设置为false,即手动可以在首页代码里写js控制封面图片的消失时机。
此时在首页合适的位置,一般在plus的ready事件后,调用js关闭封面图片,plus.navigator.closeSplashscreen();

关于如何优化启动速度,可以参考这篇文章http://ask.dcloud.net.cn/article/571

关于HBuilder早期版本Android手机返回时页面会先模糊后清晰的处理方法

为了节约系统资源,在webview不可见时,我们的引擎默认会回收掉它的渲染资源(但js仍可以正常操作)。
如果页面复杂、渲染的慢,在返回时可能会因为来不及渲染而造成先模糊后清晰的问题。
此时或者优化页面写法,加快渲染。或者使用我们提供的api,使得webview在不可见时一样不移除渲染资源。
具体API地址见plus.webview的webviewStyle对象里的render参数,render设为always即可不移除渲染,解决模糊的问题,但会占用更多内存。http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewStyle
另外从HBuilder7开始,pop-in、slide-in-right、fade-in等动画经过特殊处理,在返回时不会虚一下。

关于pop-in挤压动画和slide-in-right右移动画的取舍

plus.webview提供了很多切换动画,上下左右平移、淡入淡出、缩放、挤压......但比较常用的动画是右移slide-in-right和挤压pop-in。
一般在iOS上,强烈推荐使用pop-in,更接近原生体验。
在Android上,pop-in体验好,但性能消耗大于slide-in-right。因为pop-in是需要前后2个webview一起做动画,而slide-in-right是只有一个webview在动画。pop-in为了达到更好的效果,需要开发者编码时注意一些写法,如果写不好,效果还不如slide-in-right
这里是pop-in动画使用注意:http://ask.dcloud.net.cn/article/225

关于b/s和c/s的切屏效果对比

有些人认为HTML5=b/s,所有页面都是要从服务器下载。
但App其实界面是本地的,联网从服务器只是取json和图片,数据量小。
这种差别引发的问题就是,c/s的app加载速度快于b/s网页,流量消耗小于b/s网页。
所以想要优化到App的体验,就使用正经的App开发模式,做c/s,减少用户流量、加快切屏速度。
DCloud同时提供了c/s的本地app的动态升级方案,相比原生App,5+App的动态更新可以做到自动化、差量化。具体见http://ask.dcloud.net.cn/article/199

后记

不管使用哪种方法,都要注意一点,手机App的HTML页面必须本身性能足够高。
页面体积要小、加载和渲染要快。
互联网上有很多提升HTML、JS、CSS性能的方案,此处不再罗列。
但再次强调,尽量避免使用js渲染页面。
在页面load那1、2秒钟,手机的压力是非常大的,加载众多资源、构建dom、渲染、还要做动画,此时大量依赖js渲染界面的做法会让手机cpu、gpu忙不过来,要不卡动画、要不阻塞js。
pc上web框架的盛行,也是后来pc浏览器性能足够高之后的事情,互联网发展初期的开发者并不像如今这般依赖框架。
手机,尤其是低端Android机的性能也很差,如果照着写pc web的思路写页面,最终的用户体验必然会非常差。
首先,AMD框架尽量不用,包括angularjs在内,js动态解析标签再替换渲染是很慢的。
其次,jquery也尽量不要使用。document.getElementById("") 、document.querySelectorAll("")、$(""),这三者性能依次下降,尤其是在低端Android上遍历dom时,当你辛辛苦苦减少白屏和用户等待时间时,你会非常愤怒这些js框架拖了你的后腿。
并且HBuilder提供了很多代码块来快速完成代码,比如敲dg就可以出document.getElementById(""),比敲$("#")要快多了。
当然个别页面为了使用一些现成的jquery插件而引用了框架,倒也不会对app整体产生太大影响,这需要开发者自己根据产品对性能追求的极致程度来把握了。

提升HTML5的性能体验系列之一 避免切页白屏的更多相关文章

  1. 提升html5的性能体验系列之一避免切页白屏

    窗体切换白屏的现实问题 HTML5的性能比原生差很多,比如切页时白屏.列表滚动不流畅.下拉刷新和上拉翻页卡顿.在低端Android手机上,很多原生App常用的功能和体验效果都很难使用HTML5技术模拟 ...

  2. 提升html5的性能体验系列之四使用原生ui

    原生UI即nativeUI的设计目的 HTML和css有一个优势就是灵活的样式设计.在大多数情况下,我们都应该使用HTML+css来负责UI.但是有些情况下,我们发现HTML+css的UI不满足需求. ...

  3. 提升HTML5的性能体验系列之五 webview启动速度优化及事件顺序解析

    webview加载时有5个事件.触发顺序为loading.titleUpdate.rendering.rendered.loaded.webview开始载入页面时触发loading,载入过程中如果&l ...

  4. 提升HTML5的性能体验系列之四 使用原生UI

    原生UI的设计目的 HTML和css有一个优势就是灵活的样式设计.在大多数情况下,我们都应该使用HTML+css来负责UI.但是有些情况下,我们发现HTML+css的UI不满足需求.1. 绝对置顶HT ...

  5. 提升html5的性能体验系列之五webview启动速度优化及事件顺序解析]

    webview加载时有3个事件.触发顺序为loading.titleUpdate.loaded.webview开始载入页面时触发loading,载入过程中如果title已经解析并赋予新值,则触发tit ...

  6. 提升html5的性能体验系列之三流畅下拉刷新

    下拉刷新 为实现下拉刷新功能,大多H5框架都是通过DIV模拟下拉回弹动画,在低端android手机(Android4.4以下)上,DIV动画经常出现卡顿现象(特别是图文列表的情况).解决方案还是web ...

  7. 提升HTML5的性能体验系列之三 流畅下拉刷新和上拉

    下拉刷新 为实现下拉刷新功能,大多H5框架都是通过DIV模拟下拉回弹动画,在低端android手机(Android4.4以下)上,DIV动画经常出现卡顿现象(特别是图文列表的情况).解决方案还是web ...

  8. 提升HTML5的性能体验系列之二 列表流畅滑动

    App的顶部一般有titlebar,下面是list.常见的一个需求是要在list滚动时,titlebar不动.这个简单的需求,实现起来其实并不简单. 在普通web上的做法是使用div的滚动条,把lis ...

  9. 提升html5的性能体验系列之二列表流畅滑动

    App的顶部一般有titlebar,下面是list.常见的一个需求是要在list滚动时,titlebar不动.这个简单的需求,实现起来其实并不简单. 在普通web上的做法是使用div的滚动条,把lis ...

随机推荐

  1. 搭建asp渗透测试环境

    win2k3下载地址 http://yun.baidu.com/share/link?shareid=77306757&uk=2852438886 win2003 Enterprise Edi ...

  2. msf客户端渗透(六):抓包、搜索文件、破解弱口令、修改MACE时间

    嗅探抓包 查看网卡 指定网卡,因为资源有限,默认抓满50000个包如果不dump下来,就会自动销毁掉,从0开始抓. dump嗅探到的文件到本机,传递到本机的过程是结果ssl加密的 dump了两个文件 ...

  3. fiddler对浏览器、app抓包及证书安装(转)

    http://blog.csdn.net/u011608531/article/details/50838227 1.fiddler对浏览器抓包 1.1 对浏览器的http的抓包 Capturing开 ...

  4. Appium1.6启动ios9.3报错Original error: Sdk '9.3.5' was not in list of simctl sdks

    问题: 使用Apppium1.6启动ios9.3报错Original error: Sdk '9.3.5' was not in list of simctl sdks   我的启动配置如下 {   ...

  5. stock抓取基本资料

    use Goutte\Client; use GuzzleHttp\Client as GuzzleClient; include './vendor/autoload.php'; $client = ...

  6. http协议与常见状态码

    什么是http: http是属于应用层(基于tcp的连接方式)的面向对象的协议,是计算机通过网络通信的规则,使得浏览器向web服务器请求信息和服务 http协议特点: http是一种无状态协议(对食物 ...

  7. java日期加减年月日

    /** * 日期相加减 * @param time * 时间字符串 yyyy-MM-dd HH:mm:ss * @param num * 加的数,-num就是减去 * @return * 减去相应的数 ...

  8. TZOJ 2546 Electricity(去掉割点后形成的最大连通图数)

    描述 Blackouts and Dark Nights (also known as ACM++) is a company that provides electricity. The compa ...

  9. TZOJ 4621 Grammar(STL模拟)

    描述 Our strings only contain letters(maybe the string contains nothing). Now we define the production ...

  10. postman接口测试实例

    牛刀小试项目 抽奖项目