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

系列文章目录导航:
- 提升HTML5的性能体验系列之一 避免切页白屏
- 提升HTML5的性能体验系列之二 列表流畅滑动
- 提升HTML5的性能体验系列之三 流畅下拉刷新
- 提升HTML5的性能体验系列之四 使用原生UI(nativeUI)
- 提升HTML5的性能体验系列之五 webview启动速度优化及事件顺序解析
- 提升HTML5的性能体验系列之六 降低内存占用

【本文更新时间2017-10-7】

App的顶部一般有titlebar,下面是list。
常见的一个需求是要在list滚动时,titlebar不动。
这个简单的需求,但在HTML世界里实现起来其实并不简单。因为普通的HTML方式做不到60fps的无掉帧平滑滚动。

在pc web上的做法是使用div的区域滚动,把list放到div里。
但div滚动条在Android4.4以下的手机上不可商用,如果dom复杂,不管多高端的Android手机,滚动效果也惨不忍睹。

还有一种做法是把titlebar使用fix来固顶。
但此时手机浏览器的滚动条会通到顶部,当titlebar的右侧出现滚动条时,看起来非常怪异。
还有一个副作用是滚动太快时,titlebar的div会下来一下又弹上去。这是因为滚动时触发页面重绘,dom很复杂时重绘来不及,绝对定位的titlebar就会先下来后上去。

还有一种方法是使用自绘的滚动条,即不用浏览器的滚动条,自己画一个滚动条,iScroll等方案是采取这种思路。但模拟的始终是模拟的,和原生的滚动条效果还是差很多,在列表头和尾的拉动回弹的表现不佳,而且列表长了、内容复杂了,非常卡顿。

想要解决这个问题其实也不难,既然div的滚动条卡,而浏览器body的整体滚动条不卡,那就老老实实使用浏览器的body滚动。至于title区域的滚动条通顶和固定方案,使用原生title来解决。
HBuilder8.0起,支持了原生的titleNView,创建webview对象时,在style参数里配置titleNView就可以在Webview上加一个原生的title。

plus.webview.create('new.html', 'new', {'titleNView':{'backgroundcolor':'#FFFFFF','titletext':'标题栏','titlecolor':'#FF0000'}});
\n

HTML页面的滚动部分会自动在这个原生title下面。

titleNView的具体api见,功能还是比较丰富的:http://html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewTitleNViewStyles
titleNView属于Webview的style,自然也可以通过Webview的setstyle方法来修改titleNView的参数,比如用js动态修改titleNView上的文字,可以使用setstyle方法给titleNView重新配置参数即可。修改是增量的,不是全量重写。

提到原生封装的title,人们的直觉一般是自定义性差。
但其实不然,DCloud始终重视开发者的自定义性。
titleNView的父类是plus.nativeObj.view,这是一块原生画布,可以自由的在上面写字绘图、设编辑框,拥有良好的自定义性。
通过Webview的getTitleNView()方法,可以得到标题栏的NView对象,然后参考nview的api,自由定制界面。http://html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View

当然90%的使用场景,在titleNView自带的封装参数里就能完成。个别情况下开发者才需要研究nview的api手绘界面。

配合nativeObj下面的原生imageslider,还可以实现沉浸式题图效果,题图开始通顶到状态栏上,在向下滚动后渐变消失,而title渐变出现,非常动感。
关于沉浸式,是另外的话题,此处不展开。有兴趣可参考http://ask.dcloud.net.cn/article/1150

使用titleNView还有一个好处,在新窗体动画时,不管内容页面渲染多么慢,原生title在动画期间一定是渲染好的,这样页面不会整屏白屏。

mui对这个效果进行了封装,使用mui.openWindowWithTitle即可打开一个带原生头的webview。
在Hello mui里nav bar中点“native title”,可看到效果和源码。

已过期历史:在HBuilder8.0以前,官方曾推荐过双Webview式title。
即把屏幕切分成2个webview,把titlebar的HTML装载到一个webview里,list页面是另一个webview,list页面直接使用浏览器的滚动条而不是div滚动条,这样也可以得到一个流畅的列表滑动体验。
在mui框架里,通过mui的init里的subpage,可以通过配置而不是编码的方式更加简单的开发这种双webview界面。
但在nview成熟后,官方已经废弃了双Webview模式。目前是不再主推双Webview,但开发者的老代码仍然可以兼容。官方未来会直接在底层移除对双Webview的支持。

关于bounce回弹效果
HTML5+提供了原生的bounce回弹效果,默认是开启的。
但也可以关闭和进行参数设置,具体见http://html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewBounceStyle

如果你的App滚动不流畅,可能的原因:

