vue-router - 组合式API

785 阅读3分钟

访问路由和当前路由

setup 中,并不存在this关键字,取而代之的是使用 useRouteruseRoute 函数来访问路由对象和当前路由信息

但是在模板中我们仍然可以访问 $router$route,所以不需要在 setup 中返回 routerroute

useRouter 函数可以用来访问当前应用程序的路由实例,它返回一个带有路由相关方法的对象

import { useRouter } from 'vue-router'

export default {
  setup() {
    const router = useRouter()

    // 使用 router 对象调用路由方法
    router.push('/some/path')

    return {}
  }
}

useRoute 函数可以用来访问当前路由对象,路由对象包含当前路由的各种信息

在Vue中,路由对象route是响应式对象,这意味着它的属性可以被监听并且当属性发生变化时将触发相应的回调函数

但是,如果我们监听整个route对象,那么只要该对象上的任何属性发生变化,都会触发watch回调函数

这可能会导致性能问题,并且需要在回调函数中做很多逻辑判断,以确定哪个属性发生了变化

相反,建议直接监听我们所期望的属性,例如route.paramsroute.query

这样,只有当这些特定属性发生更改时,watch回调函数才会被触发。这不仅可以提高性能,还可以使代码更易于理解和维护

import { useRoute } from 'vue-router'
import { ref, watch } from 'vue'

export default {
  setup() {
    const route = useRoute()
    const userData = ref()

    watch(
      () => route.params.id,
      async newId => {
        userData.value = await fetchUser(newId)
      }
    )
  },
}

导航守卫

以组合式API形式定义的导航守卫可以用在任何由 <router-view> 渲染的组件中,它们不必像组件内守卫那样只能用在路由组件上

在组合式路由守卫函数中,只有onBeforeRouteLeaveonBeforeRouteUpdate,并没有onBeforeRouteEnter

onBeforeRouteEnter对应的逻辑和created对应的逻辑可以直接被编写在setup函数中,所以这两个生命周期钩子已经被取消

import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'

export default {
  setup() {
    // 与 beforeRouteLeave 相同,无法访问 `this`
    onBeforeRouteLeave((to, from) => {
     	// .....
    })

    // 与 beforeRouteUpdate 相同,无法访问 `this`
    onBeforeRouteUpdate(async (to, from) => {
      // ....
    })
  },
}

useLink

可以使用 useLink 函数将 RouterLink 的内部行为作为一个组合式函数公开

useLink 函数接收一个类似 RouterLink 所有 prop 的响应式对象,并暴露底层属性来构建自己的 RouterLink 组件或生成自定义链接

可以通过RouterLink.props 获取所有被作为<router-link>的props传递的属性

属性说明
to要跳转的路由链接
可以是一个字符串地址,或者一个标准化的路由对象
replace是否以替换当前历史记录的形式进行调整
默认值为false
append是否把 path 追加到当前路径中
即便路由以/开头,对应的路由依旧是以追加的形式添加到当前路径的后边
默认值为false
tagRouterLink会被渲染为什么标签
默认值为<a>
active-class当前路由模糊匹配成功时,会被添加的样式
默认值为router-link-active
exact-active-class当前路由被严格匹配成功时,会被添加的样式
默认值为router-link-exact-active
import { RouterLink, useLink } from 'vue-router'
import { computed } from 'vue'

export default {
  name: 'AppLink',

  props: {
    // RouterLink.props 并没有直接作为AppLink组件的props被传递
    // 所以vue组件并不能识别这些props,因此需要使用ts-ignore
    // @ts-ignore
    ...RouterLink.props,
    inactiveClass: String,
  },

  setup(props) {
    const {
      // 标准化后的当前路由对象
      route,
      // 格式化后的链接
      href,
      // 路由是否模糊匹配成功
      isActive,
      // 路由是否精确匹配成功
      isExactActive,
      // 导航至该链接的函数 --- 当navigate被触发时,会自动跳转到AppLink对应的路由
      navigate
      } = useLink(props)

    const isExternalLink = computed(
      () => typeof props.to === 'string' && props.to.startsWith('http')
    )

    return { isExternalLink, href, navigate, isActive }
  },
}
<RouterLink to="...">
  <!-- 组件所有暴露给模板的属性和方法 都可以通过作用域插槽被组件的slot所访问 -->
  <template v-slot="{ route, href, isActive }">
    <span v-if="isActive">Already Here</span> 
    <a :href="href">{{ route.name }}</a>  
  </template>
</RouterLink>