用HTML5实现iPad应用无限平滑滚动
最后更新于:2022-04-01 19:43:56
**前言:**
LinkedIn 5月2日发布了新的iPad版本,它基于HTML5制作,在体验和界面上非常出色,在使用中可以发现它和原生应用基本没有任何差别。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9a2e6e2777.jpg)
关于这个版本,有两篇文章非常有价值,深入的介绍了Mobile Web App和HTML5移动开发的原理和方法。
第一篇《[你绝对想不到的](http://venturebeat.com/2012/05/02/linkedin-ipad-app-engineering/#s:profile_ipad_frame)LinkedIn如何构建iPad新应用》主要包括三个方面的内容:
- **LinkedIn and themobile web**
LinkedIn开始越来越多的采用HTML5来开发移动Web应用。
- **Now, with more Node.js**
大量使用了node.js。
- **“Responsive design” just doesn’t work**
他们认为[响应式网页设计](http://blog.csdn.net/hfahe/article/details/7082718/)对简单的、一次性的网站很有用,但是对应用或者社交网络来说,它没有那么好。
-------- -------- -------- -------- 华丽的分隔线
而下面一篇文章讲述了LinkedIn是如何使用HTML5在iOS中实现平滑无限滚动以及内存和性能优化的。
**LinkedIn iPad版:用HTML5的5项技术实现无限平滑滚动**
**作者:[TrunalBhanse](http://www.linkedin.com/in/trunal)**
译者:蒋宇捷
这是在一系列博客文章中的第二篇,我们将聊聊[LinkedIn新的iPad应用](http://itunes.apple.com/us/app/linkedin/id288429040?mt=8)。在第一篇文章中,我们谈到了[如何使用](http://engineering.linkedin.com/mobile/linkedin-ipad-using-local-storage-snappy-mobile-apps)HTML5本地存储建立敏捷的移动体验,而这篇文章我要讲讲当实现一个无限翻页的列表时所面临的挑战。
### 什么是“流”?
当iPad项目开始时,我们考虑过如何才能为用户创造一个引人入胜的内容消费体验。我们决定以“流”的方式来展示文章、网络更新,以及其他类似的内容:一个可以无限翻页的界面。这里是页面流的第一页:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9a2e70a042.jpg)
### 移动设备上无限列表的挑战
和台式机相比,移动设备具有更少的内存和更低的CPU主频。如果在HTML页面中渲染很长的列表,你会面临运行设备崩溃的危险。这使得在移动设备上构建大型的HTML5互动应用成为一个挑战。Native技术提供了[UITableViewController](http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewController_Class/Reference/Reference.html)来建立长的,无限滚动的列表。UITableView包含可复用的UITableViewCells来优化内存,性能以及响应。而针对HTML5我们没有任何现成解决方案。因此,我们将自己实现一个!
### 技巧1:移除图像
UIWebView或者移动Safari浏览器对[图像有严格限制](http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html)。我们的页面流里铺满了大尺寸图像,所以很快就会达到上限。一种选择是使用[HTML5Canvas](http://www.w3.org/TR/html5/the-canvas-element.html#the-canvas-element)绘制图像,[不会](http://roblaplaca.com/blog/2010/05/05/ipad-safari-image-limit-workaround/)带来内存问题。然而我们发现在画布上绘制非常大的图像相当缓慢,所以我们不得不采取另一种方法:当一副图像完全“流”出屏幕时,用另一副非常小的图像替换img标签的“SRC”属性。这能确保渲染大型图像所使用的内存被定期释放。此外,我们保证并没有引入[图像空src属性的错误](http://www.nczonline.net/blog/2009/11/30/empty-image-src-can-destroy-your-site/)。
### 技巧2:隐藏页面
释放图像并没有回收足够的内存来防止崩溃。因此,我们开始通过将CSS 的visibility属性设置为hidden 来隐藏流的独立页面(图2表示“隐藏”的页面)。经过这种调整,我们不仅看到了更多的内存被回收(这样应用程序就不会崩溃),而且渲染速度也更快,因为浏览器不会为界面上“隐藏”的页面进行绘制。
### 技巧3:删除页面
采用隐藏的页面可以覆盖80%的情况。但是余下的20%仍然会导致应用程序崩溃!我们更进一步,开始删除不需要的页面。作为副作用,如果我们删除当前页面左侧的页面,页面流会左移,而用户将失去所在位置。为了保持滚动位置,我们不得不在移除页面时(即DOM节点)用同样高度和宽度的空白页面来取代(图2中示意的“占位符”)。例如,如果用户正在浏览第5页,我们删除第0页,并用占位符取而代之。
采用了上述的3种技术,我们的流开始类似于下面图里的样子。 正如你可以在图1中看到的一样,如果用户正在查看第3页,前一页和后一页将完全加载。而当用户决定向前或者向后翻页时,他可以看到完全呈现的页面。当用户试图滚动时,我们开始加载图像并渲染页面。它可以在iPad模拟器上完美运行,但在实际设备上,你可以看到滚动性能的下降。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9a2e71fa01.png)
图1
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9a2e736ada.png)
图2
正如图2所示,当用户翻动到第5页,第0和第1页将会被删除,第2页将会隐藏,而第3页移除了所有图像。此时,用户可以继续向前翻页,其它页面将根据它们和可见页面之间的距离来决定是移除图像、隐藏还是删除自身。
我们不得不为不同版本的iPad使用一个可变大小的“窗口”。例如,iPad1内存最少,所以我们不得不给它一个非常小的窗口:
~~~
getConfig : function() {
//默认设置
var config = {
size : 3,
maxVisibleOnOneSide : 1,
};
//根据设备更新设置
if($isDesktop || $native.isNative() && $os.ipad) {
//检测是ipad1还是ipad2
if($isDesktop || $native.getDeviceVersion() > 1) {
config.size = 7;
config.maxVisibleOnOneSide = 2;
}
}
return config;
}
~~~
### 技巧4:避免缩放和盒阴影
按照之前的经验,我们使用两个HTML / CSS的优化技巧来改善性能:
- 通过HTML IMG标签中指定宽度和高度属性来避免客户端缩放图像
- 避免CSS盒阴影:它在[WebKit下很慢](https://bugs.webkit.org/show_bug.cgi?id=22102%60)
### 技术5:减少DOM节点
经过上述优化,你是否预期应用再也不会崩溃?错了!在测试过程中,上述技巧让应用程序运行的时间更长,但一段时间后它仍然会崩溃。
根据之前[iPhone应用](http://itunes.apple.com/us/app/linkedin/id288429040?mt=8)的经验,我们知道保持DOM节点最少是平滑滚动和保证足够内存的关键点。 记住这一点后,我们将所有占位所用的节点合并为一个虚拟的,相同大小的节点。结果是:不管我们滑动到多少页,页面流不会在任何设备上崩溃!最终机制如图3所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9a2e74b6cd.png)
图3
### 技术实现的视频
[这里](http://www.youtube.com/embed/Zc0tCMLRVWU)有一个当用户滑动翻页时,DOM所表现出来行为的视频。左边我们在Chrome窗口中加载页面流。而在右边,我们通过Chrome的开发者工具来展示如何添加或删除节点和通过虚拟页面的宽度来填补被删除的网页。 请注意DOM节点是如何保持在一个恒定的数量的,以及UL 的第一个li节点(“虚拟”节点)大小是如何增长的(你可能需要全屏播放视频来看)。
### 失败的尝试
我们并没有在第一时间得到正确的结果,所以必须要列出我们一些曾经失败的尝试。我们最开始使用多个UIWebViews来各自渲染一个页面并用UISwipeGestureRecognizer来翻页。 然而我们很快就意识到,在本地应用程序使用多个Web视图在内存和性能方面是一种糟糕的方式。
随后我们尝试了和[3-DIV](http://cubiq.org/swipeview)类似的方法。它可以工作,但是我们对滑动翻页的性能并不满意。 有时如果用户在翻页,我们同时在渲染一个页面,单线程的UIWebView 将无法添加到页面流里面。
### 致谢
感谢[Akhilesh Gupta](http://www.linkedin.com/in/guptaakhilesh), [AarthiJayaram](http://www.linkedin.com/in/aarthijayaram), [AshitGandhi](http://www.linkedin.com/in/atlgandhi), [KiranPrasad](http://www.linkedin.com/in/kiranprasad)和[Ganesh Srinivasan](http://www.linkedin.com/in/gan3sh)。
此外,特别感谢 [Ryan](http://www.linkedin.com/in/ryanblunden)帮我为这篇文章录制视频。
原文链接:《[LinkedIn for iPad: 5 techniques for smooth infinite scrolling in HTML5](http://engineering.linkedin.com/linkedin-ipad-5-techniques-smooth-infinite-scrolling-html5)》
转载请注明:来自[蒋宇捷的博客](http://blog.csdn.net/hfahe)
';