Vue--Router--解决多路由复用同一组件页面不刷新问题

末蓝、 2023-09-28 20:01 70阅读 0赞

原文网址:Vue—Router—解决多路由复用同一组件页面不刷新问题_IT利刃出鞘的博客-CSDN博客

简介

说明

本文介绍如何解决Vue的多路由复用同一组件页面不刷新问题。

多路由复用同一组件的场景

  1. 多路由使用同一组件

    1. 比如:添加博客(path为:/addBlog)和编辑博客(path为:/editBlog)都对应同一个组件(EditBlog.vue)
  2. 动态路由

    1. 比如:用户详情页采用动态路由,其path为:/user/:id,组件都是UserDetail.vue

原因分析

Vue中,相同的组件实例将被重复使用。如果两个路由都渲染同个组件,复用比销毁再创建更高效。不过,复用会导致组件的生命周期函数不会被调用。而我们通常会将调后端接口放到created或mounted等生命周期函数中,生命周期函数没被调用,也就无法获取后端数据。

官网网址

https://router.vuejs.org/zh/guide/essentials/dynamic-matching.html#响应路由参数的变化

问题复现

本处以博客为例。添加博客(path为:/addBlog)和编辑博客(path为:/editBlog)都对应同一个组件(EditBlog.vue)

代码

路由配置(router/index.js)

  1. import Vue from 'vue'
  2. import VueRouter from 'vue-router'
  3. import BlogEdit from '../components/BlogEdit'
  4. Vue.use(VueRouter)
  5. const routes = [
  6. {
  7. path: '/addBlog',
  8. name: 'AddBlog',
  9. component: BlogEdit
  10. },
  11. {
  12. path: '/editBlog',
  13. name: 'EditBlog',
  14. component: BlogEdit
  15. }
  16. ]
  17. const router = new VueRouter({
  18. routes
  19. })
  20. export default router

主页面(App.vue)

  1. <template>
  2. <div id="app">
  3. <div id="nav">
  4. <!--<router-link to="/">Home</router-link> |-->
  5. <!--<router-link to="/about">About</router-link>-->
  6. <router-link :to="{name: 'AddBlog'}">创建博客</router-link>
  7. |
  8. <router-link :to="{name: 'EditBlog'}">修改博客</router-link>
  9. </div>
  10. <router-view/>
  11. </div>
  12. </template>
  13. <style>
  14. <!-- 省略 -->
  15. </style>

博客编辑页(components/BlogEdit.vue)

  1. <template>
  2. <div class="outer">
  3. <div>
  4. 这是BlogEdit
  5. </div>
  6. </div>
  7. </template>
  8. <script>
  9. import LifeCycle from '../mixins/LifeCycle'
  10. export default {
  11. name: 'BlogEdit',
  12. mixins: [LifeCycle]
  13. }
  14. </script>
  15. <style scoped>
  16. .outer {
  17. margin: 20px;
  18. border: 2px solid blue;
  19. padding: 20px;
  20. }
  21. </style>

混入生命周期(mixins/LifeCycle.js)

我把生命周期的钩子函数单独拿了出来。

  1. export default {
  2. computed: {
  3. name () {
  4. return this.$options.name
  5. }
  6. },
  7. created () {
  8. console.log('created ==> ' + this.name)
  9. },
  10. activated () {
  11. console.log('activated ==> ' + this.name)
  12. },
  13. deactivated () {
  14. console.log('deactivated ==> ' + this.name)
  15. },
  16. destroyed () {
  17. console.log('destroyed ==> ' + this.name)
  18. }
  19. }

测试

访问:http://localhost:8080/#/

86d05999665f4dfb8d18d741d1e30433.gif

可见,除了第1次进入,之后的进入和退出没有触发相关的生命周期函数,比如:created等。

解决方案

方案1:导航守卫

方法:在beforeRouteEnter中请求后端数据。

导航卫士钩子(mixins/NavigationGuard.js)

