简介

说明

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

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

  • 多路由使用同一组件

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

  • 动态路由

    比如:用户详情页采用动态路由,其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)

import Vue from 'vue'
import VueRouter from 'vue-router'
import BlogEdit from '../components/BlogEdit'
 
Vue.use(VueRouter)
 
const routes = [
  {
    path: '/addBlog',
    name: 'AddBlog',
    component: BlogEdit
  },
  {
    path: '/editBlog',
    name: 'EditBlog',
    component: BlogEdit
  }
 
]
 
const router = new VueRouter({
  routes
})
 
export default router

主页面(App.vue)

<template>
  <div id="app">
    <div id="nav">
      <!--<router-link to="/">Home</router-link> |-->
      <!--<router-link to="/about">About</router-link>-->
      <router-link :to="{name: 'AddBlog'}">创建博客</router-link>
      |
      <router-link :to="{name: 'EditBlog'}">修改博客</router-link>
    </div>
    <router-view/>
  </div>
</template>
 
<style>
<!-- 省略 -->
</style>

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

<template>
  <div class="outer">
    <div>
      这是BlogEdit
    </div>
  </div>
</template>
 
<script>
import LifeCycle from '../mixins/LifeCycle'
 
export default {
  name: 'BlogEdit',
  mixins: [LifeCycle]
}
</script>
 
<style scoped>
.outer {
  margin: 20px;
  border: 2px solid blue;
  padding: 20px;
}
</style>

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

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

export default {
  computed: {
    name () {
      return this.$options.name
    }
  },
  created () {
    console.log('created ==> ' + this.name)
  },
  activated () {
    console.log('activated ==> ' + this.name)
  },
  deactivated () {
    console.log('deactivated ==> ' + this.name)
  },
  destroyed () {
    console.log('destroyed ==> ' + this.name)
  }
}

测试

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

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

解决方案

方案1:导航守卫

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

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

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

export default {
  beforeRouteEnter (to, from, next) {
    // 无法访问this
    console.log('beforeRouteEnter ==> 来自:' + from.path)
    console.log('beforeRouteEnter ==> 去往:' + to.path)
    next(true)
  },
  beforeRouteUpdate (to, from, next) {
    console.log(this.$options.name + ':beforeRouteUpdate ==> 来自:' + from.path)
    console.log(this.$options.name + ':beforeRouteUpdate ==> 去往:' + to.path)
    next(true)
  },
  beforeRouteLeave (to, from, next) {
    console.log(this.$options.name + ':beforeRouteLeave ==> 来自:' + from.path)
    console.log(this.$options.name + ':beforeRouteLeave ==> 去往:' + to.path)
    next(true)
  }
}

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

<template>
  <div class="outer">
    <div>
      这是BlogEdit
    </div>
  </div>
</template>
 
<script>
import LifeCycle from '../mixins/LifeCycle'
import NavigationGuard from '../mixins/NavigationGuard'
 
export default {
  name: 'BlogEdit',
  mixins: [LifeCycle, NavigationGuard]
}
</script>
 
<style scoped>
.outer {
  margin: 20px;
  border: 2px solid blue;
  padding: 20px;
}
</style>

测试

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

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

方案2:watch监听$route

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

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

<template>
  <div class="outer">
    <div>
      这是BlogEdit
    </div>
  </div>
</template>
 
<script>
import LifeCycle from '../mixins/LifeCycle'
 
export default {
  name: 'BlogEdit',
  mixins: [LifeCycle],
  watch: {
    $route (to, from) {
      console.log('组件:' + this.$options.name)
      console.log('来自:' + from.name)
      console.log('去往:' + to.name)
    }
  }
}
</script>
 
<style scoped>
.outer {
  margin: 20px;
  border: 2px solid blue;
  padding: 20px;
}
</style>

测试

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

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

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

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

比如:

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

修改App.vue

<router-view :key="$route.fullPath"></router-view><template>
  <div id="app">
    <div id="nav">
      <!--<router-link to="/">Home</router-link> |-->
      <!--<router-link to="/about">About</router-link>-->
      <router-link :to="{name: 'AddBlog'}">创建博客</router-link>
      |
      <router-link :to="{name: 'EditBlog'}">修改博客</router-link>
    </div>
    <!-- 原来代码 -->
    <-- <router-view/> -->
    <router-view :key="$route.fullPath"></router-view>
  </div>
</template>
 
<style>
<!-- 省略 -->
</style>

测试

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

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

其他网址

Vue keepAlive实现不同的路由共用一个组件component的缓存问题

到此这篇关于VueRouter解决多路由复用同一组件页面不刷新问题的文章就介绍到这了,更多相关VueRouter复用同一组件页面不刷新内容请搜索阿兔在线工具以前的文章或继续浏览下面的相关文章希望大家以后多多支持阿兔在线工具!

点赞(0)

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部