Vue常见问题——Vue路由跳转、切换、返回页面不刷新问题

2023-10-27

前言

最近用iview-admin做后台管理系统,遇到了个问题,列表页面点击进入详情页面编辑,编辑完成自动跳转到列表页,需要页面重新刷新请求列表(后管就是这么简单粗暴),然并卵~,再次回到列表页页面不会重新刷新;问题很好解决,因为iview-admin的路由设置会默认缓存页面notCache:false,因此我直接设置notCache:true就ok了,页面可以重新刷新。但是我觉得这个问题简单也不简单;
vue-router的切换不同于传统的页面的切换,路由之间的切换,其实就是组件之间的切换,不是真正的页面切换。这也会导致一个问题,就是引用相同组件的时候,会导致该组件无法更新,也就是我们口中的页面无法更新的问题了,这是根源;
所以参考网上一些文章加上自己之前遇到过得一些相似问题小结一下;

针对不同的需求分为两部分:

一、需求:页面不刷新

场景:(vue-cli生成的项目)

  • 商品列表页点击进入详情页,再次返回列表页会重新请求接口数据,重新渲染DOM,同时如果有滚动条,滚动条返回顶部;需求: 列表页进入详情页,再次返回列表页不刷新,同时滚动条位置不变。
  • 同上;需求: 列表页进入编辑页,编辑完成返回列表页,不刷新全部列表,只针对该条数据进行刷新,同时滚动条位置不变。

分析问题:

  • 列表页进入详情页,再返回重新请求接口数据,重新渲染DOM,这样不仅白白浪费一次请求消耗性能,而且也会影响用户的体验,尤其是移动端项目。
  • 针对滚动条问题,用户浏览到下面列表出现滚动条后,再次返回滚动条回到最顶部,也很影响用户体验;

解决问题:

  • <keep-alive>容器组件,将页面缓存起来;<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
  • 使用路由跳转时:beforeRouteLeave和beforeRouteEnter 来保存滚动条的位置;(beforeRouterLeave必须写在有配置路由的页面上才有效的)
  • 当编辑列表详情时,记录列表行的 index 和 ID,保存返回到列表页时用当前数据刷新列表行数据;

具体代码:

  • 在路由配置页(router.js)中设置页面是否缓存以为滚动条的位置(不一定是body的滚动条也可能是某一个容器的滚动条)
routes: [
	{
	    path: 'index/query',
	    component: ()=>import('@/components/data_center/xxx/index.vue'),
	    meta: {
	        keepAlive: true, // 是否缓存   
	        scollTopPosition: 0 // 滚动条位置
	    }
	}
]
  • 在整个页面框架(App.vue)中需要进行是否缓存的设置
<template>
  <div id="app">
    <keep-alive>
          <!-- 如果当前打开页面的路由中 keepAlive: true (开启了缓存时) -->
          <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
        
    <!-- 如果当前打开页面的路由中 没有 或者为 keepAlive: false (关闭缓存时[默认就是false]) -->
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>
  • 在product.vue页面中,添加beforeRouteEnter和beforeRouteLeave两个监听方法,在离开该页时记录scollTopPosition,当从详情页返回时,再把记录的位置赋给对应容器的滚动条
// 不!能!获取组件实例 `this`
beforeRouteEnter(to, from, next) {
    next(vm => {
          if (from.path === "xxx") {
            document.getElementById('home_query').scrollTop = to.meta.scollTopPosition;
          }
    });
},
beforeRouteLeave(to, from, next) {
    if(from.meta.keepAlive) {
         from.meta.scollTopPosition = document.getElementById('home_query').scrollTop;
    }
    next();
}
  • 当编辑列表页返回时,一般就是根据$index和id来用新数据刷新之前的旧数据;
vm.$set(vm.array,index,newValue)
vm.array.splice(index,1,newValue)

