在 Vue 中相同的路由组件如何重新渲染?

在 Vue 中,当我们切换路由时,组件将被重新渲染,但是如果我们在同一个路由上通过不同的参数来访问相同的组件,Vue 将不会重新渲染该组件。这在某些情况下可能会导致视图不会更新,对于这种情况,我们可以采用以下几种方法来解决。

1. 监听路由变化并强制更新组件

我们可以通过监听路由变化来手动更新组件。Vue Router 提供了 beforeEach 和 afterEach 两个全局钩子函数。在 beforeEach 函数中,我们可以记录上一个路由和当前路由,然后在 afterEach 函数中检测路由是否相同。如果路由相同但是参数不同,我们可以通过 $forceUpdate 方法强制更新组件。以下是示例代码:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Foo from './Foo.vue'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/foo/:id',
      component: Foo
    }
  ]
})

// 缓存上一个路由
let previousRoute = {}

router.beforeEach((to, from, next) => {
  previousRoute = from
  next()
})

router.afterEach((to, from) => {
  if (to.path === from.path && to.params.id !== from.params.id) {
    const matched = router.match(previousRoute)
    if (matched) {
      matched.instances.default.$forceUpdate()
    }
  }
})

在上面的代码中,我们记录了上一个路由和当前路由,并在路由相同但是参数不同的情况下强制更新了组件。这样就可以确保我们在相同路由下不同参数时,组件可以重新渲染。

2. 使用 key 属性重复渲染组件

另一种解决方案是通过给相同路由的组件添加一个唯一的 key 值来重新渲染组件。在 Vue 中,key 是用于判断两个元素是否相同的依据。当 key 值不同时,Vue 认为这是两个不同的元素,会重新渲染元素。以下是示例代码:

<template>
  <div :key="key">{{ message }}</div>
</template>

<script>
export default {
  computed: {
    message() {
      return `Current id is ${this.$route.params.id}.`
    },
    key() {
      return `foo-${this.$route.params.id}`
    }
  }
}
</script>

在上面的代码中,每当路由发生变化时,key 值也会发生变化,这样就可以确保组件重新渲染。

3. 使用 watch 监听路由变化

另一个方法是使用 watch 监听 $route 对象的变化。当 $route 发生变化时,我们可以手动触发组件的重新渲染。

例如,在一个使用了 Vue Router 的代码中,我们可以这样写:

<template>
  <router-view ref="routerView"/>
</template>

<script>
export default {
  watch: {
    '$route': function(to, from) {
      this.$refs.routerView.render()
    }
  },
}
</script>

这里,我们使用了 watch 监听 $route 的变化,并在回调函数中手动触发了组件的重新渲染。

一些注意点

无论你使用哪种方法重新渲染相同的路由组件,都需要注意一些细节。这里列出一些需要注意的点:

  1. 重新渲染组件可能会带来额外的性能开销,如果不必要,最好还是避免重新渲染。
  2. key 属性的值必须是唯一的,否则可能会引发不可预期的问题。
  3. 如果组件使用了 activated 和 deactivated 钩子函数,注意这些钩子函数在重新渲染时也会被触发。如果你需要在组件重新渲染时执行特定的逻辑,请确保你的钩子函数可以处理这种情况。