移动Web单页应用开发实践——页面结构化

1. 前言

在开发面向现代智能手机的移动Web应用的时候,无法避免一个事实,就是需要开发单页应用(Single Page WebApp)。对于不同的系统需求,单页应用的粒度会不同,可能是整个系统都使用一个页面装载,也可能是按模块分为独立页面装载。在开发单页应用时第一个要处理的问题就是页面结构化,由于多个功能集中在一个页面呈现,就必然需要考虑如何实现多个视图布局?如何实现视图之间动画切换?等问题。

下面我就来讲述下手机搜狐前端团队在单页应用开发的页面结构化上做过的一些尝试与努力。

2. 页面视图

在讲页面结构化之前需要先理解视图的概念,视图是单页应用开发中最常见的模块,通常在一个单页应用中,会有多个视图存在,每一个视图都可以处理一部分业务功能,所有视图的功能集就是单页应用所能处理业务的最大能力。下面介绍几种单页应用中最常出现的几种视图。

2.1 单视图层

三段式结构是单视图的一种最基本布局方式,如下图:

单视图并不一定都有head或foot,所以Header、Footer使用虚线来表示。多数应用中还会有导航条(Navigatior),但一般情况下导航条会被计算为Header或Content的一部分,而不会独立存在。

2.2 侧边栏

侧边栏是一种特殊的视图,在不显示时,当前视图是盖在侧边栏至上的,当它被呼出时,视图一部分滑出屏幕外,侧边栏才被显示出来,它的高度等于页面可视区域的高度。

显示前:

显示后:

2.3 封面图

封面图与侧边栏类似,也是一个特殊的视图。封面图一般会在页面初始时候出现,而后消失,消失之后就不再出现。它的视图层级是最高的,并且完全覆盖于其他页面元素,它的高度会大于或等于可视区域的高度。

3 多视图布局

单页应用中第一个要思考的问题就是:如何实现多视图的布局?通常我们会将视图的定位设置为position:absolute,这是一种简单又实用的方法。在一个时间节点上,页面可视区域只能有一个可见的当前视图,虚线表示其他视图,在页面可视区域之外不可见(display:none),如下图:

使用伪代码表示:

<style type="text/css">

    .view {

        position: absolute;

        top: 0;

        left: 0;

        z-index: 99;

        display: none;

        width: 100%;

        height: 100%;

    }

    .current {

        z-index: 100;

        display: block;

    }

</style>

<div class="view current"></div>

<div class="view"></div>

此时,我们需要思考另一个问题:如何实现当前视图的Content区域内容滚动?视图的样式高度设置为height:100%,将视图高度设定为一屏高的目的是为了方便实现视图动画切换的效果(视图动画切换会在后面详细的讲)。但这样做会导致另一个问题,高度为一屏高意味着浏览器滚动条失效,无法使用浏览器滚动条滚动页面。

3.1 基于iScroll的多视图布局

现在比较流行的一种解决方案是使用iScroll组件实现固定区域滚动,这样就能解决Content区域的滚动问题,在手机搜狐的早期项目也是这么做的。此外,使用iScroll还额外带来了一些好处,如:

  • Header区域能固定在页面顶部,不会因为Content区域滚动导致Header被顶上去;
  • 单视图的高度控制在一屏高,这样有利于实现视图之间的动画切换;

对于这种结构的应用,在使用视图切换的时候就非常好做,使用CSS3的transition来完成动画切换,如下图:

使用伪代码表示:

<style type="text/css">

    .current.out {

        -webkit-transition: -webkit-transform 400ms;

        -webkit-transform: translate3d(-100%,0,0);

    }

    .next {

        display: block;

        -webkit-transform: translate3d(100%,0,0);

    }

    .next.in{

        -webkit-transition: -webkit-transform 400ms;

        -webkit-transform: translate3d(0,0,0);

    }

</style>

<div class="view current out"></div>

<div class="view next in"></div>

视图切换的动画效果可以根据业务需求定制,比如:由左向右滑动、由右向左、由上到下、右下到上等都是可以的。在完成切换动画时,再将next视图的状态设置为current,如下:

<div class="view"></div>

<div class="view current"></div>

下图是项目中使用的一个由下往上动画切换效果:

3.2 iScroll页面结构下的侧边栏

使用iScroll的页面结构,无论是侧边栏还是封面图都非常好实现,看伪代码:

侧边栏,默认状态

<style type="text/css">

    .sidebar {

        z-index: 50;

        display: block;

        width: 80%;

    }

    .sidebar.show + .current {

        -webkit-transition: -webkit-transform 400ms;

        -webkit-transform: translate3d(80%,0,0);

    }

    .sidebar.hide + .current {

        -webkit-transition: -webkit-transform 400ms;

        -webkit-transform: translate3d(0,0,0);

    }

