快速构建H5单页面切换应用
在Web App和Hybrid App横行的时代,为了拥有更好的用户体验,单页面应用顺势而生,单页面应用简称`SPA`,即Single Page Application,就是只有一个HTML页面的应用程序,应用中所有的视图都包含在这个HTML页面中,并通过JavaScript控制相关视图的显示和隐藏,这种模式可以让用户在Web App感受Native App的速度和流畅。本篇文章的目的就是教你如何来快速的构建一个H5单页面切换骨架。
页面设计
在构建SPA应用时,首先要确定你的应用需要包含哪些视图,在这里,为了能够说明问题,我们只需要构建三个视图,即 首页、列表页面和列表详情页面。 这三个页面的逻辑关系是:
- 程序启动,默认进入首页
- 点击首页的按钮切换到列表页面
- 点击列表页面的按钮切换到列表详情页面
- 点击返回按钮或物理返回键能够回到上一页。
首先我们来看一下核心的HTML代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <body> <div class = "pageview" style= "background: #3b76c0" id= "-main-view" > <h3>首页</h3> <div title= "-list-view" class = "right-arrow" ></div> </div> <div class = "pageview" style= "background: #58c03b;display: none" id= "-list-view" > <h3>列表页面</h3> <div class = "left-arrow" ></div> <div title= "-detail-view" class = "right-arrow" ></div> </div> <div class = "pageview" style= "background: #c03b25;display: none" id= "-detail-view" > <h3>列表详情页面</h3> <div class = "left-arrow" ></div> </div> </body> |
class=`pageview`的div容器所包含的就是一个独立的视图页面,在body中共有3个这样的div,需要注意的是,第2、3个div都设置了style=`display:none`,唯独第1个视图没有设置,这样做的目的就是让程序启动时默认显示首页。
在这段代码中,用一个通用的CSS类来描述每一个视图的样式以及切换效果,这个类就是`pageview`, 我们先看看pageview是如何定义的:
1 2 3 4 5 6 7 8 9 | .pageview{ position: absolute; left: 0; top:0; width: 100%; height: 100%; overflow: hidden; -webkit-transition: 0.4s ease- out -webkit-transform; } |
在这里,视图页面需要设置成绝对定位,并且和父容器等宽等高,这样视图才能够平滑的进行切换,另外还需要设置页面切换的过渡效果,我们使用CSS3的transition属性, 具体的参数就不在这里做过多的讲解了,大家应该都明白的。这个样式类所产生的效果是:当改变-webkit-transform的值时,页面会以样式中定义的过渡效果进行平移,持续时间是0.4s. 到此为止,主要的页面设计已经完成了。
逻辑控制
要实现页面切换,就要控制两个页面同时平移,即当前页面不断的离开屏幕,新的页面不断的进入屏幕。为了方便描述,我们把原来的页面叫做`currentView`,把新的页面叫做`applyView`,即申请进入的视图。如果用transform来描述的话,currentView 需要从原来的0% 平移到-100%,即页面向左平移了一个页面宽度的距离,与此同时,appyView需要从原来的100% 平移到0%,刚好占领currentView原来的位置,当然在平移之前,我们需要设置好currentView和applyView的初始位置,分别需要设置成0%和100%。
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 页面向左平移 var currentViewStart = "translateX(0%)" , // currentView初始位置 applyViewStart = "translateX(100%)" , // applyView初始位置 currentViewEnd = "translateX(-100%)" , // currentView的最终位置 applyViewEnd = "translateX(0%)" ; // applyView最终位置 // 页面向右平移 if (direction == "right" ) { currentViewStart = "translateX(0%)" ; applyViewStart = "translateX(-100%)" ; currentViewEnd = "translateX(100%)" ; applyViewEnd = "translateX(0%)" } |
我们知道,通过JS操作就需要获取页面的DOM对象,为了减少DOM的查询,在页面加载时,我们将所有需要用到的页面对象一次性查询出来,并以键值对的形式存储到Map对象中,当需要使用时,只需要根据key来获取即可。
1 2 3 4 5 6 7 8 9 | //初始化执行 initViewPool:function(){ var views = document.querySelectorAll( ".pageview" ); // 通过call使用数组的forEach来遍历NodeList Array.prototype.forEach.call(views,function(item){ // viewPool是一个全局对象 viewPool[item.id] = item; // 将DOM的id作为键 }); } |
下面我们将通过JS来控制页面的切换效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // 获取当前页面的DOM对象 var currentView = viewPool[currentViewId]; // 获取新页面的DOM对象 var applyView = viewPool[pageId]; // 设置新页面的初始位置 applyView.style.webkitTransform = applyViewStart; // 设置当前页面的初始位置 currentView.style.webkitTransform = currentViewStart; // 设置新页面显示 applyView.style.display = "" ; var t1 = setTimeout(function() { // 当设置最终位置时,页面就会以过渡效果平移到最终位置 applyView.style.webkitTransform = applyViewEnd; currentView.style.webkitTransform = currentViewEnd; },200); var t2 = setTimeout(function() { // 400ms后,页面平移结束,设置currentView为隐藏 currentView.style.display = "none" ; // 将新页面设置为当前页面 currentViewId = pageId; if (direction === 'left' ) { window.location.hash = currentViewId.substring(1); } window.clearTimeout(t1); window.clearTimeout(t2); },600); |
在这里有一个重要的操作就是:一定要将设置最终位置的操作放到定时器中,即t1, 这是因为当页面被设置了初始位置后,需要一定的时间来`渲染`这个样式,第2个定时器是为了等待动画执行完毕后进行相关的操作,比如设置当前页面,设置hash,清除定时器等。当这段代码被执行时,页面就会以设定的效果进行平滑的移动,最终,当前页面被隐藏,新页面被设置为当前页面显示到屏幕中央,这样就完成了一次单页面切换效果。
支持物理键返回
既然是单页面切换,就不得不提另外一个问题,那就是物理返回键操作。其实,单页面切换只是页面的显示和隐藏操作,仅此而已,并不是真正意义上的hash跳转,而物理键返回实际上是监听浏览器的hash变化,因此为了让单页面能够支持物理键返回操作,我们需要模拟浏览器的hash变化,即当一个新页面进入时,给当前地址加上一个#hash 的标识,当点击物理返回键的时候,这个hash值会发生变化(回退到上一个hash),与此同时也会触发一个hashchange事件,当监听到hash变化时,我们就通过JS切换到上一个hash对应的页面,这样就实现了物理返回键的效果。
1 2 3 4 | if (direction === 'left' ){ //当进入到新页面时,设置当前hash的值为当前页面的id window.location.hash = currentViewId.substring(1); } |
监听hash变化的处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var that = this ; window.addEventListener( "hashchange" , function () { //当点击返回键时,hash会回退到上一页的hash值 //获取上一页的hash值,并转化为对应view的id var id = window.location.hash.replace( "#" , "-" ); // 判断当前页面不是首页, // 并且触发的浏览器的`back`操作,即点击返回键,因为页面前进的时候也会发生hash变化 if (currentViewId != "-main-view" && id != currentViewId) { id = id || "-main-view" ; //如果上一页是首页,则hash为空,这时需要补上对应的id //调用forward方法从当前页面切换到上一页 that.forward(id, "right" ); } }, false ); |
以上便是单页面切换的基本思路,对应的完整示例代码已上传至 Github: https://github.com/git-onepixel/h5spa, 你可以下载完整代码进行调试和学习,如果需要查看效果演示,请点击或使用微信扫一扫下面的二维码进行访问:
原创发布 @一像素 2016.01
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)