阅读 51

单页应用后退不刷新方案(vue & react)

引言

前进刷新,后退不刷新,是一个类似app页面的特点,要在单页web应用中做后退不刷新,却并非一件易事。

为什么麻烦

spa的渲染原理(以vue为例):url的更改触发onHashChange/pushState/popState/replaceState,通过url中的pathName去匹配路由中定义的组件,加载进来并实例化渲染在项目的出口router-view中。

换言之,一个实例的解析渲染意味着另外一个实例的销毁,因为渲染出口只有一个。

keep-alive为什么不行?因为keep-alive的原理是将实例化后的组件存储起来,当下次url匹配到了改组件时,优先从存储里面取。

但是vue只提供了入存储的方式,没提供删存储的方式,所以没法实现“前进刷新”。

有一种方案是手动根据to和from去做前进后退判断,这种判断不能应对复杂的跳转逻辑可维护性也很差

有坑的社区方案(以vue为例)

vue-page-stackvue-navigation

这两个方案都有明显缺点:前者不支持嵌套路由,在一些场景下会出现url变化,页面完全无反应的情况,后者存在类似的bug。并且这两种方案侵入性都很强,因为他们都是基于vue-router的魔改。并且会在url中增加无意义的多余字段(stackID)

目前不错的方案

现在有一个可行且简单的方案:嵌套子路由 + 叠页面

叠页面的灵感:原生应用中的webview in webview,多页应用中的window in window

要在spa中实现后退不刷新,本质是要实现多实例共存

这个方案的核心在于:通过嵌套子路由实现多实例共存,通过css的absolute实现视觉上的页面堆叠

vue中的实现

在routes配置文件中:

import Home from "../views/Home.vue";

const routes = [
  {
    path"/home",
    name"Home",
    component: Home,
    children: [
      {
        path"sub",
        component() =>
          import(/* webpackChunkName: "sub" */ "../views/Sub.vue"),
      },
    ],
  },
];

export default routes;

主页: