vue-page-stack

vue-page-stack

欢迎Star支持下,有什么需求可以直接提issue

由于重度使用了 Vue 全家桶在 web App、公众号和原生 Hybrid 开发,所以很自然的会遇到页面跳转与回退这方面的问题。
场景举例:

  1. 列表页进入详情页,然后回退
  2. 某操作页 A 需要在下一页面 B 选择,选择后需要退回到 A 页面( A 页面还要知道选择了什么)
  3. 在任意页面进入到登录页面,登录或者注册成功后返回到原页面,并且要保证继续回退是不会到登陆页面的
  4. 支持浏览器的 back 和 forward(微信或者小程序很有用)
  5. 在进入、退出或者某些特殊页面的时候添加一些动画,比如模仿 ios 的默认动画(进入是页面从右向左平移,退出是页面从左向右平移)

尝试了以下方法,但是都没有达到我的预期

keep-alive

一般是使用两个 router-view 通过 route 信息和 keep-alive 控制页面是否缓存,这样存在两个问题:

  1. keep-alive 对相同的页面只会存储一次,不会有两个版本的相同页面
  2. 两个 router-view 之间没有办法使用 transition 等动画

CSS 配合嵌套 route

曾经在查看 cube-ui 的例子的时候,发现他们的例子好像解决了页面缓存的问题,我借鉴(copy)了他们的处理方式,升级了一下,使用 CSS 和嵌套 route 的方式实现了基本的需求。 但是也有缺点:

  1. 我必须严格按照页面的层级来写我的 route
  2. 很多页面在多个地方需要用到,我必须都得把路由配上(例如商品详情页面,会在很多个地方有入口)

最后憋出个下面的轮子,已经广泛应用了

性能

先说一下大家最关心的性能问题,比Vue自带的keep-alive组件要好很多,因为keep-alive缓存一次之后在keep-alive组件destroyed之前所有的缓存是不会销毁的,但是vue-page-stack是根据UI层级关系进行缓存和销毁的。下面使用vue-devtool展示两者的不同

vue-page-stack
在这里插入图片描述

通过上图(第二个是keep-alive)我们可以清楚地看见激活组件和缓存组件的状态,vue-page-stack将栈上的UI存储,回退的时候再拿出来激活,并且将不用的组件缓存清除;而keep-alive会把你激活过的所有组件都缓存下来

原理

是参考的keep-alive的代码,下面粘出部分代码,以供参考

let VuePageStack = keyName => {
  return {
    name: config.componentName,
    abstract: true,
    data() {
      return {};
    },
    props: {
      max: {
        type: [String, Number],
        default() {
          return '';
        }
      }
    },
    render() {
      let key = this.$route.query[keyName];
      const slot = this.$slots.default;
      const vnode = getFirstComponentChild(slot);
      if (!vnode) {
        return vnode;
      }
      let index = getIndexByKey(key);
      if (index !== -1) {
        vnode.componentInstance = stack[index].vnode.componentInstance;
        // destroy the instances that will be spliced
        for (let i = index + 1; i < stack.length; i++) {
          stack[i].vnode.componentInstance.$destroy();
          stack[i] = null;
        }
        stack.splice(index + 1);
      } else {
        if (history.action === config.replaceName) {
          // destroy the instance
          stack[stack.length - 1].vnode.componentInstance.$destroy();
          stack[stack.length - 1] = null;
          stack.splice(stack.length - 1);
        }
        stack.push({ key, vnode });
      }
      vnode.data.keepAlive = true;
      return vnode;
    }
  };
};

Vue 单页应用导航管理器,像原生app一样管理页面栈而不是销毁。

Example

预览

示例源码

功能特性

  • 🐉在vue-router上扩展,原有导航逻辑不变
  • push或者forward的时候重新渲染页面,Stack中会添加新渲染的页面
  • 🏆back或者go(负数)的时候先前的页面不会重新渲染,而是从Stack中读取,并且这些页面保留着先前的内容状态,例如表单内容,滚动条滑动的位置等
  • 🏈back或者go(负数)的时候会把不用的页面从Stack中移除
  • 🎓replace会更新Stack中当前页面
  • 🎉回退到之前页面的时候有activated钩子函数触发
  • 🚀支持浏览器的后退,前进事件
  • 🍕支持响应路由参数的变化,例如从 /user/foo 导航到 /user/bar,组件实例会被复用
  • 🐰提供路由方向的变化,并且可以在前进和后退的时候添加不同的动画

安装和用法

安装

npm install vue-page-stack
# OR
yarn add vue-page-stack

使用

import Vue from 'vue'
import VuePageStack from 'vue-page-stack';

// vue-router is necessary
Vue.use(VuePageStack, { router }); 
// App.vue
<template>
  <div id="app">
    <vue-page-stack>
      <router-view ></router-view>
    </vue-page-stack>
  </div>
</template>

CDN

<script src="https://unpkg.com/vue-page-stack/dist/vue-page-stack.umd.min.js"></script>
Vue.use(VuePageStack, { router });

API

注册插件

注册的时候可以指定VuePageStack的名字和keyName

use Vue.use to install vue-page-stack
使用之前需要注册插件

Vue.use(VuePageStack, options);
// example
Vue.use(VuePageStack, { router });

Options 说明:

AttributeDescriptionTypeAccepted ValuesDefault
routervue-router instanceObjectvue-router instance-
nameVuePageStack nameString‘VuePageStack’‘VuePageStack’
keyNamestack-key nameString‘stack-key’‘stack-key’

注册的时候可以指定VuePageStack的名字和keyName

Vue.use(VuePageStack, { router, name: 'VuePageStack', keyName: 'stack-key' });

前进和后退

如果想在页面前进或者后退的时候添加一些动画,可以通过stack-key-dir进行判断

// App.vue
$route(to, from) {
  if (to.params['stack-key-dir'] === 'forward') {
    this.transitionName = 'forward';
  } else {
    this.transitionName = 'back';
  }
}

example

获取当前UI栈

let UIStack = this.$pageStack.getStack();

example code

相关说明

keyName

为什么会给路由添加keyName这个参数,是为了支持浏览器的后退,前进事件,这个特性在webApp,微信公众号和小程序很重要

更新日志

主要的更新日志在 release notes

原理

获取当前页面实例部分参考了Vue源码中keep-alive的部分

感谢

这个插件同时借鉴了vue-navigationvue-nav,很感谢他们给的灵感。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值