vue/react單頁應用後退不重新整理方案
目錄
- 引言
- 為什麼麻煩
- 有坑的社群方案(以為例)
- 目前不錯的方案
- 上效果圖
- 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-stack
,vue-navigation
。
這兩個方案都有明顯缺點:前者不支援巢狀路由,在一些場景下會出現url變化,頁面完全無反應的情況,後者存在類似的bug。並且這兩種方案侵入性都很強,因為他們都是基於vue-router的魔改。並且會在url中增加無意義的多餘欄位(stackID)
目前不錯的方案
現在有一個可行且簡單的方案:巢狀子路由 + 疊頁面。
要在spa中實現後退不重新整理,本質是要實現多例項共存。
這個方案的核心在於:通過巢狀子路由實http://www.cppcns.com現多例項共存,通過的absolute實現視覺上的頁面堆疊。
上效果圖
vue中的實現
在routes配置檔案中:
import Home from "../views/Home.vue"; const routes = [ { path: "/home",name: "Home",component: Home,www.cppcns.comchildren: [ { path: "sub",component: () => import(/* webpackChunkName: "sub" */ "../views/Sub.vue"),},],]; export default routes;
主頁:
<template> <div class="home"> <input v-model="inputValue" /> <h3>{{ inputValue }}</h3> <button @click="handleToSub">to sub</button> <router-view @reload="handleReload" /> </div> </template> <script> export default { name: "Home",data() { return { inputValue: "",}; },methods: { handleToSub() { // 注意路由格式,是基於上一個路由/home下面的sub,不是獨立的/sub this.$router.push("/home/sub"); },handleReload(val) { // 這裡可以做一些重新獲取資料的操作,比如在詳情頁修改資料,返回後重新拉取列表 console.log("reload",val); },mounted() { // 子頁面返回,不會重新跑生命週期 console.log("mounted"); },}; </script> <style scoped> .home { position: relative; } </style>
子頁面:
<template> <div class="sub"> <h1>This is Sub page</h1> </div> </template> <script> export default { beforeDestroy() { // 可以傳自定義引數,如果沒需要,也可以不做 this.$emit("reload",123); },}; </script> <style scoped> .sub { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #fff; } </style>
react中的實現
在routes中:
import { Route } from PXdNvec"react-router-dom"; const Routes = () => { return ( <> {/* 這裡不能加exact,因為要先匹配父頁面再匹配子頁面 */} <Route path="/home" component={lazy(() => 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();PXdNvec
const handleToSub = () => {
history.push("/home/sub");
};
const handleReload = (val: number) => {
console.log("reload",val);
};
useEffect(() => {
console.log("mounted");
},[]);
return (
<HomeContainer>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<h3>{inputValue}</h3>
<button onClick={handleToSub}>to sub</button>
<Route
path="/home/sub"
component={() => <Sub handleReload={handleReload} />}
/>
</HomeContainer>
);
};
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<SubProps> = ({ handleReload }) => { useEffect(() => { rPXdNveceturn () => handleReload(123); },[]); return ( <SubContainer> <h1>This is Sub page</h1> </SubContainer> ); }; export default Sub;
題外
在前司的核心專案“平安好車主”中,我就在部分h5新專案用了該方案,在線上經受住了170w+訪問量的考驗。目前在Shopee也在推行這種h5方案,由於邏輯簡單,得到了不少同事的認可和使用。比如常見的:列表頁存在搜尋條件,進入詳情頁再返回。 大家可以試用一下,會有驚喜的。
該方案的優點
- 實現簡單,無侵入式修改,幾乎0邏輯;
- 子頁面可以單獨提供出去,供三方接入;
- 完全的多例項共存,後退不重新整理;
- 可以像父子元件一樣通訊,監聽子頁面離開;
缺點
路由格式需要做改造,必須做成巢狀關係,對url有一定要求。
地址
https://github.com/zhangnan24/no-refresh-back-vue
到此這篇關於vue/react單頁應用後退不重新整理方案的文章就介紹到這了,更多相關vue/react後退不重新整理內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!