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/react单页应用后退不刷新方案_第1张图片

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;

主页:





子页面:





react中的实现

在routes中:

import { Route } from "react-router-dom";

const Routes = () => {
  return (
    <>
      {/* 这里不能加exact,因为要先匹配父页面再匹配子页面 */}
       import("../views/Home"))} />
    
  );
};

export default Routes;

主页:

import React, { useEffect, useState } from "react";
import { Route, useHistory } from "react-router-dom";
import styled from "styled-components";
import Sub from "./Sub";

const HomeContainer = styled.div`
  position: relative;


const Home: React.FC = () => {
  const [inputValue, setInputValue] = useState("");
  const history = useHistory();

  const handleToSub = () => {
    history.push("/home/sub");
  };

  const handleReload = (val: number) => {
    console.log("reload", val);
  };

  useEffect(() => {
    console.log("mounted");
  }, []);

  return (
    
       setInputValue(e.target.value)}
      />
      

{inputValue}

} />
); }; export default Home;

子页面:

import React from "react";
import styled from "styled-components";

const SubContainer = styled.div`
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: #fff;


type SubProps = {
  handleReload: (val: number) => void;
};

const Sub: React.FC = ({ handleReload }) => {
  useEffect(() => {
   return () => handleReload(123);
  }, []);
  
  return (
    
      

This is Sub page

); }; export default Sub;

题外

在前司的核心项目“平安好车主”中,我就在部分h5新项目用了该方案,在线上经受住了170w+访问量的考验。目前在Shopee也在推行这种h5方案,由于逻辑简单,得到了不少同事的认可和使用。比如常见的:列表页存在搜索条件,进入详情页再返回。 大家可以试用一下,会有惊喜的。

该方案的优点

  • 实现简单,无侵入式修改,几乎0逻辑;
  • 子页面可以单独提供出去,供三方接入;
  • 完全的多实例共存,后退不刷新;
  • 可以像父子组件一样通信,监听子页面离开;

缺点

路由格式需要做改造,必须做成嵌套关系,对url有一定要求。
github地址
https://github.com/zhangnan24/no-refresh-back-vue

到此这篇关于vue/react单页应用后退不刷新方案的文章就介绍到这了,更多相关vue/react后退不刷新内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(vue/react单页应用后退不刷新方案)