Vue框架中如何实现单页面后退不刷新的效果
Admin 2022-06-24 群英技术资讯 689 次浏览
spa的渲染原理(以vue为例):url的更改触发onHashChange/pushState/popState/replaceState,通过url中的pathName去匹配路由中定义的组件,加载进来并实例化渲染在项目的出口router-view中。
换言之,一个实例的解析渲染意味着另外一个实例的销毁,因为渲染出口只有一个。
keep-alive为什么不行?因为keep-alive的原理是将实例化后的组件存储起来,当下次url匹配到了改组件时,优先从存储里面取。
但是vue只提供了入存储的方式,没提供删存储的方式,所以没法实现“前进刷新”。
有一种方案是手动根据to和from去做前进后退判断,这种判断不能应对复杂的跳转逻辑,可维护性也很差。
vue-page-stack
,vue-navigation
。
这两个方案都有明显缺点:前者不支持嵌套路由,在一些场景下会出现url变化,页面完全无反应的情况,后者存在类似的bug。并且这两种方案侵入性都很强,因为他们都是基于vue-router的魔改。并且会在url中增加无意义的多余字段(stackID)
现在有一个可行且简单的方案:嵌套子路由 + 叠页面。
叠页面的灵感:原生应用中的webview in webview,多页应用中的window in window。
要在spa中实现后退不刷新,本质是要实现多实例共存。
这个方案的核心在于:通过嵌套子路由实现多实例共存,通过css的absolute实现视觉上的页面堆叠。
在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;
主页:
<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>
在routes中:
import { Route } from "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(); 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(() => { return () => handleReload(123); }, []); return ( <SubContainer> <h1>This is Sub page</h1> </SubContainer> ); }; export default Sub;
在前司的核心项目“平安好车主”中,我就在部分h5新项目用了该方案,在线上经受住了170w+访问量的考验。目前在Shopee也在推行这种h5方案,由于逻辑简单,得到了不少同事的认可和使用。比如常见的:列表页存在搜索条件,进入详情页再返回。 大家可以试用一下,会有惊喜的。
路由格式需要做改造,必须做成嵌套关系,对url有一定要求。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
js中的循环方法有哪些?关于在JavaScript 中的遍历循环的方法很多,下面给大家分享的是for循环、for...in循环、for...of循环、foreach(...)、some(...)、every(...)这六种循环,感兴趣的朋友可以参考学习。
这篇文章主要介绍了vue多页面配置,单页应用这个概念,是随着前几年 AngularJS、React、Ember 等这些框架的出现而出现的。在前面的前言内容里,我们在页面渲染中讲了页面的局部刷新,而单页应用则是使用了页面的局部刷新的能力,下面来看看详细内容,需要的朋友可以参考一下
这篇文章给大家分享的是微信小程序中的底部弹出框效果的实现。小编觉得挺实用的,因此分享给大家做个参考,文中示例代码介绍的非常详细,感兴趣的朋友接下来一起跟随小编看看吧。
这篇文章主要介绍了uni-app 的生命周期,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
jquery去掉click事件的方法:1、利用“$(指定元素)”语句获取已经绑定click点击事件的指定元素对象;2、利用unbind()方法删除指定元素对象的click点击事件,语法为“元素对象.unbind();”。
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008