PS: 如何在vue中实时查看滚动条,滚动的位置的值?

 mounted() {
    // 监听window中滚动条的位置
    window.addEventListener('scroll', function(){
     let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
      console.log(scrollTop);
    });
 
    // 监听指定某个元表滚动条的位置
    document.querySelector('#listBox').addEventListener('scroll', function(){
      let scrollTop = this.pageYOffset || this.scrollTop;
      console.log(scrollTop);
}

二、需求:页面刷新

在解决这个问题之前先说一下 <keep-alive>这个组件,其实在上面页面后退不刷新的解决方案里面会用这个组件也是最重要的;

keep-alive理解:
在平常开发中,有部分组件没有必要多次初始化,这时,我们需要将组件进行持久化,使组件的状态维持不变,在下一次展示时,也不会进行重新初始化组件。
也就是说,kee-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免DOM重新渲染 。也就是所谓的组件缓存。
开启keep-alive之后页面生命周期钩子函数执行顺序:页面第一次进入created—mounted—activated,退出时触发deactivated。当再次进入时,只触发activated;

场景:

  • 在路由配置里面设置了keep-alive的页面里面,返回页面或者再次this.route.push跳转时页面不刷新,一般我们用的vue-cli开发项目,会设置keep-alive,而如果用类似iview-admin这样类似的框架时,会有专门的配置方法配置路由缓存,比如:notCache
  • 同一路由携带不同参数,本质上是重用相同的组件实例,默认在跳转路由时会采用缓存策略,并不会刷新当前路由组件,因此不会调用组件的生命周期挂钩

解决问题:

  • 如果因为设置了keep-alive导致页面不刷新,可以针对该页面关闭keep-alive
 meta: {
  keepAlive: false, // 是否缓存   
 }
 // iview-admin
  meta: {
    icon: 'md-apps',
    title: '动态详情',
    hideInMenu: true,
    notCache: true //关闭缓存
   },
  • 可以使用activated周期函数代替mounted函数,把列表页的请求接口的方法放到activated里面
  • 监听路由变化(不推荐、用户体验不好)

官方提供的解决方案为要对同一组件更改做出反应,监听$route的变化,或者使用使用2.2中引入的beforeRouteUpdate
导航卫士,调用对应的方法。

// 监控路由中的数据变化
watch: {
    $route(to, from) {
      if (this.$route.query.id) {
        console.log( "获取页面数据" );
      }
    }
},


// 或者使用beforeRouteUpdate 导航守卫监听路由变化
beforeRouteUpdate(to, from, next) {
    console.log(this.$route.query.id);
    if (this.$route.query.id) {
      console.info("获取页面数据");
    }
    next();
},

注意:

  1. 该方案可以在监听方法中完成在vue生命周期初始化过程中的业务逻辑,可以实现页面重新加载数据的效果,但是滚动条不会重置,因此需要对滚动条进行重置处理;
  2. 当页面刷新后,此时会认为路由并未发生改变,虽然此时watch中的$route或者beforeRouteUpdate 路由监听均视作无变化,但是会正常执行生命周期,因此不存在刷新出错的问题;
  3. 只有在这种情况下严格按照官网:对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,beforeRouteUpdate才起作用
  • 给路由添加唯一key

如果想强制刷新,可以在根路由上为其分配一个唯一key。采用$route.fullpath作为其唯一key。这样vue就回认为内部路由每个都是不同的路由,在跳转时便会强制刷新组件。

<!-- App.vue根组件代码 -->
<template>
  <div class="app">
      <div class="slide">
          <ul>
              <li><router-link to="/page1/freddy">freddy</router-link></li>	
              <li><router-link to="/page1/nick">nick</router-link></li>	
              <li><router-link to="/page1/mike">mike</router-link></li>	
          </ul>	
      </div>
      <div class="content">
      	   <router-view :key="key"></router-view>
      </div>
  </div>
</template>
 
<script>
    export default{
	data(){
	    return {}
	},
	computed:{
	    key(){
	        return this.$route.path + Math.random();
	    }
	}
    }
</script>

这时候路由就会更新了。不过这也就意味着需要把每个都绑定一个key值。如果我从page1跳到page2不同组件的话,我其实是不用担心组件更新问题的。

  • 使用provide和inject结合使用 - 利用v-if原理重载路由

<router-view v-if="routerAlive"></router-view>增加一个不同v-if值,来先摧毁,然后再重新创建起到刷新页面的效果。

<!-- App.vue根组件代码 -->
<template>
  <div class="app">
      <div class="slide">
          <ul>
              <li><router-link to="/page1/freddy" @click.native="routerRefresh">freddy</router-link></li>	
              <li><router-link to="/page1/nick" @click.native="routerRefresh">nick</router-link></li>	
              <li><router-link to="/page1/mike" @click.native="routerRefresh">mike</router-link></li>	
          </ul>	
      </div>
      <div class="content">
      	   <router-view v-if="routerAlive"></router-view>
      </div>
  </div>
</template>
 
<script>
    export default{
	data(){
	    return {
		routerAlive:true
	    }
	},
	methods:{
	    routerRefresh(){
		this.routerAlive = false;
		this.$nextTick(()=>{
		    this.routerAlive = true;
	        });
	    }
	}
    }
</script>
  1. 因为router-link组件有取消点击事件,这里的.native就是为了触发组件原生标签中的事件。
  2. this.$nextTick(()=>{}) 的用法是等this.routerAlive = false; 触发后再执行 this.routerAlive = true; 从而起到摧毁再创建的效果。

provide和inject


<!-- App.vue根组件代码 -->
<template>
  <div class="app">
      <div class="slide">
          <ul>
              <li><router-link to="/page1/freddy" >freddy</router-link></li>	
              <li><router-link to="/page1/nick" >nick</router-link></li>	
              <li><router-link to="/page1/mike" >mike</router-link></li>	
          </ul>	
      </div>
      <div class="content">
      	   <router-view v-if="routerAlive"></router-view>
      </div>
  </div>
</template>
 
<script>
    export default{
	data(){
	    return {
		routerAlive:true
	    }
	},
	provide(){    //在父组件中创建属性
            return {
                routerRefresh: this.routerRefresh
            }
        },
	methods:{
	    routerRefresh(){
	        this.routerAlive = false;
		this.$nextTick(()=>{
		    this.routerAlive = true;
		});
	    }
	}
    }
</script>
<!-- 组件代码 -->
<template>
    <div class="page-1">
	    名字:<input type="text" v-model="value"><br/>
	    <button @click="linkToNick1">跳转到nick,不刷新路由</button>
	    <button @click="linkToNick2">跳转到nick,并刷新路由</button>
	    <br/>
	    <button @click="linkToSelf1">跳转到本身,不刷新路由</button>
	    <button @click="linkToSelf2">刷新本身</button>
    </div>
</template>
<script type="text/javascript">
    export default {
	name:'page1',
	inject:['routerRefresh'],   //在子组件中注入在父组件中出创建的属性
	mounted(){
	    this.value = this.$route.params.name;
	},
	data(){
	    return {
	        value:''
	    }
	},
	methods:{
	    linkToNick1(){
		this.$router.push('/page1/nick');
	    },
	    linkToSelf1(){
		this.$router.push('/page1/freddy');
	    },
	    linkToNick2(){
		this.$router.push('/page1/nick');
		this.routerRefresh();
	    },
	    linkToSelf2(){
		this.routerRefresh();
	    }
	}
    }
</script>

三、总结

  1. 针对路由跳转的问题还需要分清是同一路由,还是同一路由不同参数,还是不同路由。
  2. 对keep-alive的理解使用;
  3. 路由回退最好用this.$router.go(-1)this.$router.back()
  4. keep-alive只对SPA页面有用,传统的多页面不起作用。

本文参考:参考

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue常见问题——Vue路由跳转、切换、返回页面不刷新问题 的相关文章

  • 如何实现 JavaScript 对象被垃圾回收时触发的函数?

    实际上 垃圾被收集 销毁或以其他方式超出范围 我想要做的是 当调用了 bind 方法的对象被销毁时 取消绑定非 DOM 元素上的事件处理程序 编辑 我又查看了我的代码 并决定我真正需要它的唯一地方是当不再需要包含该对象的模块时 这通常发生在
  • 使用 parsley.js 支持每个字段多个自定义错误消息

    我正在尝试使用 parsley js 验证一个简单的表单 并且我对 parsley js 非常初学者 我想使用 window ParsleyValidator addValidator 方法在一个自定义验证方法中显示多个错误消息 所以我尝试
  • 需要帮助从数组中为国家/地区着色,保留其余默认颜色

    我需要一些帮助从我创建的数组中获取数据 然后仅对数组中存在的国家 地区进行着色 而不在数组中的其余国家 地区我希望保留为默认颜色 我正在使用 D3 来完成所有这些工作 并且我非常确定我可以通过 D3 实现我需要的目标 但不确定如何实现 我想
  • 如何创建一个多重过滤函数来过滤掉多个属性?

    我有一个要过滤的对象数组 name Apple age 24 model Android status Under development name Roboto age 24 model Apple status Running 我需要使
  • Access-Control-Allow-Headers 不允许请求标头字段 Access-Control-Allow-Headers

    我试图通过发布请求将文件发送到我的服务器 但是当它发送时会导致错误 Access Control Allow Headers 不允许请求标头字段 Content Type 所以我用谷歌搜索了错误并添加了标题 http post rootSc
  • 在 javascript 中访问 ajax POST 响应

    我正在从 javascript 函数发出 ajax POST 请求 function UpdateMetrics ajax type POST url MyHandler ashx Param1 value1 data contentTyp
  • 如何获取传单标记簇中点击事件的图块?

    这是我的代码 function onMapClick e e originalEvent defaultPrevented true var orig e originalEvent console log orig target map
  • 通过 Javascript 将图像切割成碎片

    我正在创建一个简单的拼图游戏 为了做到这一点 我需要将我正在使用的图片切成 20 块 Javascript 有没有办法将一张图片切成 20 个相等的部分 并将它们保存为网页中的 20 个不同的对象 或者我只需要进入 Photoshop 自己
  • 覆盖函数(例如“警报”)并调用原始函数?

    我想用调用原始版本的新版本覆盖 Javascript 内置函数 类似于用调用的版本覆盖类上的方法 super有多种语言版本 我怎样才能做到这一点 例如 window alert function str do something addit
  • nodejs mocha suite 未定义错误

    我正在尝试使用摩卡运行一些测试 但似乎无法克服这个错误 E tdd nodejs cart gt mocha cart test js node js 201 throw e process nextTick error or err Re
  • Backbone 中的加载栏

    我想显示加载消息 图标 直到列表中的所有项目都已呈现 这是我的示例中的 jsfiddle http jsfiddle net 9R9zU 58 http jsfiddle net 9R9zU 58 我尝试在 Feed 部分添加一个带有加载栏
  • Vue 监听 Vuex 提交吗?

    有没有一种方法可以监听 Vuex 提交 而不观察任何随提交而更改的属性 只是简单地找出是否发生了提交 我有一个 Filter 组件 想将其放入 NPM 包中 但我已经有一个用例 在该用例中 我希望设置一个 cookie 在选择过滤器时存储过
  • Angular 2 runOutsideAngular 仍然改变 UI

    从我的理解来看runOutsideAngular https angular io docs ts latest api core index NgZone class html runOutsideAngular anchor 如果我需要
  • 如果多个键是相同的 JS,则对对象中的值求和

    例如我有 5 个对象 row aa col 1 value 1 row bb col 2 value 1 row bb col 3 value 1 row aa col 1 value 1 row aa col 2 value 1 我想对值
  • Javascript 中的线性回归 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想在网络浏览器中用 Javascript 进行最小二乘拟合 目前 用户使用 HTML 文本输入输入数
  • 如何设置在浏览器的新选项卡(_blank)中打开的pdf文件的标题

    这是我的尝试 是否在新选项卡上打开 但它总是显示test pdf如题 function titlepath path name alert path alert name document title name window open pa
  • Cosmos DB 中的 MaxItemCount 源选项属性不起作用

    我正在尝试编写一个运行 SQL 查询的简单存储过程 并且我想通过使用 MaxItemCount 属性来限制结果 查询生成 3 个文档 但我只想返回 1 个文档 我使用 MaxItemCount 属性强制执行此限制 但这似乎不起作用 func
  • 限制 jQuery id 字符串吗?

    简而言之 我的问题是字符串在 jQuery 中作为可搜索 id 或可搜索内容有什么限制 更新 我得到了 ID 部分 但不是为什么我什至无法使用该字符串搜索 html 内容 对于任何愿意告诉我一个正则表达式来将模式从 MM dd yy HH
  • WooCommerce 使用 AJAX 设置购物车数量?

    我已经为此绞尽脑汁好几天了 需要一些指导 我正在为 WooCommerce 网站完全从头开始制作自定义主题 现在我正在尝试让购物车功能正常工作 我一直试图使用按钮 来更新购物车中产品的数量 对我来说问题似乎是WC 我在functions p
  • 利用重力效果拖动元素

    我想完成类似于 photoshop com 和此网站的功能 http mrdoob com projects chromeexperiments google gravity http mrdoob com projects chromee

随机推荐

  • 薄膜电阻和厚膜电阻有什么区别?

    简介 厚膜电阻主要是指采用厚膜工艺印刷而成的电阻 薄膜电阻稳定性的老化过程因实现不同电阻值所需的薄膜厚度而不同 因此在整个电阻范围内是可变的 此外 改变最佳薄膜厚度还会严重影响 TCR TCR是一个不容忽视的微小参数 它的单位是ppm 1
  • C语言结构体大小计算(超详细,例子丰富,有图)

    看了网上很多关于结构体大小计算的方法 感觉很多讲的不是很清楚 换一种例子就行不通了 我自己也是查阅了很多资料 并且进行了大量的例子验证 总结了一个很好计算结构体大小的方法 直接无脑以下三步即可 1 找到结构体中最大的成员变量所占的字节数 2
  • Java方法的调用(值传递和引用传递)

    系列文章目录 文章目录 系列文章目录 Java方法的调用 一 静态方法 二 非静态方法 三 实际参数和形式参数 四 值传递和引用传递 1 值传递 2 引用传递 Java方法的调用 一 静态方法 静态方法调用 类名 方法名 二 非静态方法 1
  • 计算机网络——传输层

    这篇文章是计算机网络系列文章的第四篇 计算机网络 物理层 计算机网络 数据链路层 计算机网络 网络层 计算机网络 传输层 计算机网络 应用层 序言 计算机网络中的传输层在当今的社会起到了什么作用 计算机网络中的传输层在通信和数据传输方面起着
  • 用户协议html代码,微信小程序同意用户协议确认投稿页面设计制作开发教程

    bookInfo title 作 者 bookInfo author 感谢上传的图书和题目 参与我们的书城建设 加入图书分类小组 搜索QQ群123456 加入出题小组 搜索QQ群123456 同意遵守树芽读书的 用户协议 修订版 用户协议
  • ST-LINK 调试、连线

    硬件连线 只需要三根线 swclk swdio gnd 调试 1 debug st link setting 2 pork sw 确定 3 utilities st link settings reset and run打钩 Add对应的芯
  • vue之自定义一Tree组件编写

    1 实现注意事项 递归组件是可以在它们 己模板中调 自身的组件 Node vue
  • 《数字集成电路静态时序分析基础》笔记⑤

    欢迎关注个人公众号摸鱼范式 目录 标准单元库 时序库概述 非线性延迟模型 延迟模型 非线性模型 Derating参数 时序模型 组合逻辑 时序单元 线延迟 参考书目 网络课程 数字集成电路静态时序分析基础 的笔记 地址 https www
  • PyCharm安装教程

    目录 一 下载 1 官网 2 下载 二 安装 1 下载完成后 直接点击安装包安装 即可 2 开始安装 然后下一步 3 可以在此处自定义地址 然后下一步 4 选择安装选择 然后下一步 5 点击安装 等待片刻 安装完成 三 配置PyCharm
  • 陶哲轩发新论文了,又是AI帮忙的那种

    丰色 发自 凹非寺量子位 公众号 QbitAI 不到一个月的时间 陶哲轩又一篇论文上线 这次是关于欧拉函数的单调非递减序列 他通过初等论证证明了一个名为M x 函数的渐近式 即随着x增大 M x 的行为趋势 该函数在他之前的一篇博客中有所提
  • 【嵌入式开发基础】git 之 format-patch的使用

    背景介绍 我们在日常的开发中 涉及对第三方源码的修改或在需要将自己的改动给到其他同事时 经常需要将改动打patch后进行处理 这时候我们常直接使用diff命令生成patch文件 然后通过patch进行打对应的patch文件 详细的使用请看这
  • 液晶屏接口 - MIPI

    MIPI 移动行业处理器接口 是Mobile Industry Processor Interface的缩写 MIPI并不是一个单一的接口或协议 而是包含了一套协议和标准 以满足各种子系统 图像子系统 摄像头和显示器 存储子系统 无线子系统
  • 【pytorch函数笔记(二)】torch.nn.Sigmoid()

    import torch nn as nn torch nn Sigmoid 一 sigmoid介绍 sigmoid是激活函数的一种 它会将样本值映射到0到1之间 sigmoid的公式如下 1 1 e
  • VC++ GDI+将CDC保存为图片文件(bmp、jpg、png)

    int GetEncoderClsid const wchar t format CLSID pClsid UINT num 0 UINT size 0 ImageCodecInfo pImageCodecInfo NULL GetImag
  • 运算放大器相关

    1 电压电流采样 放大倍数 电压采样电路 放大增益 Vi 48 1 48 1V 虚短 V V 两个输入端视为同等电位 虚断 反向输入端无电流输入输出 流入输入端电流不足1uA 输入端可以视为等效开路 通过R3和R4的电流相等 欧姆定律 I
  • 手机云游戏App

    注 在安卓手机端使用 其他端不做分析 App 手机游戏 PC和主机游戏 免费时长 手机游戏 是否排队 备注 咪咕快游 支持 数量一般 和腾讯还有合作 有不少腾讯的游戏 支持 每日登录签到送30 60分钟 当天失效 0点更新 每套登录签到和任
  • PMIC

    Aurix TLF35584 多电压安全微处理器电源 提供电源给MCU 第二供电系统 车载自诊断系统供电 用于MCU CAN总线独立供电 输出复位信号给MCU 包含看门狗 由MCU喂狗 如不能则复位MCU 中断 与MCU相接 当电源有异常时
  • Oracle9i之xmltype应用

    Oracle9i之xmltype应用 1 2007年07月12日 星期四 14 52 这几天在研究9I下的XMLTYPE数据类型 这在解析和查找生成XML方面都很方便 在网上搜到了一篇入门级的文章 转贴下来 有几个地方小改了一下 文章摘要
  • java基本环境及常识

    1 编程语言 1 机器语言 0和1 在硬件上直接运行 计算机智能识别0和1 2 汇编语言 也称为符号语言 3 高级语言 面向过程的高级语言 程序设计的基本单位为函数 包括c c 面向对象的的高级语言 程序设计的基本单位为类 包括java c
  • Vue常见问题——Vue路由跳转、切换、返回页面不刷新问题

    前言 最近用iview admin做后台管理系统 遇到了个问题 列表页面点击进入详情页面编辑 编辑完成自动跳转到列表页 需要页面重新刷新请求列表 后管就是这么简单粗暴 然并卵 再次回到列表页页面不会重新刷新 问题很好解决 因为iview a