移动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 {
background-color: red;
position: absolute;
z-index: 50;
width: 80%;
height: 100%;
}
.scroller {
background-color: green;
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 {
background-color: red;
position: absolute;
z-index: 200;
width: 100%;
height: 100%;
}
.scroller {
background-color: green;
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开发者能互相交流。
Note:文章中的伪代码也许不能完全正确运行,只是提供一种解决问题的参考和思路,实际处理过程远比伪代码要复杂得多。
相关推荐
在当今的Web开发领域,构建交互性强、用户体验优秀的单页应用程序(SPA)已经成为一种趋势。本项目“LocalWeather”正是这样一个例子,它通过集成HTML5、JavaScript面向对象编程(OOP)、jQuery库、AJAX异步通信以及...
单页网站制作教程是针对Web开发领域中一种特殊类型的网站设计——单页面网站(Single Page Application, SPA)的教程资源。这种类型的网站将所有内容都包含在一个HTML页面中,通过JavaScript进行动态加载和交互,提供...
【JavaWeb科研成果申报管理系统源码详解】 ...总之,"Java web项目-科研成果申报管理系统源码"为学习者提供了一个实战平台,通过研究和实践,可以全面掌握JavaWeb开发技术,并能将其应用到实际工作中。
Vue.js 是一款非常流行的前端JavaScript框架,用于构建用户界面,尤其适合单页面应用程序(SPA)。在给定的压缩包文件中,“网页模板——vue.js实现的冒泡数字阶梯顺序排列可视化动画特效源码”是一个使用Vue.js技术...
通过这个毕业设计,开发者不仅展示了对React和Mui框架的熟练运用,还展示了对现代Web开发流程的理解,包括模块化、自动化、版本控制和文档编写。这样的实践项目对于提升个人技能和未来就业具有重要意义。
3. **路由管理**:Vue Router用于管理页面跳转和状态,使应用具备单页应用(SPA)的特点,提供流畅的用户体验。 4. **异步通信**:Vue.js结合axios库,实现与SSM后端的API接口进行异步数据交互,完成CRUD操作。 **...
根据提供的文件信息,我们可以推断出这是一本关于Web前端设计的书籍——《大巧不工Web前端设计修炼之道》的下载链接。虽然文件本身并未给出书籍的具体内容,但通过书名及其描述,我们可以总结出一些与Web前端设计...
更进一步,angle-admin-v3.5.1在开发过程中遵循了最佳实践,例如模块化开发和组件化设计,这有助于提高代码的可维护性和复用性。通过 Meteor 的实时更新和Angular的数据绑定,开发者可以实现快速的反馈和迭代,提高...
【标题】"nodevuefabaocn基于node和vue实现的移动官网"揭示了这...通过深入研究这个项目,开发者可以了解完整的前端到后端开发流程,提升Node.js和Vue.js的实际应用能力,同时掌握现代化Web开发的常见工具和最佳实践。
总之,JavaScript作为Web开发的关键技术,提供了丰富的功能和灵活性,从简单的页面交互到复杂的单页应用都离不开它。通过学习和实践,你可以充分利用JavaScript的潜力,创建出富有创新和用户体验优良的Web应用。
首先,SSM是Java领域常见的Web开发三大组件——Spring、SpringMVC和MyBatis的简称。Spring作为核心容器,负责管理应用对象的生命周期和依赖注入;SpringMVC则负责处理HTTP请求,实现业务逻辑与视图的分离;MyBatis则...
4. **可复用性**:前端和后端接口标准化,后端服务可以供多个客户端使用,如Web、移动应用等。 综上所述,花卷商城项目利用Spring Boot和Vue.js构建的前后端分离架构,不仅体现了现代Web开发的最佳实践,还确保了...
**标题解析** "待办事项Web应用程序:使用React和...综上所述,这个待办事项Web应用程序融合了React和Spring Boot的优秀特性,为用户提供了一个简单易用的任务管理平台,同时展现了现代Web开发的典型技术和最佳实践。
10. **React Native**: 除了Web开发,React还有用于原生移动应用开发的分支——React Native,它允许开发者使用相同的React组件模型构建iOS和Android应用。 "React Projects.zip"可能包含一系列逐步指导的项目,...
2. **移动Web开发**:avalon.js也支持移动端,可以用来构建响应式布局的移动应用。 3. **组件化开发**:对于需要重复使用的UI模块,如表单、菜单、轮播图等,avalon.js的组件化特性尤为适用。 五、学习和进阶 对于...
在Web开发领域,jQuery以其易用性和强大的功能库,成为了JavaScript中最受欢迎的库之一。今天我们将深入探讨一款基于jQuery的轻量级插件——jquery.singlePageNav.min.js。这款插件专为单页面网站设计,提供了一个...
1. **前端开发趋势**:通过小米前端团队的洞察,你可以了解到当前前端开发领域的发展方向,比如Web组件化、PWA(渐进式 web 应用)、SPA(单页应用)、框架的最新进展(如React、Vue、Angular等)。 2. **JavaScript...
在现代Web开发中,React作为一款强大的JavaScript库,被广泛用于构建用户界面,尤其是单页应用程序(SPA)。本项目"vertical-jump-app"正是利用React的特性,打造了一个垂直跳转的应用程序,旨在提供流畅的用户体验...
Vue Router实现页面路由,使应用具备SPA(单页应用)特性,提高用户体验。 图书管理系统的功能主要包括图书的添加、删除、修改、查询等基本操作,以及用户登录、权限管理、图书分类、借阅记录等功能。这些功能的...