</style>

<div class="view sidebar"></div>

<div class="view current"></div>

侧边栏显示时

<div class="view sidebar show"></div>

<div class="view current"></div>

侧边栏隐藏时,当hide动画结束之后,移除hide样式

<div class="view sidebar hide"></div>

<div class="view current"></div>

3.3 iScroll页面结构下的封面图

封面图的实现与侧边栏差不多。

封面图,默认状态

<style type="text/css">

    .cover {

        z-index: 200;

        display: block;

        visibility: hidden;

        opacity: 0;

    }

    .cover.show {

        visibility: visible;

        -webkit-transition: opacity 400ms;

        opacity: 1;

    }

    .cover.hide {

        visibility: visible;

        -webkit-transition: opacity 400ms;

        opacity: 0;

    }

</style>

<div class="view cover"></div>

<div class="view current"></div>

封面图显示时

<div class="view cover show"></div>

<div class="view current"></div>

封面图隐藏时,当hide动画结束之后,移除hide样式

<div class="view cover hide"></div>

<div class="view current"></div>

在项目中的实现效果:

3.4 iScroll对内容刷新的支持

对于Content区域的内容刷新iScroll也有很好的支持,可以直接参见iScroll提供的例子:http://lab.cubiq.org/iscroll/examples/pull-to-refresh/

Note:iScroll目前已经更新到了5.0的版本,大家可以关注Github项目https://github.com/cubiq/iscroll/

4. 多视图布局,新的探索

对于单页应用来说,iScroll确实是一个非常优秀的解决方案,但是iScroll缺有一个最大的缺陷——慢,滚动的性能与浏览器原生实现相比,在低端的移动设备上有明显卡顿,这点我在另一片博文中也提到过《移动Web产品前端开发口诀——“快”》。

Note:目前有一个新的趋势,浏览器经过一两年的发展,Android下已经优化的相当不错,iScroll在一些较低端的移动设备上,性能表现得比以前要好非常多,比如小米1,早期的米1还在运行UC7.x的版本时,iScroll明显的卡,现在在UC9.x下,iScroll也能运行得比较流畅了。

4.1 Fixed+原生Scroll

在此之下,我们也做了一些新的尝试,第一尝试就是放弃使用iScroll组件。放弃之后遇到的第一个问题,如何使Header固定位置在顶部?由此,我们使用了原生的CSS特性position:fixed,如下图:

Fixed在一些移动设备浏览器上有兼容问题,我找到了一种能检测浏览器是否支持position:fixed的方法,这个也发一篇博文《移动Web开发,4行代码检测浏览器是否支持position:fixed》,在检测到浏览器不支持fixed时,可以使用absolute作为替代方案,监听window的scroll事件,每次scroll动作结束时,重新计算一次Header的top值,将其定位到页面顶部。

有关position:fixed的bug在另一篇博文中《移动端web页面使用position:fixed问题总结》也有总结。

另外强调一点,不要在Fixed区域中直接使用input或textarea元素。在fixed元素中的input获取焦点之后,弹出软键盘会带来很多额外的问题,如:

  • 在iOS下软键盘弹出,fixed定位会出问题;
  • 在Android下软件盘弹出,可能会导致输入区域被遮挡;

点击input弹出一个新视图来完成后续输入,是一种比较好的解决方案,下图是一个基于iScroll的页面结构实现:

4.2 原生Scroll下的视图切换

使用了原生Scroll之后,带来最大的改变是视图切换动画的变化。使用iScroll的页面结构,视图的高度固定,并且是position:absolute定位,所以非常容易做视图切换。

换成原生Scroll之后,想使用一个比较缓和的动画过渡效果是非常困难的,可选的动画效果十分有限,经过了很多试验之后,最后选择使用淡入-淡出的动画效果,这是一种折中的方法。最初在完成这种动画实现的时候,编码的方法比较简单,就是将当前视图淡出,下一视图淡入,如下图:

后来在做了更多尝试之后,开发出了一种兼容更强的淡入-淡出动画过渡。技术要点就是使用一个幕布层(mask)实现淡入效果,在mask完成淡入之后,再完成实际的视图的切换,操作步骤大致如下:

  • 创建一个幕布层<div class="mask"></div>,mask为position:absolute定位,初始为透明状态,背景设置为白色或其他颜色,并使mask盖在当前视图上面;
  • mask使用transition实现opacity:1的动画过渡,当完成动画时,mask将会把当前视图完全遮住;
  • 最后,直接将当前视图隐藏,将下一视图显示既可;
  • 完成所有动作之后,隐藏mask;

