为了账号安全,请及时绑定邮箱和手机立即绑定

虚拟任务栈技术 - 让你的网页具备原生APP的页面切换体验

场景

不提场景的解决方案都是耍流氓,那么我们先来看一下所谓 “虚拟任务栈” 的应对场景:

目前移动端应用主要分为两种:
第一种是:以原生开发(Android、IOS)为主的原生 APP
第二种是:以前端三大框架(Angular、React、Vue)为主要开发语言的移动端网页(无论是 webAPP,webview 的混合开发 或者是 H5 应用场景)

对于原生开发来说(我们以 Android 为例),存在一个独有的概念,叫做 任务栈(Task)。任务栈会以 的形式管理所有的 android 页面(activity),使 android 页面具有 进栈和出栈 的特性,如下图所示:

图片来自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、规则上:
	在规则上,栈遵循 <先进后出> 的原则

基于以上的特性,我们可以通过一个 数组 来表述一个栈,因为数组同样具备 pushpop 的操作,同样数据中元素的进出在pushpop时,也遵循了 <先进后出> 的原则

把页面保存到栈中

有了栈,下面我们需要做的就是把页面保存到栈中,把页面保存到栈中,我们就必须要借助 Vue 中提供的 KeepAlive 组件。

先明确一下,KeepAlive 的作用:

<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们

并且我们必须要知道,对于 KeepAlive 来说,它提供了一个关键的 Props:

include - 字符串或正则表达式。只有名称匹配的组件会被缓存。

以上功能点,就是我们 把页面保存到栈中 的关键。

我们只需要把需要缓存的页面名称(其实就是 组件名称),通过 include 放入到 keep-alive 组件中,那么我们就可以完成页面的缓存了。

虚拟任务栈在实际应用中的实现

明确了思路之后,我们来看实现。对于实际的实现,我们需要借助 Vue 的实际操作来去做。

我们知道当我们需要在 Vue 中跳转页面时,我们实际上是在进行路由的跳转,而路由的跳转对应的是组件的切换。

所以要实现“虚拟任务栈”,我们需要从以下两个地方着手:

1、在根组件(APP.vue) 中监听路由的跳转,实现动画(进入、退出)以及完成页面的进栈和出栈。
2、在页面跳转的编程式导航中,我们需要告诉根组件,当前的跳转是在进入还是在退出。

达到以上两步,我们就可以实现 “虚拟任务栈” 的功能。

那么我们下面来看,我们应该怎么做(代码直接截取《混合开发 仿京东项目App》 中的代码实现):

首先:在根组件(APP.vue) 中监听路由的跳转

监听路由跳转,我们需要处理三种情况:

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——京东。课程将各种复杂功能与知识点完美融合,从技术原理到开发上线,让你真实感受到一个明星产品开发的全过程。功能实现之外,还有一流用户体验和优秀交互设计等你一探究竟,拓宽开发眼界。

点击查看更多内容
7人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消