不提场景的解决方案都是耍流氓,那么我们先来看一下所谓 “虚拟任务栈” 的应对场景:
目前移动端应用主要分为两种:
第一种是:以原生开发(Android、IOS)为主的原生 APP
第二种是:以前端三大框架(Angular、React、Vue)为主要开发语言的移动端网页(无论是 webAPP,webview 的混合开发 或者是 H5 应用场景)
对于原生开发来说(我们以 Android 为例),存在一个独有的概念,叫做 任务栈(Task)。任务栈会以 栈 的形式管理所有的 android 页面(activity),使 android 页面具有 进栈和出栈 的特性,如下图所示:
基于这种特性,才有了我们平时使用原生APP 时所具备的 进入页面动画、退出页面动画、进入页面读取数据渲染视图、返回之前页面无需重新读取数据渲染视图 等等特性。
但是在 移动端网页(包括 webAPP,webview 的混合开发 或者是 H5 应用场景) 技术体系中,却没有任务栈的概念,所以我们平常看到的大多数 移动端网页 是这样样子的:
这种效果像极了我们在浏览器中查看网页的过渡效果(其实就是…),但这却不是我们想要的,我们期望的 移动端网页 应该是这个样子的(注意哦:当我们在进行页面后退操作的时候,已存在栈中的页面,并不会重新获取数据、渲染视图,而是维持了之前的状态):
这就是 ”虚拟任务栈“ 的应用场景:
虚拟任务栈可以模拟 原生应用中 Task 栈的效果 使你的网页具备 1.进入页面动画、 2.退出页面动画、 3.进入页面读取数据渲染视图、 4.返回之前页面无需重新读取数据渲染视图 的特性
如果你需要这个技术,或者对这个技术感到好奇,那么你应该看下去。
”虚拟任务栈“概念我最初构建于 2018年年底,随后在多个项目中进行了实践,实践成熟之后在2019年中旬慕课网上架的《混合开发 仿京东项目App》 中讲解了该技术的实现方案,目前课程中 ”7-11 虚拟任务栈“ 一节,已开放试看,大家可以直接通过链接 ,以 观看试看视频 的方式查看 ”虚拟任务栈“ 实现思路。
最初我并没有想要写一篇博客讲解这个思路(主要因为比较懒),但是随后我在网上看到了很多关于”虚拟任务栈“的博客,对于这些博客我不做任何评论,毕竟”虚拟任务栈“的实现并 不存在技术上的难点 。
不过因为这些博客的缘故,我还是想着写一下”虚拟任务栈“的实现吧,所以才有了间隔一年之后的这篇博客内容。
关于”虚拟任务栈“的使用场景,我们在之前已经解释了,如果有对场景依然不清晰的同学,建议直接看课程中的试看视频,视频中,非常清楚的讲解了”虚拟任务栈“的使用场景和可以达到的效果。
所以我们下面直接来讲解”虚拟任务栈“的实现思路。
再来回顾一下我们的目标,我们希望让我们的网页跳转时,具备以下功能:
1.进入页面动画、 2.退出页面动画、 3.进入页面读取数据渲染视图、 4.返回之前页面无需重新读取数据渲染视图
那么要达到这个目标,我们就需要做两件事情:
1、我们需要监听到路由的跳转(页面的跳转) 2、我们需要保存已经进入栈中的页面,而不是销毁他们
所以我们的实现思路,需要围绕着要做的这两件事情来去做。
监听路由的跳转,VueRouter 为我们提供了现成的解决方案,我们可以直接通过 watch
属性来监听 $router
的跳转变化:
// 代码来自 VueRouter 官网:https://router.vuejs.org/zh/guide/advanced/transitions.html // watch $route 决定使用哪种过渡 watch: { '$route' (to, from) { const toDepth = to.path.split('/').length const fromDepth = from.path.split('/').length this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left' } }
这一步要做的事情,我们需要分割为两步来去看:
1、首先我们得需要一个栈 2、其次我们把页面保存到栈中
栈的特性是什么?
关于栈的特性,我们可以从 操作
和 规则
两个方面来看:
1、操作上: 在操作上,栈主要有两个操作:一个是进栈(PUSH),另一个是出栈(POP) 2、规则上: 在规则上,栈遵循 <先进后出> 的原则
基于以上的特性,我们可以通过一个 数组 来表述一个栈,因为数组同样具备 push
与 pop
的操作,同样数据中元素的进出在push
与pop
时,也遵循了 <先进后出> 的原则
有了栈,下面我们需要做的就是把页面保存到栈中,把页面保存到栈中,我们就必须要借助 Vue 中提供的 KeepAlive 组件。
先明确一下,KeepAlive 的作用:
<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
并且我们必须要知道,对于 KeepAlive 来说,它提供了一个关键的 Props:
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
以上功能点,就是我们 把页面保存到栈中 的关键。
我们只需要把需要缓存的页面名称(其实就是 组件名称),通过 include
放入到 keep-alive
组件中,那么我们就可以完成页面的缓存了。
明确了思路之后,我们来看实现。对于实际的实现,我们需要借助 Vue 的实际操作来去做。
我们知道当我们需要在 Vue 中跳转页面时,我们实际上是在进行路由的跳转,而路由的跳转对应的是组件的切换。
所以要实现“虚拟任务栈”,我们需要从以下两个地方着手:
1、在根组件(APP.vue) 中监听路由的跳转,实现动画(进入、退出)以及完成页面的进栈和出栈。 2、在页面跳转的编程式导航中,我们需要告诉根组件,当前的跳转是在进入还是在退出。
达到以上两步,我们就可以实现 “虚拟任务栈” 的功能。
那么我们下面来看,我们应该怎么做(代码直接截取《混合开发 仿京东项目App》 中的代码实现):
监听路由跳转,我们需要处理三种情况:
1、页面的进入 2、页面的退出 3、页面跳转到 tabBar 的页面中(清空虚拟任务栈)
以下是具体代码实现:
// App.vue <template> <div id="app"> <transition :name="transitionName"> <keep-alive :include="keepAliveNames"> <router-view></router-view> </keep-alive> </transition> </div> </template> <script> export default { ... // vue监听路由对象$route的方法 watch: { // watch $route 决定使用哪种过渡 $route(to, from) { const routerType = to.params.routerType; // 1、页面的进入 if (routerType === 'push') { // 入栈 this.keepAliveNames.push(to.name); // 执行进入页面的跳转动画 this.transitionName = 'fold-left'; } // 2、页面的退出 else { // 出栈 this.keepAliveNames.pop(); // 执行退出页面的跳转动画 this.transitionName = 'fold-right'; } /** * 3、页面跳转到 tabBar 的页面中 * 初始化虚拟任务栈 */ if (to.params.clearTask) { this.keepAliveNames = ['imooc']; } } } } </script> <style lang="scss"> // CSS 跳转动画代码省略 </style>
在页面跳转时,同样对应三种情况:
1、进入新的页面,通知虚拟任务栈,当前页面需要被保存到栈中 2、退出页面,通知虚拟任务栈,当前的页面需要从栈中弹出 3、进入 tabbar 中的页面,通知虚拟任务栈,执行清空操作
以下是第一种情况:进入新的页面,通知虚拟任务栈,当前页面需要被保存到栈中
// 1、进入新的页面,当前页面需要被保存到栈中 onGoodsItemClick: function(item) { ... // 编程式导航实现页面的跳转, this.$router.push({ // 进入页面的路由名称 name: 'goodsDetails', params: { // 进入页面的标记 routerType: 'push' }, // 把传递的数据附加到我们的 URL 上 query: { ... } }); },
然后是第二种情况:退出页面,通知虚拟任务栈,当前的页面需要从栈中弹出
2、退出页面,通知虚拟任务栈,当前的页面需要从栈中弹出 /** * 后退按钮点击事件 */ onBackClick: function() { // 正常的后退操作 this.$router.go(-1); },
最后是第三种情况:
3、进入 tabbar 中的页面,通知虚拟任务栈,执行清空操作 // 编程式导航实现页面的跳转, this.$router.push({ // 进入页面的路由名称 name: 'imooc', params: { // 进入页面的标记 routerType: 'push', // 自定义标记,表示进入 tabbar 中的哪个 tab componentIndex: 1, // 自定义标记,清空虚拟任务栈 clearTask: true } });
以上就是整个“虚拟任务栈”的实现思路,就像我们开头所说的,“虚拟任务栈” 并不涉及新的知识点,只是思路的整理。
最后要说的:
我们拥抱技术的开放,但正因为开放,我们更应该遵守规则。
非常欢迎转载,但请标明出处!
老规矩,给自己的课打个广告:
无需原生开发基础,也能完美呈现京东商城。《混合开发京东商城系统,提前布局大前端》课程融合vue、Android、IOS等目前流行的前端和移动端技术,混合开发经典电商APP——京东。课程将各种复杂功能与知识点完美融合,从技术原理到开发上线,让你真实感受到一个明星产品开发的全过程。功能实现之外,还有一流用户体验和优秀交互设计等你一探究竟,拓宽开发眼界。