效果图:

4.3 原生Scroll页面结构下的侧边栏

侧边栏的结构也变得复杂了一些,使用原生Scroll之后,body的高度会被内容区域撑到很高,但侧边栏还是必须保证一屏高。所以我在侧边栏显示时,将html与body的高度控制为一屏高,这样可以防止页面被滚动。使用伪代码表示:

侧边栏,默认状态

<html class="frame">

<head>

<style type="text/css">

    .frame {

        height: 100%;

    }

    .sidebar {

        

        position: absolute;

        z-index: 50;

        width: 80%;

        height: 100%;

    }

    .scroller {

        

        position: relative;

        z-index: 100;

        height: 2000px;

    }

    .sidebar-show body, .sidebar-hide body {

        height: 100%;

    }

    .sidebar-show .scroller {

        overflow: hidden;

        height: 100%;

        -webkit-transition: -webkit-transform 400ms;

        -webkit-transform: translate3d(80%,0,0);

    }

    .sidebar-hide .scroller {

        overflow: hidden;

        height: 100%;

        -webkit-transition: -webkit-transform 400ms;

        -webkit-transform: translate3d(0,0,0);

    }

</style>

</head>

<body>

<div class="sidebar"></div>

<div class="scroller"></div>

</body>

</html>

侧边栏显示时,在html元素上增加一个样式sidebar-show

<html class="frame sidebar-show">

侧边栏隐藏时,将html元素上的样式替换成sidebar-hide,当hide动画结束之后,移除hide样式

<html class="frame sidebar-hide">

在项目中的实际效果:

另外,将侧边栏设置为position:fixed定位会是另一种实现思路。

4.4 原生Scroll页面结构下的封面图

封面图的实现与侧边栏差不多,使用伪代码表示:

封面图,默认为显示状态

<html class="frame cover-show">

<head>

<style type="text/css">

    .frame, .frame body {

        height: 100%;

    }

    .cover {

        

        position: absolute;

        z-index: 200;

        width: 100%;

        height: 100%;

    }

    .scroller {

        

        position: relative;

        z-index: 100;

        height: 2000px;

    }

    .cover-show body, .cover-hide body {

        height: 100%;

    }

    .cover-show .scroller {

        overflow: hidden;

        height: 100%;

    }

    .cover-hide .cover {

        -webkit-transition: opacity 400ms;

        opacity: 0;

    }

</style>

</head>

<body>

<div class="cover"></div>

<div class="scroller"></div>

</body>

</html>

封面图隐藏时,将html元素上的样式替换成cover-hide,当hide动画结束之后,移除hide样式

<html class="frame cover-hide">

项目中的应用:

4.5 原生Scroll页面结构下,内容刷新的实现

一般情况下,我们会页面底部放一个加载更多的按钮,让用户点击按钮加载下一页内容,如下图:

又或者,监听window的scroll事件,当页面发生滚动时,监测是否滚动到页面底部,自动加载下一页内容。这两种方式都能很好的解决加载下一页的业务需求,但是对于加载最新或刷新的操作只能在页面中放置一个刷新按钮来完成业务需求。

对于Pull Up/Down Request的操作,在原生Scroll下,几乎是无法实现的。但我依然希望能找到一种方法,实现Pull Request操作。

现在我正在研究一种模拟Pull操作的解决方案,已经有了一个雏形,并实现了一些功能。下面这个示例中没有使用任何的iScroll技术,完全使用原生Scroll实现页面滚动,并且滚动到页面底部后可以完成Pull Up操作,如下图:

这个技术的实现原理并不复杂,就是在页面滚动到底部时,创建一个空白层,模拟Pull Up手势拖动页面的效果。

我后面会封装成一个组件放在GitHub上分享给大家。

5 结束语

手机搜狐目前还是一个年轻的前端团队,在手机搜狐的一年半时间,积累和很多有关移动端Web开发的经验,写这篇文章希望能将自己在移动Web方面的一些经验分享给大家,同时,也希望能有更多的移动Web开发者能互相交流。

https://github.com/maxzhang/maxzhang.github.com/issues/8

时间: 2024-08-22 10:29:42

移动Web单页应用开发实践——页面结构化的相关文章

【转】移动Web单页应用开发实践——页面结构化

1. 前言 在开发面向现代智能手机的移动Web应用的时候,无法避免一个事实,就是需要开发单页应用(Single Page WebApp).对于不同的系统需求,单页应用的粒度会不同,可能是整个系统都使用一个页面装载,也可能是按模块分为独立页面装载.在开发单页应用时第一个要处理的问题就是页面结构化,由于多个功能集中在一个页面呈现,就必然需要考虑如何实现多个视图布局?如何实现视图之间动画切换?等问题. 下面我就来讲述下手机搜狐前端团队在单页应用开发的页面结构化上做过的一些尝试与努力. 2. 页面视图