\n

  1. 有人仍然使用div滚动然后抱怨滚动不流畅,注意检查自己的代码,一定要用body滚动而不是div滚动。
    mui为了多端发布兼容和部分选择器项目滚动,是提供了div滚动的,尤其是在iOS上因为性能较高使用面更大,但这些都是可配置的,觉得不流畅时注意检查配置是不是变成div滚动了。
  2. 不管是mui提供的div滚动还是plus.webview的body滚动,都是可以设滚动加速度值的,可以根据自己的页面情况设置不同的加速度值。默认其实不用设置,但如果你设置了错误的值,请检查并修复。
  3. 你可能关闭了硬件加速。Android上如果不开启硬件加速,很难做到60fps的平滑滚动。具体参考Android硬件加速详解
  4. 可能是因为js监听了滚动。js监听滚动,并实时计算和修改dom,会导致卡顿。如果你需要做下拉到底自动翻下一页,那么只需要监听HTML5+提供的页面到底事件,而不是任意滚动事件都监听。具体参考提升HTML5的性能体验系列之三 流畅下拉刷新
\n
16 分享 关注
wglhtml5 hellojh 海洋 仙人指路 大鱼泡泡 igo44444 dreamboycx 你猜我猜不猜 最爱橙子 Android_XR 977294777@qq.com 可苦可乐 982912393@qq.com 2719722353@qq.com 11523110@qq.com windmxa1@qq.com
DCloud_heavensoft

DCloud_heavensoft 回复 biubiu灬

http://ask.dcloud.net.cn/article/141
0 赞 2018-07-19 09:47
biubiu灬

biubiu灬 回复 DCloud_heavensoft

我放在body里滚动了,但是下拉刷新显示不出来
0 赞 2018-07-19 08:30
蔡邵鑫

蔡邵鑫 回复 DCloud_heavensoft

body中height:100%,滑动会与下拉刷新冲突
http://ask.dcloud.net.cn/question/44422
0 赞 2017-12-20 13:48
hcoder深海

hcoder深海

沉浸式、mui、h5+ 视频教程:
http://www.hcoder.net/course/index/cate/4
0 赞 2017-07-06 09:27
小虎虎

小虎虎 回复 DCloud_heavensoft

Android 初始化的时候子页面打开下拉刷新和上拉加载功能。下拉时有回弹效果,可是上拉的时候是没有回弹效果的。
还有一个问题是,为什么把子页面的bounce打开后,Android并无bounce效果
0 赞 2016-12-16 11:06
DCloud_heavensoft

DCloud_heavensoft

js不要检测滑动,Android浏览器默认的上下滚动没有故障,我们的这个方案也不会干涉新的斜上滑动问题。
0 赞 2014-10-27 17:14
musiclee

musiclee

试过发现这种方式在iphone4上面滑动是比较流畅的,但是在android下面有个问题,就是手指如果是斜着上下滑动,那么经常滑不起,只能是比较严格的上下滑动没问题,这个怎么解决?在plus里面有没有配置一类的方式来放宽对滑动的检测条件?
0 赞 2014-10-27 10:35
M5

M5

可以卸载框架中,写一个方法将窗体分为三部分,head,body,footer。将head做为主窗体,加载content(也就是body部分),head和footer是兄弟窗口,均在body上方。
函数:
function con(id,url,x,y)
用于根据一个DOM元素的高宽创建一个浮动窗口。
参数:
id为DOM元素的名字,同时也会是浮动窗口的名字
url为浮动窗口加载的页面
x为浮动窗口加载时的X坐标
y为浮动窗口加载时的y坐标

浮动窗口的高宽与id所指定的DOM元素的高宽相同。
0 赞 2014-09-26 09:15
DCloud_heavensoft

DCloud_heavensoft 回复 wglhtml5

可以。使用webview的evaljs方法,见http://www.html5plus.org/#specification#/specification/Webview.html
1 赞 2014-08-28 21:53
wglhtml5

wglhtml5

这两个webview之间能互相访问吗?
0 赞 2014-08-28 16:12
向涛

向涛 回复 DCloud_heavensoft

哦,那你帮我看下,下面的代码,我把listbox 改到 body 上去滚动 就不会卡了?
0 赞 2014-08-09 23:01
向涛

向涛

我现在用的大概代码是:
.titlebar{
postion: absolute;
top: 0;
left: 0;
height:44px;
width: 100%;
z-index: 2;
}

.listbox{
border-top: 44px solid rgba(0, 0, 0, 0);
height: 100%;
box-sizing: border-box;
overflow: auto;
-webkit-overflow-scrolling: touch;
}

<header class="titlebar"></header>

<div class="listbox"></div>

list里面才20多条数据,在iPhone4 下都会卡,
0 赞 2014-08-09 23:00
DCloud_heavensoft

DCloud_heavensoft

body不会卡,只有div会卡。把list放在一个webview使用浏览器的滚动条滚动,不要放到div里。
2 赞 2014-08-09 22:50
向涛

向涛

在普通web上的做法是使用div的滚动条,把list放到div里。
但是很不幸的是,div滚动条在Android上非常非常卡,滚动完全无法商用。

按照上面的两种方式,感觉还是没有解决到滚动卡的问题呢?
还是说,body滚动不会卡,只有div滚动会卡?
0 赞 2014-08-09 22:43

要回复文章请先登录注册