为便于管理,我把导航卫士单独拿出来,作为mixin给组件使用。

  1. export default {
  2. beforeRouteEnter (to, from, next) {
  3. // 无法访问this
  4. console.log('beforeRouteEnter ==> 来自:' + from.path)
  5. console.log('beforeRouteEnter ==> 去往:' + to.path)
  6. next(true)
  7. },
  8. beforeRouteUpdate (to, from, next) {
  9. console.log(this.$options.name + ':beforeRouteUpdate ==> 来自:' + from.path)
  10. console.log(this.$options.name + ':beforeRouteUpdate ==> 去往:' + to.path)
  11. next(true)
  12. },
  13. beforeRouteLeave (to, from, next) {
  14. console.log(this.$options.name + ':beforeRouteLeave ==> 来自:' + from.path)
  15. console.log(this.$options.name + ':beforeRouteLeave ==> 去往:' + to.path)
  16. next(true)
  17. }
  18. }

博客编辑组件(components/BlogEdit.vue)

  1. <template>
  2. <div class="outer">
  3. <div>
  4. 这是BlogEdit
  5. </div>
  6. </div>
  7. </template>
  8. <script>
  9. import LifeCycle from '../mixins/LifeCycle'
  10. import NavigationGuard from '../mixins/NavigationGuard'
  11. export default {
  12. name: 'BlogEdit',
  13. mixins: [LifeCycle, NavigationGuard]
  14. }
  15. </script>
  16. <style scoped>
  17. .outer {
  18. margin: 20px;
  19. border: 2px solid blue;
  20. padding: 20px;
  21. }
  22. </style>

测试

访问: http://localhost:8080/#/

268dbc3974404a209588babf77a044f4.gif

可以发现:离开路由时会调用beforeRouteLeave,进入路由时会调用beforeRouteEnter。所以可以将调后端接口的方法放到beforeRouteEnter里边去。

方案2:watch监听$route

方法:使用watch监听$route的变化,变化时根据情况请求后端数据。

修改博客编辑组件(components/BlogEdit.vue)

  1. <template>
  2. <div class="outer">
  3. <div>
  4. 这是BlogEdit
  5. </div>
  6. </div>
  7. </template>
  8. <script>
  9. import LifeCycle from '../mixins/LifeCycle'
  10. export default {
  11. name: 'BlogEdit',
  12. mixins: [LifeCycle],
  13. watch: {
  14. $route (to, from) {
  15. console.log('组件:' + this.$options.name)
  16. console.log('来自:' + from.name)
  17. console.log('去往:' + to.name)
  18. }
  19. }
  20. }
  21. </script>
  22. <style scoped>
  23. .outer {
  24. margin: 20px;
  25. border: 2px solid blue;
  26. padding: 20px;
  27. }
  28. </style>

测试

访问:http://localhost:8080/#/

7557b98f47e74c6491c012a3125e00bc.gif

可以发现:路由变化时会触发对$route的watch。所以可以将调后端接口的方法放到里边去。

方案3:父组件router-view指定key

方法:在父组件的router-view中指定key,这个key必须是唯一的,比如:”$route.fullPath”。这样vue就会认为每个内部路由都是不同的,在跳转时便会强制刷新组件。

比如:

  1. <router-view :key="$route.fullPath"></router-view>

修改App.vue

  1. <router-view :key="$route.fullPath"></router-view><template>
  2. <div id="app">
  3. <div id="nav">
  4. <!--<router-link to="/">Home</router-link> |-->
  5. <!--<router-link to="/about">About</router-link>-->
  6. <router-link :to="{name: 'AddBlog'}">创建博客</router-link>
  7. |
  8. <router-link :to="{name: 'EditBlog'}">修改博客</router-link>
  9. </div>
  10. <!-- 原来代码 -->
  11. <-- <router-view/> -->
  12. <router-view :key="$route.fullPath"></router-view>
  13. </div>
  14. </template>
  15. <style>
  16. <!-- 省略 -->
  17. </style>

测试

访问:http://localhost:8080/#/

397cca7742fd4d7e88a32ef6f885d7f7.gif

可以发现:可以正常触发组件的生命周期(created、destroyed)。

其他网址

Vue keepAlive实现不同的路由共用一个组件component的缓存问题_代码修整工的博客-CSDN博客

发表评论

表情:
评论列表 (有 0 条评论,70人围观)

还没有评论,来说两句吧...

相关阅读

    相关 VueRouter嵌套

    1. 前言 本小节我们介绍如何嵌套使用 VueRouter。嵌套路由在日常的开发中非常常见,如何定义和使用嵌套路由是本节的重点。同学们在学完本节课程之后需要自己多尝试配置