移动Web单页应用开发实践——实现Pull to Request(上/下拉请求操作)

在单页应用开发中,无论是页面结构化,还是Pull to Request,都离不开一个技术——页面局部滚动.当下的移动web技术,主要使用下面两种方式实现局部区域的滚动: 基于IScroll组件,也有很多团队自己实现类似的组件,实现原理大都一样. 使用浏览器原生支持overflow: scroll,在iOS下使用-webkit-overflow-scrolling: touch;实现惯性滚动. IScroll实现 关于IScroll,大约半年前的一篇文章中 #1 ,对IScroll的观点是建议大家

web单页应用(一)

构建第一个单页应用 1.html页面结构 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" type="text/css" href="css/css.css"&

html5手机Web单页应用实践--起点移动阅读

一开始以hybrid形式做了一个android的小说阅读客户端,叫4G阅读.而后由于业务需求,要迅速实现纯手机html5 版的,所以就直接在原先客户端内内嵌的网页进行改版,快速实现以后在优化的过程中发现越改越多越改越多- 注意此web应用只支持android及iphone内的浏览器,及PC或mac上的chrome,safari,firefox等支持html5的浏览器.IE10以上浏览器 这算是试验版了吧,以前没这么弄过.. 手机访问http://crapi.4gshu.com:8096/4g-r

单页应用Scrat实践

单页应用Scrat实践 1.开始 随着前端工程化深入研究,前端工程师现在碉堡了,甚至搞了个自己的前端网站http://div.io/需要邀请码才能注册,不过里面的技术确实牛.距离顶级的前端架构,目前博主应该是far away,幸运的是现在有很多前端大神积极的分享自己的经验,比如百度这位https://github.com/fouber/blog/issues/4. 将iframe项目使用多页HTML与FIS重构以后,前端已经得到了极大的优化,然而多页HTML带来的状态丢失(登录信息,菜单信息),

基于Redux架构的单页应用开发总结(二)

写在前面 这次重点介绍基于Redux架构的单页应用代码的组织方式 关于less的组织 作为一个后端出身的前端工程师,写简单的css实在没有那种代码可配置和结构化的快感.所以引入less是个不错的选择,无论是针对代码后期的管理,还是提高代码的复用能力. global.less 这个是全局都可以调用的方法库,我习惯把 项目的配色.各种字号.用于引入混出的方法等写在这里,其他container页面通过@import方式引入它,就可以使用里面的东西.不过定义它时要注意以下两点: 第一,这个less里只能

Play Framework Web开发教程(33): 结构化页面-组合使用模板

和你编写代码类似,你编写的页面也可以由多个小的片段组合而成,这些小的片段本身也可以由更小的片段构成.这些小片段通常是可以在其它页面重复使用的:有些部分可以用在所有页面,而有些部分是某些页面特定的.本篇介绍如何使用这些可重用的小模板来构成整个页面.Includes到目前为止的例子,我们只显示了HTML的片段,没有实例显示整个页面.下面我们给出完整的显现产品列表的代码和模板: 1 def catalog() = Action { 2     val products = ProductDAO.lis

单页Web应用:

概念: Web应用程序: WEB应用程序一般是B(浏览器)/S(服务器)模式.Web应用程序首先是“应用程序”,和用标准的程序语言,如C.C++等编写出来的程序没有什么本质上的不同.然而Web应用程序又有自己独特的地方,就是它是基于Web的,而不是采用传统方法运行的.换句话说,它是典型的浏览器/服务器架构的产物. 理解了什么是浏览器/服务器架构,就了解了什么是Web应用程序.常见的计数器.留言版.聊天室和论坛BBS等,都是Web应用程序,不过这些应用相对比较简单,而Web应用程序的真正核心主要是

单页应用SEO浅谈

单页应用SEO浅谈 前言 单页应用(Single Page Application)越来越受web开发者欢迎,单页应用的体验可以模拟原生应用,一次开发,多端兼容.单页应用并不是一个全新发明的技术,而是随着互联网的发展,满足用户体验的一种综合技术. SEO 一直以来,搜索引擎优化(SEO)是开发者容易忽略的部分.SEO是针对搜索(Google.百度.雅虎搜索等)在技术细节上的优化,例如语义.搜索关键词与内容相关性.收录量.搜索排名等.SEO也是同行.市场竞争常用的的营销手段.Google.百度的搜